Merge branch 'master' of https://gitee.com/addstone/yudao-cloud
commit
8f66c602f1
5
pom.xml
5
pom.xml
|
|
@ -12,13 +12,14 @@
|
|||
<module>yudao-gateway</module>
|
||||
<module>yudao-framework</module>
|
||||
<!-- 各种 module 拓展 -->
|
||||
<!-- <module>yudao-module-member</module>-->
|
||||
<module>yudao-module-bpm</module>
|
||||
<module>yudao-module-system</module>
|
||||
<module>yudao-module-infra</module>
|
||||
<module>yudao-module-member</module>
|
||||
<module>yudao-module-bpm</module>
|
||||
<module>yudao-module-pay</module>
|
||||
<module>yudao-module-report</module>
|
||||
<module>yudao-module-mp</module>
|
||||
<module>yudao-module-mall</module>
|
||||
</modules>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
|
|
|
|||
|
|
@ -629,6 +629,11 @@
|
|||
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
|
||||
<version>${weixin-java.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
|
||||
<version>${weixin-java.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- SMS SDK begin -->
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
package cn.iocoder.yudao.framework.common.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 终端的枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum TerminalEnum implements IntArrayValuable {
|
||||
|
||||
WECHAT_MINI_PROGRAM(10, "微信小程序"),
|
||||
WECHAT_WAP(11, "微信公众号"),
|
||||
H5(20, "H5 网页"),
|
||||
APP(31, "手机 App"),
|
||||
;
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TerminalEnum::getTerminal).toArray();
|
||||
|
||||
/**
|
||||
* 终端
|
||||
*/
|
||||
private final Integer terminal;
|
||||
/**
|
||||
* 终端名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,14 +2,15 @@ package cn.iocoder.yudao.framework.common.util.collection;
|
|||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* Collection 工具类
|
||||
|
|
@ -19,13 +20,17 @@ import java.util.stream.Collectors;
|
|||
public class CollectionUtils {
|
||||
|
||||
public static boolean containsAny(Object source, Object... targets) {
|
||||
return Arrays.asList(targets).contains(source);
|
||||
return asList(targets).contains(source);
|
||||
}
|
||||
|
||||
public static boolean isAnyEmpty(Collection<?>... collections) {
|
||||
return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty);
|
||||
}
|
||||
|
||||
public static <T> boolean anyMatch(Collection<T> from, Predicate<T> predicate) {
|
||||
return from.stream().anyMatch(predicate);
|
||||
}
|
||||
|
||||
public static <T> List<T> filterList(Collection<T> from, Predicate<T> predicate) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
|
|
@ -47,6 +52,13 @@ public class CollectionUtils {
|
|||
return new ArrayList<>(convertMap(from, keyMapper, Function.identity(), cover).values());
|
||||
}
|
||||
|
||||
public static <T, U> List<U> convertList(T[] from, Function<T, U> func) {
|
||||
if (ArrayUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return convertList(Arrays.asList(from), func);
|
||||
}
|
||||
|
||||
public static <T, U> List<U> convertList(Collection<T> from, Function<T, U> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
|
|
@ -61,6 +73,13 @@ public class CollectionUtils {
|
|||
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <K, V> List<V> mergeValuesFromMap(Map<K, List<V>> map) {
|
||||
return map.values()
|
||||
.stream()
|
||||
.flatMap(List::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashSet<>();
|
||||
|
|
@ -75,6 +94,13 @@ public class CollectionUtils {
|
|||
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> convertMapByFilter(Collection<T> from, Predicate<T> filter, Function<T, K> keyFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return from.stream().filter(filter).collect(Collectors.toMap(keyFunc, v -> v));
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
|
|
@ -149,6 +175,46 @@ public class CollectionUtils {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对比老、新两个列表,找出新增、修改、删除的数据
|
||||
*
|
||||
* @param oldList 老列表
|
||||
* @param newList 新列表
|
||||
* @param sameFunc 对比函数,返回 true 表示相同,返回 false 表示不同
|
||||
* 注意,same 是通过每个元素的“标识”,判断它们是不是同一个数据
|
||||
* @return [新增列表、修改列表、删除列表]
|
||||
*/
|
||||
public static <T> List<List<T>> diffList(Collection<T> oldList, Collection<T> newList,
|
||||
BiFunction<T, T, Boolean> sameFunc) {
|
||||
List<T> createList = new LinkedList<>(newList); // 默认都认为是新增的,后续会进行移除
|
||||
List<T> updateList = new ArrayList<>();
|
||||
List<T> deleteList = new ArrayList<>();
|
||||
|
||||
// 通过以 oldList 为主遍历,找出 updateList 和 deleteList
|
||||
for (T oldObj : oldList) {
|
||||
// 1. 寻找是否有匹配的
|
||||
T foundObj = null;
|
||||
for (Iterator<T> iterator = createList.iterator(); iterator.hasNext(); ) {
|
||||
T newObj = iterator.next();
|
||||
// 1.1 不匹配,则直接跳过
|
||||
if (!sameFunc.apply(oldObj, newObj)) {
|
||||
continue;
|
||||
}
|
||||
// 1.2 匹配,则移除,并结束寻找
|
||||
iterator.remove();
|
||||
foundObj = newObj;
|
||||
break;
|
||||
}
|
||||
// 2. 匹配添加到 updateList;不匹配则添加到 deleteList 中
|
||||
if (foundObj != null) {
|
||||
updateList.add(foundObj);
|
||||
} else {
|
||||
deleteList.add(oldObj);
|
||||
}
|
||||
}
|
||||
return asList(createList, updateList, deleteList);
|
||||
}
|
||||
|
||||
public static boolean containsAny(Collection<?> source, Collection<?> candidates) {
|
||||
return org.springframework.util.CollectionUtils.containsAny(source, candidates);
|
||||
}
|
||||
|
|
@ -182,7 +248,8 @@ public class CollectionUtils {
|
|||
return valueFunc.apply(t);
|
||||
}
|
||||
|
||||
public static <T, V extends Comparable<? super V>> V getSumValue(List<T> from, Function<T, V> valueFunc, BinaryOperator<V> accumulator) {
|
||||
public static <T, V extends Comparable<? super V>> V getSumValue(List<T> from, Function<T, V> valueFunc,
|
||||
BinaryOperator<V> accumulator) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -201,4 +268,20 @@ public class CollectionUtils {
|
|||
return deptId == null ? Collections.emptyList() : Collections.singleton(deptId);
|
||||
}
|
||||
|
||||
public static <T, U> List<U> convertListByFlatMap(Collection<T> from,
|
||||
Function<T, ? extends Stream<? extends U>> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <T, U> Set<U> convertSetByFlatMap(Collection<T> from,
|
||||
Function<T, ? extends Stream<? extends U>> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ package cn.iocoder.yudao.framework.common.util.date;
|
|||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
|
||||
/**
|
||||
* 时间工具类,用于 {@link java.time.LocalDateTime}
|
||||
|
|
@ -22,6 +24,10 @@ public class LocalDateTimeUtils {
|
|||
return LocalDateTime.now().plus(duration);
|
||||
}
|
||||
|
||||
public static LocalDateTime minusTime(Duration duration) {
|
||||
return LocalDateTime.now().minus(duration);
|
||||
}
|
||||
|
||||
public static boolean beforeNow(LocalDateTime date) {
|
||||
return date.isBefore(LocalDateTime.now());
|
||||
}
|
||||
|
|
@ -62,23 +68,57 @@ public class LocalDateTimeUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* 检查时间重叠 不包含日期
|
||||
* 判断当前时间是否在该时间范围内
|
||||
*
|
||||
* @param startTime1 需要校验的开始时间
|
||||
* @param endTime1 需要校验的结束时间
|
||||
* @param startTime2 校验所需的开始时间
|
||||
* @param endTime2 校验所需的结束时间
|
||||
* @return 是否重叠
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 是否
|
||||
*/
|
||||
// TODO @puhui999:LocalDateTimeUtil.isOverlap() 是不是可以满足呀?
|
||||
public static boolean checkTimeOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
|
||||
// 判断时间是否重叠
|
||||
// 开始时间在已配置时段的结束时间之前 且 结束时间在已配置时段的开始时间之后 []
|
||||
return startTime1.isBefore(endTime2) && endTime1.isAfter(startTime2)
|
||||
// 开始时间在已配置时段的开始时间之前 且 结束时间在已配置时段的开始时间之后 (] 或 ()
|
||||
|| startTime1.isBefore(startTime2) && endTime1.isAfter(startTime2)
|
||||
// 开始时间在已配置时段的结束时间之前 且 结束时间在已配值时段的结束时间之后 [) 或 ()
|
||||
|| startTime1.isBefore(endTime2) && endTime1.isAfter(endTime2);
|
||||
public static boolean isBetween(String startTime, String endTime) {
|
||||
if (startTime == null || endTime == null) {
|
||||
return false;
|
||||
}
|
||||
LocalDate nowDate = LocalDate.now();
|
||||
return LocalDateTimeUtil.isIn(LocalDateTime.now(),
|
||||
LocalDateTime.of(nowDate, LocalTime.parse(startTime)),
|
||||
LocalDateTime.of(nowDate, LocalTime.parse(endTime)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断时间段是否重叠
|
||||
*
|
||||
* @param startTime1 开始 time1
|
||||
* @param endTime1 结束 time1
|
||||
* @param startTime2 开始 time2
|
||||
* @param endTime2 结束 time2
|
||||
* @return 重叠:true 不重叠:false
|
||||
*/
|
||||
public static boolean isOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
|
||||
LocalDate nowDate = LocalDate.now();
|
||||
return LocalDateTimeUtil.isOverlap(LocalDateTime.of(nowDate, startTime1), LocalDateTime.of(nowDate, endTime1),
|
||||
LocalDateTime.of(nowDate, startTime2), LocalDateTime.of(nowDate, endTime2));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定日期所在的月份的开始时间
|
||||
* 例如:2023-09-30 00:00:00,000
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 月份的开始时间
|
||||
*/
|
||||
public static LocalDateTime beginOfMonth(LocalDateTime date) {
|
||||
return date.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定日期所在的月份的最后时间
|
||||
* 例如:2023-09-30 23:59:59,999
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 月份的结束时间
|
||||
*/
|
||||
public static LocalDateTime endOfMonth(LocalDateTime date) {
|
||||
return date.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package cn.iocoder.yudao.framework.common.util.number;
|
||||
|
||||
import cn.hutool.core.math.Money;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
|
@ -16,7 +17,7 @@ public class MoneyUtils {
|
|||
* 计算百分比金额,四舍五入
|
||||
*
|
||||
* @param price 金额
|
||||
* @param rate 百分比,例如说 56.77% 则传入 56.77
|
||||
* @param rate 百分比,例如说 56.77% 则传入 56.77
|
||||
* @return 百分比金额
|
||||
*/
|
||||
public static Integer calculateRatePrice(Integer price, Double rate) {
|
||||
|
|
@ -27,24 +28,46 @@ public class MoneyUtils {
|
|||
* 计算百分比金额,向下传入
|
||||
*
|
||||
* @param price 金额
|
||||
* @param rate 百分比,例如说 56.77% 则传入 56.77
|
||||
* @param rate 百分比,例如说 56.77% 则传入 56.77
|
||||
* @return 百分比金额
|
||||
*/
|
||||
public static Integer calculateRatePriceFloor(Integer price, Double rate) {
|
||||
return calculateRatePrice(price, rate, 0, RoundingMode.FLOOR).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算百分比金额
|
||||
*
|
||||
* @param price 金额
|
||||
* @param rate 百分比,例如说 56.77% 则传入 56.77
|
||||
* @param scale 保留小数位数
|
||||
* @param roundingMode 舍入模式
|
||||
*/
|
||||
public static BigDecimal calculateRatePrice(Number price, Number rate, int scale, RoundingMode roundingMode) {
|
||||
return NumberUtil.toBigDecimal(price).multiply(NumberUtil.toBigDecimal(rate)) // 乘以
|
||||
.divide(BigDecimal.valueOf(100), scale, roundingMode); // 除以 100
|
||||
}
|
||||
/**
|
||||
* 计算百分比金额
|
||||
*
|
||||
* @param price 金额
|
||||
* @param rate 百分比,例如说 56.77% 则传入 56.77
|
||||
* @param scale 保留小数位数
|
||||
* @param roundingMode 舍入模式
|
||||
*/
|
||||
public static BigDecimal calculateRatePrice(Number price, Number rate, int scale, RoundingMode roundingMode) {
|
||||
return NumberUtil.toBigDecimal(price).multiply(NumberUtil.toBigDecimal(rate)) // 乘以
|
||||
.divide(BigDecimal.valueOf(100), scale, roundingMode); // 除以 100
|
||||
}
|
||||
|
||||
/**
|
||||
* 分转元
|
||||
*
|
||||
* @param fen 分
|
||||
* @return 元
|
||||
*/
|
||||
public static BigDecimal fenToYuan(int fen) {
|
||||
return new Money(0, fen).getAmount();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分转元(字符串)
|
||||
*
|
||||
* 例如说 fen 为 1 时,则结果为 0.01
|
||||
*
|
||||
* @param fen 分
|
||||
* @return 元
|
||||
*/
|
||||
public static String fenToYuanStr(int fen) {
|
||||
return new Money(0, fen).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,4 +13,28 @@ public class NumberUtils {
|
|||
return StrUtil.isNotEmpty(str) ? Long.valueOf(str) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过经纬度获取地球上两点之间的距离
|
||||
*
|
||||
* 参考 <<a href="https://gitee.com/dromara/hutool/blob/1caabb586b1f95aec66a21d039c5695df5e0f4c1/hutool-core/src/main/java/cn/hutool/core/util/DistanceUtil.java">DistanceUtil</a>> 实现,目前它已经被 hutool 删除
|
||||
*
|
||||
* @param lat1 经度1
|
||||
* @param lng1 纬度1
|
||||
* @param lat2 经度2
|
||||
* @param lng2 纬度2
|
||||
* @return 距离,单位:千米
|
||||
*/
|
||||
public static double getDistance(double lat1, double lng1, double lat2, double lng2) {
|
||||
double radLat1 = lat1 * Math.PI / 180.0;
|
||||
double radLat2 = lat2 * Math.PI / 180.0;
|
||||
double a = radLat1 - radLat2;
|
||||
double b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
|
||||
double distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
|
||||
+ Math.cos(radLat1) * Math.cos(radLat2)
|
||||
* Math.pow(Math.sin(b / 2), 2)));
|
||||
distance = distance * 6378.137;
|
||||
distance = Math.round(distance * 10000d) / 10000d;
|
||||
return distance;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,11 @@ public class DictFrameworkUtils {
|
|||
log.info("[init][初始化 DictFrameworkUtils 成功]");
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static String getDictDataLabel(String dictType, Integer value) {
|
||||
return GET_DICT_DATA_CACHE.get(new KeyValue<>(dictType, String.valueOf(value))).getLabel();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static String getDictDataLabel(String dictType, String value) {
|
||||
return GET_DICT_DATA_CACHE.get(new KeyValue<>(dictType, value)).getLabel();
|
||||
|
|
|
|||
|
|
@ -33,9 +33,12 @@
|
|||
<!-- 三方云服务相关 -->
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<!-- <artifactId>weixin-java-mp</artifactId>-->
|
||||
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
|||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import com.baomidou.mybatisplus.extension.toolkit.Db;
|
||||
|
|
@ -18,6 +19,9 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力
|
||||
*
|
||||
* 1. {@link BaseMapper} 为 MyBatis Plus 的基础接口,提供基础的 CRUD 能力
|
||||
* 2. {@link MPJBaseMapper} 为 MyBatis Plus Join 的基础接口,提供连表 Join 能力
|
||||
*/
|
||||
public interface BaseMapperX<T> extends MPJBaseMapper<T> {
|
||||
|
||||
|
|
@ -45,8 +49,14 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
|
|||
return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
|
||||
}
|
||||
|
||||
default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
|
||||
SFunction<T, ?> field3, Object value3) {
|
||||
return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
|
||||
.eq(field3, value3));
|
||||
}
|
||||
|
||||
default Long selectCount() {
|
||||
return selectCount(new QueryWrapper<T>());
|
||||
return selectCount(new QueryWrapper<>());
|
||||
}
|
||||
|
||||
default Long selectCount(String field, Object value) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,313 @@
|
|||
package cn.iocoder.yudao.framework.mybatis.core.query;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import com.github.yulichang.toolkit.MPJWrappers;
|
||||
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 拓展 MyBatis Plus Join QueryWrapper 类,主要增加如下功能:
|
||||
* <p>
|
||||
* 1. 拼接条件的方法,增加 xxxIfPresent 方法,用于判断值不存在的时候,不要拼接到条件中。
|
||||
*
|
||||
* @param <T> 数据类型
|
||||
*/
|
||||
public class MPJLambdaWrapperX<T> extends MPJLambdaWrapper<T> {
|
||||
|
||||
public MPJLambdaWrapperX<T> likeIfPresent(SFunction<T, ?> column, String val) {
|
||||
MPJWrappers.lambdaJoin().like(column, val);
|
||||
if (StringUtils.hasText(val)) {
|
||||
return (MPJLambdaWrapperX<T>) super.like(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPJLambdaWrapperX<T> inIfPresent(SFunction<T, ?> column, Collection<?> values) {
|
||||
if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
|
||||
return (MPJLambdaWrapperX<T>) super.in(column, values);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPJLambdaWrapperX<T> inIfPresent(SFunction<T, ?> column, Object... values) {
|
||||
if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
|
||||
return (MPJLambdaWrapperX<T>) super.in(column, values);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPJLambdaWrapperX<T> eqIfPresent(SFunction<T, ?> column, Object val) {
|
||||
if (ObjectUtil.isNotEmpty(val)) {
|
||||
return (MPJLambdaWrapperX<T>) super.eq(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPJLambdaWrapperX<T> neIfPresent(SFunction<T, ?> column, Object val) {
|
||||
if (ObjectUtil.isNotEmpty(val)) {
|
||||
return (MPJLambdaWrapperX<T>) super.ne(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPJLambdaWrapperX<T> gtIfPresent(SFunction<T, ?> column, Object val) {
|
||||
if (val != null) {
|
||||
return (MPJLambdaWrapperX<T>) super.gt(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPJLambdaWrapperX<T> geIfPresent(SFunction<T, ?> column, Object val) {
|
||||
if (val != null) {
|
||||
return (MPJLambdaWrapperX<T>) super.ge(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPJLambdaWrapperX<T> ltIfPresent(SFunction<T, ?> column, Object val) {
|
||||
if (val != null) {
|
||||
return (MPJLambdaWrapperX<T>) super.lt(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPJLambdaWrapperX<T> leIfPresent(SFunction<T, ?> column, Object val) {
|
||||
if (val != null) {
|
||||
return (MPJLambdaWrapperX<T>) super.le(column, val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPJLambdaWrapperX<T> betweenIfPresent(SFunction<T, ?> column, Object val1, Object val2) {
|
||||
if (val1 != null && val2 != null) {
|
||||
return (MPJLambdaWrapperX<T>) super.between(column, val1, val2);
|
||||
}
|
||||
if (val1 != null) {
|
||||
return (MPJLambdaWrapperX<T>) ge(column, val1);
|
||||
}
|
||||
if (val2 != null) {
|
||||
return (MPJLambdaWrapperX<T>) le(column, val2);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MPJLambdaWrapperX<T> betweenIfPresent(SFunction<T, ?> column, Object[] values) {
|
||||
Object val1 = ArrayUtils.get(values, 0);
|
||||
Object val2 = ArrayUtils.get(values, 1);
|
||||
return betweenIfPresent(column, val1, val2);
|
||||
}
|
||||
|
||||
// ========== 重写父类方法,方便链式调用 ==========
|
||||
|
||||
@Override
|
||||
public <X> MPJLambdaWrapperX<T> eq(boolean condition, SFunction<X, ?> column, Object val) {
|
||||
super.eq(condition, column, val);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> MPJLambdaWrapperX<T> eq(SFunction<X, ?> column, Object val) {
|
||||
super.eq(column, val);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> MPJLambdaWrapperX<T> orderByDesc(SFunction<X, ?> column) {
|
||||
//noinspection unchecked
|
||||
super.orderByDesc(true, column);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MPJLambdaWrapperX<T> last(String lastSql) {
|
||||
super.last(lastSql);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> MPJLambdaWrapperX<T> in(SFunction<X, ?> column, Collection<?> coll) {
|
||||
super.in(column, coll);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MPJLambdaWrapperX<T> selectAll(Class<?> clazz) {
|
||||
super.selectAll(clazz);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MPJLambdaWrapperX<T> selectAll(Class<?> clazz, String prefix) {
|
||||
super.selectAll(clazz, prefix);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> MPJLambdaWrapperX<T> selectAs(SFunction<S, ?> column, String alias) {
|
||||
super.selectAs(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> MPJLambdaWrapperX<T> selectAs(String column, SFunction<E, ?> alias) {
|
||||
super.selectAs(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectAs(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
super.selectAs(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E, X> MPJLambdaWrapperX<T> selectAs(String index, SFunction<E, ?> column, SFunction<X, ?> alias) {
|
||||
super.selectAs(index, column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> MPJLambdaWrapperX<T> selectAsClass(Class<E> source, Class<?> tag) {
|
||||
super.selectAsClass(source, tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E, F> MPJLambdaWrapperX<T> selectSub(Class<E> clazz, Consumer<MPJLambdaWrapper<E>> consumer, SFunction<F, ?> alias) {
|
||||
super.selectSub(clazz, consumer, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E, F> MPJLambdaWrapperX<T> selectSub(Class<E> clazz, String st, Consumer<MPJLambdaWrapper<E>> consumer, SFunction<F, ?> alias) {
|
||||
super.selectSub(clazz, st, consumer, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> MPJLambdaWrapperX<T> selectCount(SFunction<S, ?> column) {
|
||||
super.selectCount(column);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MPJLambdaWrapperX<T> selectCount(Object column, String alias) {
|
||||
super.selectCount(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> MPJLambdaWrapperX<T> selectCount(Object column, SFunction<X, ?> alias) {
|
||||
super.selectCount(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectCount(SFunction<S, ?> column, String alias) {
|
||||
super.selectCount(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectCount(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
super.selectCount(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> MPJLambdaWrapperX<T> selectSum(SFunction<S, ?> column) {
|
||||
super.selectSum(column);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectSum(SFunction<S, ?> column, String alias) {
|
||||
super.selectSum(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectSum(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
super.selectSum(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> MPJLambdaWrapperX<T> selectMax(SFunction<S, ?> column) {
|
||||
super.selectMax(column);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectMax(SFunction<S, ?> column, String alias) {
|
||||
super.selectMax(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectMax(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
super.selectMax(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> MPJLambdaWrapperX<T> selectMin(SFunction<S, ?> column) {
|
||||
super.selectMin(column);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectMin(SFunction<S, ?> column, String alias) {
|
||||
super.selectMin(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectMin(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
super.selectMin(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> MPJLambdaWrapperX<T> selectAvg(SFunction<S, ?> column) {
|
||||
super.selectAvg(column);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectAvg(SFunction<S, ?> column, String alias) {
|
||||
super.selectAvg(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectAvg(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
super.selectAvg(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> MPJLambdaWrapperX<T> selectLen(SFunction<S, ?> column) {
|
||||
super.selectLen(column);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectLen(SFunction<S, ?> column, String alias) {
|
||||
super.selectLen(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, X> MPJLambdaWrapperX<T> selectLen(SFunction<S, ?> column, SFunction<X, ?> alias) {
|
||||
super.selectLen(column, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -37,6 +37,19 @@ spring:
|
|||
uri: grayLb://infra-server
|
||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||
- Path=/admin/**
|
||||
## member-server 服务
|
||||
- id: member-admin-api # 路由的编号
|
||||
uri: grayLb://member-server
|
||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||
- Path=/admin-api/member/**
|
||||
filters:
|
||||
- RewritePath=/admin-api/member/v3/api-docs, /v3/api-docs
|
||||
- id: member-app-api # 路由的编号
|
||||
uri: grayLb://member-server
|
||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||
- Path=/app-api/member/**
|
||||
filters:
|
||||
- RewritePath=/app-api/member/v3/api-docs, /v3/api-docs
|
||||
## bpm-server 服务
|
||||
- id: bpm-admin-api # 路由的编号
|
||||
uri: grayLb://bpm-server
|
||||
|
|
@ -71,6 +84,32 @@ spring:
|
|||
- Path=/admin-api/mp/**
|
||||
filters:
|
||||
- RewritePath=/admin-api/mp/v3/api-docs, /v3/api-docs
|
||||
## product-server 服务
|
||||
- id: product-admin-api # 路由的编号
|
||||
uri: grayLb://product-server
|
||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||
- Path=/admin-api/product/**
|
||||
filters:
|
||||
- RewritePath=/admin-api/product/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs
|
||||
- id: product-app-api # 路由的编号
|
||||
uri: grayLb://product-server
|
||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||
- Path=/app-api/product/**
|
||||
filters:
|
||||
- RewritePath=/app-api/product/v3/api-docs, /v3/api-docs
|
||||
## promotion-server 服务
|
||||
- id: promotion-admin-api # 路由的编号
|
||||
uri: grayLb://promotion-server
|
||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||
- Path=/admin-api/promotion/**
|
||||
filters:
|
||||
- RewritePath=/admin-api/promotion/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs
|
||||
- id: promotion-app-api # 路由的编号
|
||||
uri: grayLb://promotion-server
|
||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||
- Path=/app-api/promotion/**
|
||||
filters:
|
||||
- RewritePath=/app-api/promotion/v3/api-docs, /v3/api-docs
|
||||
x-forwarded:
|
||||
prefix-enabled: false # 避免 Swagger 重复带上额外的 /admin-api/system 前缀
|
||||
|
||||
|
|
@ -85,6 +124,9 @@ knife4j:
|
|||
- name: infra-server
|
||||
service-name: infra-server
|
||||
url: /admin-api/infra/v3/api-docs
|
||||
- name: member-server
|
||||
service-name: member-server
|
||||
url: /admin-api/member/v3/api-docs
|
||||
- name: bpm-server
|
||||
service-name: bpm-server
|
||||
url: /admin-api/bpm/v3/api-docs
|
||||
|
|
@ -94,3 +136,9 @@ knife4j:
|
|||
- name: mp-server
|
||||
service-name: mp-server
|
||||
url: /admin-api/mp/v3/api-docs
|
||||
- name: product-server
|
||||
service-name: product-server
|
||||
url: /admin-api/product/v3/api-docs
|
||||
- name: promotion-server
|
||||
service-name: promotion-server
|
||||
url: /admin-api/promotion/v3/api-docs
|
||||
|
|
|
|||
|
|
@ -22,12 +22,26 @@
|
|||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-ui</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,27 @@
|
|||
package cn.iocoder.yudao.module.bpm.api.task;
|
||||
|
||||
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.bpm.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* 流程实例 Api 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 流程实例")
|
||||
public interface BpmProcessInstanceApi {
|
||||
|
||||
/**
|
||||
* 创建流程实例(提供给内部)
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param reqDTO 创建信息
|
||||
* @return 实例的编号
|
||||
*/
|
||||
String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO);
|
||||
String PREFIX = ApiConstants.PREFIX + "/process-instance";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建流程实例(提供给内部),返回实例编号")
|
||||
@Parameter(name = "userId", description = "用户编号", required = true, example = "1")
|
||||
String createProcessInstance(@RequestParam("userId") Long userId,
|
||||
@Valid @RequestBody BpmProcessInstanceCreateReqDTO reqDTO);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,24 @@
|
|||
package cn.iocoder.yudao.module.bpm.api.task.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程实例的创建 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Schema(description = "RPC 服务 - 流程实例的创建 Request DTO")
|
||||
@Data
|
||||
public class BpmProcessInstanceCreateReqDTO {
|
||||
|
||||
/**
|
||||
* 流程定义的标识
|
||||
*/
|
||||
@Schema(description = "流程定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "leave")
|
||||
@NotEmpty(message = "流程定义的标识不能为空")
|
||||
private String processDefinitionKey;
|
||||
/**
|
||||
* 变量实例
|
||||
*/
|
||||
|
||||
@Schema(description = "变量实例", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Map<String, Object> variables;
|
||||
|
||||
/**
|
||||
* 业务的唯一标识
|
||||
*
|
||||
* 例如说,请假申请的编号。通过它,可以查询到对应的实例
|
||||
*/
|
||||
@NotEmpty(message = "业务的唯一标识")
|
||||
private String businessKey;
|
||||
@Schema(description = "业务的唯一标识", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "业务的唯一标识不能为空")
|
||||
private String businessKey; // 例如说,请假申请的编号。通过它,可以查询到对应的实例
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package cn.iocoder.yudao.module.bpm.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.RpcConstants;
|
||||
|
||||
/**
|
||||
* API 相关的枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class ApiConstants {
|
||||
|
||||
/**
|
||||
* 服务名
|
||||
*
|
||||
* 注意,需要保证和 spring.application.name 保持一致
|
||||
*/
|
||||
public static final String NAME = "bpm-server";
|
||||
|
||||
public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/bpm";
|
||||
|
||||
public static final String VERSION = "1.0.0";
|
||||
|
||||
}
|
||||
|
|
@ -15,8 +15,8 @@ public class FileCreateReqDTO {
|
|||
@Schema(description = "文件路径", example = "xxx.png")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "文件内容", required = true)
|
||||
@Schema(description = "文件内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "文件内容不能为空")
|
||||
private byte[] content;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,43 +13,43 @@ public class ApiAccessLogCreateReqDTO {
|
|||
@Schema(description = "链路追踪编号", example = "89aca178-a370-411c-ae02-3f0d672be4ab")
|
||||
private String traceId;
|
||||
|
||||
@Schema(description = "用户编号", required = true, example = "1024")
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long userId;
|
||||
@Schema(description = "用户类型", required = true, example = "1")
|
||||
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer userType;
|
||||
@Schema(description = "应用名", required = true, example = "system-server")
|
||||
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system-server")
|
||||
@NotNull(message = "应用名不能为空")
|
||||
private String applicationName;
|
||||
|
||||
@Schema(description = "请求方法名", required = true, example = "GET")
|
||||
@Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET")
|
||||
@NotNull(message = "http 请求方法不能为空")
|
||||
private String requestMethod;
|
||||
@Schema(description = "请求地址", required = true, example = "/xxx/yyy")
|
||||
@Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy")
|
||||
@NotNull(message = "访问地址不能为空")
|
||||
private String requestUrl;
|
||||
@Schema(description = "请求参数", required = true)
|
||||
@Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "请求参数不能为空")
|
||||
private String requestParams;
|
||||
@Schema(description = "用户 IP", required = true, example = "127.0.0.1")
|
||||
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
|
||||
@NotNull(message = "ip 不能为空")
|
||||
private String userIp;
|
||||
@Schema(description = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
|
||||
@Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0")
|
||||
@NotNull(message = "User-Agent 不能为空")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "开始时间", required = true)
|
||||
@Schema(description = "开始时间",requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "开始请求时间不能为空")
|
||||
private LocalDateTime beginTime;
|
||||
@Schema(description = "结束时间", required = true)
|
||||
@Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "结束请求时间不能为空")
|
||||
private LocalDateTime endTime;
|
||||
@Schema(description = "执行时长,单位:毫秒", required = true)
|
||||
@Schema(description = "执行时长,单位:毫秒", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "执行时长不能为空")
|
||||
private Integer duration;
|
||||
@Schema(description = "结果码", required = true)
|
||||
@Schema(description = "结果码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "错误码不能为空")
|
||||
private Integer resultCode;
|
||||
@Schema(description = "结果提示")
|
||||
private String resultMsg;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,56 +13,56 @@ public class ApiErrorLogCreateReqDTO {
|
|||
@Schema(description = "链路追踪编号", example = "89aca178-a370-411c-ae02-3f0d672be4ab")
|
||||
private String traceId;
|
||||
|
||||
@Schema(description = "用户编号", required = true, example = "1024")
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long userId;
|
||||
@Schema(description = "用户类型", required = true, example = "1")
|
||||
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer userType;
|
||||
@Schema(description = "应用名", required = true, example = "system-server")
|
||||
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system-server")
|
||||
@NotNull(message = "应用名不能为空")
|
||||
private String applicationName;
|
||||
|
||||
@Schema(description = "请求方法名", required = true, example = "GET")
|
||||
@Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET")
|
||||
@NotNull(message = "http 请求方法不能为空")
|
||||
private String requestMethod;
|
||||
@Schema(description = "请求地址", required = true, example = "/xxx/yyy")
|
||||
@Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy")
|
||||
@NotNull(message = "访问地址不能为空")
|
||||
private String requestUrl;
|
||||
@Schema(description = "请求参数", required = true)
|
||||
@Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "请求参数不能为空")
|
||||
private String requestParams;
|
||||
@Schema(description = "用户 IP", required = true, example = "127.0.0.1")
|
||||
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
|
||||
@NotNull(message = "ip 不能为空")
|
||||
private String userIp;
|
||||
@Schema(description = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
|
||||
@Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0")
|
||||
@NotNull(message = "User-Agent 不能为空")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "异常时间", required = true)
|
||||
@Schema(description = "异常时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "异常时间不能为空")
|
||||
private LocalDateTime exceptionTime;
|
||||
@Schema(description = "异常名", required = true)
|
||||
@Schema(description = "异常名", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "异常名不能为空")
|
||||
private String exceptionName;
|
||||
@Schema(description = "异常发生的类全名", required = true)
|
||||
@Schema(description = "异常发生的类全名", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "异常发生的类全名不能为空")
|
||||
private String exceptionClassName;
|
||||
@Schema(description = "异常发生的类文件", required = true)
|
||||
@Schema(description = "异常发生的类文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "异常发生的类文件不能为空")
|
||||
private String exceptionFileName;
|
||||
@Schema(description = "异常发生的方法名", required = true)
|
||||
@Schema(description = "异常发生的方法名", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "异常发生的方法名不能为空")
|
||||
private String exceptionMethodName;
|
||||
@Schema(description = "异常发生的方法所在行", required = true)
|
||||
@Schema(description = "异常发生的方法所在行", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "异常发生的方法所在行不能为空")
|
||||
private Integer exceptionLineNumber;
|
||||
@Schema(description = "异常的栈轨迹异常的栈轨迹", required = true)
|
||||
@Schema(description = "异常的栈轨迹异常的栈轨迹", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "异常的栈轨迹不能为空")
|
||||
private String exceptionStackTrace;
|
||||
@Schema(description = "异常导致的根消息", required = true)
|
||||
@Schema(description = "异常导致的根消息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "异常导致的根消息不能为空")
|
||||
private String exceptionRootCauseMessage;
|
||||
@Schema(description = "异常导致的消息", required = true)
|
||||
@Schema(description = "异常导致的消息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "异常导致的消息不能为空")
|
||||
private String exceptionMessage;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ public class DatabaseDocController {
|
|||
*/
|
||||
private static ProcessConfig buildProcessConfig() {
|
||||
return ProcessConfig.builder()
|
||||
.ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_")) // 忽略表前缀
|
||||
.ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_", "FLW_")) // 忽略表前缀
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ public class FileConfigServiceImpl implements FileConfigService {
|
|||
FileConfigDO config = Objects.equals(CACHE_MASTER_ID, id) ?
|
||||
fileConfigMapper.selectByMaster() : fileConfigMapper.selectById(id);
|
||||
if (config != null) {
|
||||
fileClientFactory.createOrUpdateFileClient(id, config.getStorage(), config.getConfig());
|
||||
fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig());
|
||||
}
|
||||
return fileClientFactory.getFileClient(id);
|
||||
return fileClientFactory.getFileClient(null == config ? id : config.getId());
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>yudao</artifactId>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>yudao-module-mall</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
<description>
|
||||
商城大模块,由 product 商品、promotion 营销、trade 交易、statistics 统计等组成
|
||||
</description>
|
||||
<modules>
|
||||
<module>yudao-module-promotion-api</module>
|
||||
<module>yudao-module-promotion-biz</module>
|
||||
<module>yudao-module-product-api</module>
|
||||
<module>yudao-module-product-biz</module>
|
||||
<module>yudao-module-trade-api</module>
|
||||
<module>yudao-module-trade-biz</module>
|
||||
<!-- <module>yudao-module-statistics-api</module>-->
|
||||
<!-- <module>yudao-module-statistics-biz</module>-->
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-module-mall</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>yudao-module-product-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
product 模块 API,暴露给其它模块调用
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-ui</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package cn.iocoder.yudao.module.product.api.category;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 商品分类")
|
||||
public interface ProductCategoryApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/category";
|
||||
|
||||
@GetMapping(PREFIX + "/valid")
|
||||
@Operation(summary = "校验部门是否合法")
|
||||
@Parameter(name = "ids", description = "商品分类编号数组", example = "1,2", required = true)
|
||||
CommonResult<Boolean> validateCategoryList(@RequestParam("ids") Collection<Long> ids);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package cn.iocoder.yudao.module.product.api.comment;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.product.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 产品评论")
|
||||
public interface ProductCommentApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/comment";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建评论")
|
||||
CommonResult<Long> createComment(@RequestBody @Valid ProductCommentCreateReqDTO createReqDTO);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package cn.iocoder.yudao.module.product.api.comment.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "RPC 服务 - 商品评论创建 Request DTO")
|
||||
@Data
|
||||
public class ProductCommentCreateReqDTO {
|
||||
|
||||
@Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "商品 SKU 编号不能为空")
|
||||
private Long skuId;
|
||||
@Schema(description = "订单编号", example = "223")
|
||||
private Long orderId;
|
||||
@Schema(description = "交易订单项编号", example = "666")
|
||||
private Long orderItemId;
|
||||
|
||||
@Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
|
||||
@NotNull(message = "描述星级不能为空")
|
||||
private Integer descriptionScores;
|
||||
@Schema(description = "服务星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
|
||||
@NotNull(message = "服务星级不能为空")
|
||||
private Integer benefitScores;
|
||||
@Schema(description = "评论内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "好评")
|
||||
@NotNull(message = "评论内容不能为空")
|
||||
private String content;
|
||||
@Schema(description = "评论图片地址数组,以逗号分隔最多上传 9 张", example = "https://www.iocoder.cn/xxx.jpg,http://www.iocoder.cn/yyy.jpg")
|
||||
private List<String> picUrls;
|
||||
|
||||
@Schema(description = "是否匿名", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "是否匿名不能为空")
|
||||
private Boolean anonymous;
|
||||
@Schema(description = "评价人", requiredMode = Schema.RequiredMode.REQUIRED, example = "888")
|
||||
@NotNull(message = "评价人不能为空")
|
||||
private Long userId;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* 占位
|
||||
*/
|
||||
package cn.iocoder.yudao.module.product.api;
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package cn.iocoder.yudao.module.product.api.property.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "RPC 服务 - 商品属性项的明细 Response DTO")
|
||||
@Data
|
||||
public class ProductPropertyValueDetailRespDTO {
|
||||
|
||||
@Schema(description = "属性的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long propertyId;
|
||||
@Schema(description = "属性的名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色")
|
||||
private String propertyName;
|
||||
|
||||
@Schema(description = "属性值的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long valueId;
|
||||
@Schema(description = "属性值的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色")
|
||||
private String valueName;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package cn.iocoder.yudao.module.product.api.sku;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.product.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 商品 SKU")
|
||||
public interface ProductSkuApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/sku";
|
||||
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "查询 SKU 信息")
|
||||
@Parameter(name = "id", description = "SKU 编号", required = true, example = "1024")
|
||||
CommonResult<ProductSkuRespDTO> getSku(@RequestParam("id") Long id);
|
||||
|
||||
@GetMapping(PREFIX + "/list")
|
||||
@Operation(summary = "批量查询 SKU 信息")
|
||||
@Parameter(name = "ids", description = "SKU 编号列表", required = true, example = "1024,2048")
|
||||
CommonResult<List<ProductSkuRespDTO>> getSkuList(@RequestParam("ids") Collection<Long> ids);
|
||||
|
||||
@GetMapping(PREFIX + "/list-by-spu-id")
|
||||
@Operation(summary = "批量查询 SKU 信息")
|
||||
@Parameter(name = "spuIds", description = "SPU 编号列表", required = true, example = "1024,2048")
|
||||
CommonResult<List<ProductSkuRespDTO>> getSkuListBySpuId(@RequestParam("spuIds") Collection<Long> spuIds);
|
||||
|
||||
@PostMapping(PREFIX + "/update-stock")
|
||||
@Operation(summary = "更新 SKU 库存(增加 or 减少)")
|
||||
CommonResult<Boolean> updateSkuStock(@RequestBody @Valid ProductSkuUpdateStockReqDTO updateStockReqDTO);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package cn.iocoder.yudao.module.product.api.sku.dto;
|
||||
|
||||
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "RPC 服务 - 商品 SKU 信息 Response DTO")
|
||||
@Data
|
||||
public class ProductSkuRespDTO {
|
||||
|
||||
@Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
@Schema(description = "SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "属性数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<ProductPropertyValueDetailRespDTO> properties;
|
||||
|
||||
@Schema(description = "销售价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Integer price;
|
||||
@Schema(description = "市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
private Integer marketPrice;
|
||||
@Schema(description = "成本价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "300")
|
||||
private Integer costPrice;
|
||||
@Schema(description = "SKU 的条形码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456789")
|
||||
private String barCode;
|
||||
@Schema(description = "图片地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg")
|
||||
private String picUrl;
|
||||
|
||||
@Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Integer stock;
|
||||
@Schema(description = "商品重量,单位:kg 千克", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.5")
|
||||
private Double weight;
|
||||
@Schema(description = "商品体积,单位:m^3 平米", requiredMode = Schema.RequiredMode.REQUIRED, example = "3.0")
|
||||
private Double volume;
|
||||
|
||||
@Schema(description = "一级分销的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "550")
|
||||
private Integer firstBrokeragePrice;
|
||||
@Schema(description = "二级分销的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "250")
|
||||
private Integer secondBrokeragePrice;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package cn.iocoder.yudao.module.product.api.sku.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "RPC 服务 - 商品 SKU 更新库存 Request DTO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ProductSkuUpdateStockReqDTO {
|
||||
|
||||
@Schema(description = "商品 SKU 数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "商品 SKU 不能为空")
|
||||
private List<Item> items;
|
||||
|
||||
@Data
|
||||
public static class Item {
|
||||
|
||||
@Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "商品 SKU 编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "库存变化数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
@NotNull(message = "库存变化数量不能为空")
|
||||
private Integer incrCount; // 正数:增加库存;负数:扣减库存
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package cn.iocoder.yudao.module.product.api.spu;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 商品 SPU")
|
||||
public interface ProductSpuApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/spu";
|
||||
|
||||
@GetMapping(PREFIX + "/list")
|
||||
@Schema(description = "批量查询 SPU 数组")
|
||||
@Parameter(name = "ids", description = "SPU 编号列表", required = true, example = "1,3,5")
|
||||
CommonResult<List<ProductSpuRespDTO>> getSpuList(@RequestParam("ids") Collection<Long> ids);
|
||||
|
||||
@GetMapping(PREFIX + "/valid")
|
||||
@Schema(description = "批量查询 SPU 数组,并且校验是否 SPU 是否有效")
|
||||
@Parameter(name = "ids", description = "SPU 编号列表", required = true, example = "1,3,5")
|
||||
CommonResult<List<ProductSpuRespDTO>> validateSpuList(@RequestParam("ids") Collection<Long> ids);
|
||||
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Schema(description = "获得 SPU")
|
||||
@Parameter(name = "id", description = "SPU 编号", required = true, example = "1")
|
||||
CommonResult<ProductSpuRespDTO> getSpu(@RequestParam("id") Long id);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
package cn.iocoder.yudao.module.product.api.spu.dto;
|
||||
|
||||
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
|
||||
import lombok.Data;
|
||||
|
||||
// TODO @LeeYan9: ProductSpuRespDTO
|
||||
|
||||
/**
|
||||
* 商品 SPU 信息 Response DTO
|
||||
*
|
||||
* @author LeeYan9
|
||||
* @since 2022-08-26
|
||||
*/
|
||||
@Data
|
||||
public class ProductSpuRespDTO {
|
||||
|
||||
/**
|
||||
* 商品 SPU 编号,自增
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
// ========== 基本信息 =========
|
||||
|
||||
/**
|
||||
* 商品名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 单位
|
||||
*
|
||||
* 对应 product_unit 数据字典
|
||||
*/
|
||||
private Integer unit;
|
||||
|
||||
/**
|
||||
* 商品分类编号
|
||||
*/
|
||||
private Long categoryId;
|
||||
/**
|
||||
* 商品封面图
|
||||
*/
|
||||
private String picUrl;
|
||||
|
||||
/**
|
||||
* 商品状态
|
||||
* <p>
|
||||
* 枚举 {@link ProductSpuStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
// ========== SKU 相关字段 =========
|
||||
|
||||
/**
|
||||
* 规格类型
|
||||
*
|
||||
* false - 单规格
|
||||
* true - 多规格
|
||||
*/
|
||||
private Boolean specType;
|
||||
/**
|
||||
* 商品价格,单位使用:分
|
||||
*/
|
||||
private Integer price;
|
||||
/**
|
||||
* 市场价,单位使用:分
|
||||
*/
|
||||
private Integer marketPrice;
|
||||
/**
|
||||
* 成本价,单位使用:分
|
||||
*/
|
||||
private Integer costPrice;
|
||||
/**
|
||||
* 库存
|
||||
*/
|
||||
private Integer stock;
|
||||
|
||||
// ========== 物流相关字段 =========
|
||||
|
||||
/**
|
||||
* 物流配置模板编号
|
||||
*
|
||||
* 对应 TradeDeliveryExpressTemplateDO 的 id 编号
|
||||
*/
|
||||
private Long deliveryTemplateId;
|
||||
|
||||
// ========== 营销相关字段 =========
|
||||
|
||||
/**
|
||||
* 赠送积分
|
||||
*/
|
||||
private Integer giveIntegral;
|
||||
|
||||
// ========== 分销相关字段 =========
|
||||
|
||||
/**
|
||||
* 分销类型
|
||||
*
|
||||
* false - 默认
|
||||
* true - 自行设置
|
||||
*/
|
||||
private Boolean subCommissionType;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package cn.iocoder.yudao.module.product.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.RpcConstants;
|
||||
|
||||
/**
|
||||
* API 相关的枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class ApiConstants {
|
||||
|
||||
/**
|
||||
* 服务名
|
||||
*
|
||||
* 注意,需要保证和 spring.application.name 保持一致
|
||||
*/
|
||||
public static final String NAME = "product-server";
|
||||
|
||||
public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/product";
|
||||
|
||||
public static final String VERSION = "1.0.0";
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package cn.iocoder.yudao.module.product.enums;
|
||||
|
||||
/**
|
||||
* product 字典类型的枚举类
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
public interface DictTypeConstants {
|
||||
|
||||
String PRODUCT_UNIT = "product_unit"; // 商品单位
|
||||
String PRODUCT_SPU_STATUS = "product_spu_status"; // 商品 SPU 状态
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package cn.iocoder.yudao.module.product.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* Product 错误码枚举类
|
||||
*
|
||||
* product 系统,使用 1-008-000-000 段
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 商品分类相关 1-008-001-000 ============
|
||||
ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1_008_001_000, "商品分类不存在");
|
||||
ErrorCode CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1_008_001_001, "父分类不存在");
|
||||
ErrorCode CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1_008_001_002, "父分类不能是二级分类");
|
||||
ErrorCode CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_008_001_003, "存在子分类,无法删除");
|
||||
ErrorCode CATEGORY_DISABLED = new ErrorCode(1_008_001_004, "商品分类({})已禁用,无法使用");
|
||||
ErrorCode CATEGORY_HAVE_BIND_SPU = new ErrorCode(1_008_001_005, "类别下存在商品,无法删除");
|
||||
|
||||
// ========== 商品品牌相关编号 1-008-002-000 ==========
|
||||
ErrorCode BRAND_NOT_EXISTS = new ErrorCode(1_008_002_000, "品牌不存在");
|
||||
ErrorCode BRAND_DISABLED = new ErrorCode(1_008_002_001, "品牌已禁用");
|
||||
ErrorCode BRAND_NAME_EXISTS = new ErrorCode(1_008_002_002, "品牌名称已存在");
|
||||
|
||||
// ========== 商品属性项 1-008-003-000 ==========
|
||||
ErrorCode PROPERTY_NOT_EXISTS = new ErrorCode(1_008_003_000, "属性项不存在");
|
||||
ErrorCode PROPERTY_EXISTS = new ErrorCode(1_008_003_001, "属性项的名称已存在");
|
||||
ErrorCode PROPERTY_DELETE_FAIL_VALUE_EXISTS = new ErrorCode(1_008_003_002, "属性项下存在属性值,无法删除");
|
||||
|
||||
// ========== 商品属性值 1-008-004-000 ==========
|
||||
ErrorCode PROPERTY_VALUE_NOT_EXISTS = new ErrorCode(1_008_004_000, "属性值不存在");
|
||||
ErrorCode PROPERTY_VALUE_EXISTS = new ErrorCode(1_008_004_001, "属性值的名称已存在");
|
||||
|
||||
// ========== 商品 SPU 1-008-005-000 ==========
|
||||
ErrorCode SPU_NOT_EXISTS = new ErrorCode(1_008_005_000, "商品 SPU 不存在");
|
||||
ErrorCode SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR = new ErrorCode(1_008_005_001, "商品分类不正确,原因:必须使用第二级的商品分类及以下");
|
||||
ErrorCode SPU_SAVE_FAIL_COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1_008_005_002, "商品 SPU 保存失败,原因:优惠卷不存在");
|
||||
ErrorCode SPU_NOT_ENABLE = new ErrorCode(1_008_005_003, "商品 SPU【{}】不处于上架状态");
|
||||
ErrorCode SPU_NOT_RECYCLE = new ErrorCode(1_008_005_004, "商品 SPU 不处于回收站状态");
|
||||
|
||||
// ========== 商品 SKU 1-008-006-000 ==========
|
||||
ErrorCode SKU_NOT_EXISTS = new ErrorCode(1_008_006_000, "商品 SKU 不存在");
|
||||
ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1_008_006_001, "商品 SKU 的属性组合存在重复");
|
||||
ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1_008_006_002, "一个 SPU 下的每个 SKU,其属性项必须一致");
|
||||
ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1_008_006_003, "一个 SPU 下的每个 SKU,必须不重复");
|
||||
ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1_008_006_004, "商品 SKU 库存不足");
|
||||
|
||||
// ========== 商品 评价 1-008-007-000 ==========
|
||||
ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1_008_007_000, "商品评价不存在");
|
||||
ErrorCode COMMENT_ORDER_EXISTS = new ErrorCode(1_008_007_001, "订单的商品评价已存在");
|
||||
|
||||
// ========== 商品 收藏 1-008-008-000 ==========
|
||||
ErrorCode FAVORITE_EXISTS = new ErrorCode(1_008_008_000, "该商品已经被收藏");
|
||||
ErrorCode FAVORITE_NOT_EXISTS = new ErrorCode(1_008_008_001, "商品收藏不存在");
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package cn.iocoder.yudao.module.product.enums;
|
||||
|
||||
/**
|
||||
* Product 常量
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
public interface ProductConstants {
|
||||
|
||||
/**
|
||||
* 警戒库存 TODO 警戒库存暂时为 10,后期需要使用常量或者数据库配置替换
|
||||
*/
|
||||
int ALERT_STOCK = 10;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package cn.iocoder.yudao.module.product.enums.comment;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 商品评论的审批状态枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ProductCommentAuditStatusEnum implements IntArrayValuable {
|
||||
|
||||
NONE(1, "待审核"),
|
||||
APPROVE(2, "审批通过"),
|
||||
REJECT(2, "审批不通过"),;
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductCommentAuditStatusEnum::getStatus).toArray();
|
||||
|
||||
/**
|
||||
* 审批状态
|
||||
*/
|
||||
private final Integer status;
|
||||
/**
|
||||
* 状态名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package cn.iocoder.yudao.module.product.enums.comment;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 商品评论的星级枚举
|
||||
*
|
||||
* @author wangzhs
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ProductCommentScoresEnum implements IntArrayValuable {
|
||||
|
||||
ONE(1, "1星"),
|
||||
TWO(2, "2星"),
|
||||
THREE(3, "3星"),
|
||||
FOUR(4, "4星"),
|
||||
FIVE(5, "5星");
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductCommentScoresEnum::getScores).toArray();
|
||||
|
||||
/**
|
||||
* 星级
|
||||
*/
|
||||
private final Integer scores;
|
||||
|
||||
/**
|
||||
* 星级名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package cn.iocoder.yudao.module.product.enums.spu;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 商品 SPU 状态
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ProductSpuStatusEnum implements IntArrayValuable {
|
||||
|
||||
RECYCLE(-1, "回收站"),
|
||||
DISABLE(0, "下架"),
|
||||
ENABLE(1, "上架");
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuStatusEnum::getStatus).toArray();
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private final Integer status;
|
||||
/**
|
||||
* 状态名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否处于【上架】状态
|
||||
*
|
||||
* @param status 状态
|
||||
* @return 是否处于【上架】状态
|
||||
*/
|
||||
public static boolean isEnable(Integer status) {
|
||||
return ENABLE.getStatus().equals(status);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性
|
||||
## 感谢复旦核博士的建议!灰子哥,牛皮!
|
||||
FROM eclipse-temurin:8-jre
|
||||
|
||||
## 创建目录,并使用它作为工作目录
|
||||
RUN mkdir -p /yudao-module-product-biz
|
||||
WORKDIR /yudao-module-product-biz
|
||||
## 将后端项目的 Jar 文件,复制到镜像中
|
||||
COPY ./target/yudao-module-product-biz.jar app.jar
|
||||
|
||||
## 设置 TZ 时区
|
||||
## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖
|
||||
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms512m -Xmx512m"
|
||||
|
||||
## 暴露后端项目的 48080 端口
|
||||
EXPOSE 48100
|
||||
|
||||
## 启动后端项目
|
||||
CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-module-mall</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>yudao-module-product-biz</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
product 模块,主要实现商品相关功能
|
||||
例如:品牌、商品分类、spu、sku等功能。
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Cloud 基础 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-env</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 依赖服务 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-module-product-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-module-member-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 业务组件 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-rpc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 注册中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Config 配置中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 监控相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package cn.iocoder.yudao.module.product;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* 项目的启动类
|
||||
*
|
||||
* 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
|
||||
* 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
|
||||
* 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class ProductServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
|
||||
// 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
|
||||
// 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
|
||||
|
||||
SpringApplication.run(ProductServerApplication.class, args);
|
||||
|
||||
// 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
|
||||
// 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
|
||||
// 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package cn.iocoder.yudao.module.product.api.category;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.service.category.ProductCategoryService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* 商品分类 API 接口实现类
|
||||
*
|
||||
* @author owen
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProductCategoryApiImpl implements ProductCategoryApi {
|
||||
|
||||
@Resource
|
||||
private ProductCategoryService productCategoryService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> validateCategoryList(Collection<Long> ids) {
|
||||
productCategoryService.validateCategoryList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package cn.iocoder.yudao.module.product.api.comment;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* 商品评论 API 实现类
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProductCommentApiImpl implements ProductCommentApi {
|
||||
|
||||
@Resource
|
||||
private ProductCommentService productCommentService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> createComment(ProductCommentCreateReqDTO createReqDTO) {
|
||||
return success(productCommentService.createComment(createReqDTO));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
package cn.iocoder.yudao.module.product.api;
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package cn.iocoder.yudao.module.product.api.sku;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
|
||||
import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
|
||||
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* 商品 SKU API 实现类
|
||||
*
|
||||
* @author LeeYan9
|
||||
* @since 2022-09-06
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProductSkuApiImpl implements ProductSkuApi {
|
||||
|
||||
@Resource
|
||||
private ProductSkuService productSkuService;
|
||||
|
||||
@Override
|
||||
public CommonResult<ProductSkuRespDTO> getSku(Long id) {
|
||||
ProductSkuDO sku = productSkuService.getSku(id);
|
||||
return success(ProductSkuConvert.INSTANCE.convert02(sku));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<ProductSkuRespDTO>> getSkuList(Collection<Long> ids) {
|
||||
List<ProductSkuDO> skus = productSkuService.getSkuList(ids);
|
||||
return success(ProductSkuConvert.INSTANCE.convertList04(skus));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<ProductSkuRespDTO>> getSkuListBySpuId(Collection<Long> spuIds) {
|
||||
List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spuIds);
|
||||
return success(ProductSkuConvert.INSTANCE.convertList04(skus));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO) {
|
||||
productSkuService.updateSkuStock(updateStockReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package cn.iocoder.yudao.module.product.api.spu;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
|
||||
import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* 商品 SPU API 接口实现类
|
||||
*
|
||||
* @author LeeYan9
|
||||
* @since 2022-09-06
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProductSpuApiImpl implements ProductSpuApi {
|
||||
|
||||
@Resource
|
||||
private ProductSpuService spuService;
|
||||
|
||||
@Override
|
||||
public CommonResult<List<ProductSpuRespDTO>> getSpuList(Collection<Long> ids) {
|
||||
return success(ProductSpuConvert.INSTANCE.convertList2(spuService.getSpuList(ids)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<ProductSpuRespDTO>> validateSpuList(Collection<Long> ids) {
|
||||
return success(ProductSpuConvert.INSTANCE.convertList2(spuService.validateSpuList(ids)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<ProductSpuRespDTO> getSpu(Long id) {
|
||||
return success(ProductSpuConvert.INSTANCE.convert02(spuService.getSpu(id)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.brand;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
|
||||
import cn.iocoder.yudao.module.product.convert.brand.ProductBrandConvert;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO;
|
||||
import cn.iocoder.yudao.module.product.service.brand.ProductBrandService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 商品品牌")
|
||||
@RestController
|
||||
@RequestMapping("/product/brand")
|
||||
@Validated
|
||||
public class ProductBrandController {
|
||||
|
||||
@Resource
|
||||
private ProductBrandService brandService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建品牌")
|
||||
@PreAuthorize("@ss.hasPermission('product:brand:create')")
|
||||
public CommonResult<Long> createBrand(@Valid @RequestBody ProductBrandCreateReqVO createReqVO) {
|
||||
return success(brandService.createBrand(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新品牌")
|
||||
@PreAuthorize("@ss.hasPermission('product:brand:update')")
|
||||
public CommonResult<Boolean> updateBrand(@Valid @RequestBody ProductBrandUpdateReqVO updateReqVO) {
|
||||
brandService.updateBrand(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除品牌")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('product:brand:delete')")
|
||||
public CommonResult<Boolean> deleteBrand(@RequestParam("id") Long id) {
|
||||
brandService.deleteBrand(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得品牌")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('product:brand:query')")
|
||||
public CommonResult<ProductBrandRespVO> getBrand(@RequestParam("id") Long id) {
|
||||
ProductBrandDO brand = brandService.getBrand(id);
|
||||
return success(ProductBrandConvert.INSTANCE.convert(brand));
|
||||
}
|
||||
|
||||
@GetMapping("/list-all-simple")
|
||||
@Operation(summary = "获取品牌精简信息列表", description = "主要用于前端的下拉选项")
|
||||
public CommonResult<List<ProductBrandSimpleRespVO>> getSimpleBrandList() {
|
||||
// 获取品牌列表,只要开启状态的
|
||||
List<ProductBrandDO> list = brandService.getBrandListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
// 排序后,返回给前端
|
||||
return success(ProductBrandConvert.INSTANCE.convertList1(list));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得品牌分页")
|
||||
@PreAuthorize("@ss.hasPermission('product:brand:query')")
|
||||
public CommonResult<PageResult<ProductBrandRespVO>> getBrandPage(@Valid ProductBrandPageReqVO pageVO) {
|
||||
PageResult<ProductBrandDO> pageResult = brandService.getBrandPage(pageVO);
|
||||
return success(ProductBrandConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得品牌列表")
|
||||
@PreAuthorize("@ss.hasPermission('product:brand:query')")
|
||||
public CommonResult<List<ProductBrandRespVO>> getBrandList(@Valid ProductBrandListReqVO listVO) {
|
||||
List<ProductBrandDO> list = brandService.getBrandList(listVO);
|
||||
list.sort(Comparator.comparing(ProductBrandDO::getSort));
|
||||
return success(ProductBrandConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 商品品牌 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
*/
|
||||
@Data
|
||||
public class ProductBrandBaseVO {
|
||||
|
||||
@Schema(description = "品牌名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "苹果")
|
||||
@NotNull(message = "品牌名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "品牌图片", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "品牌图片不能为空")
|
||||
private String picUrl;
|
||||
|
||||
@Schema(description = "品牌排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "品牌排序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "品牌描述", example = "描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 商品品牌创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductBrandCreateReqVO extends ProductBrandBaseVO {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 商品品牌分页 Request VO")
|
||||
@Data
|
||||
public class ProductBrandListReqVO {
|
||||
|
||||
@Schema(description = "品牌名称", example = "苹果")
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 商品品牌分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductBrandPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "品牌名称", example = "苹果")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "状态", example = "0")
|
||||
private Integer status;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 品牌 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductBrandRespVO extends ProductBrandBaseVO {
|
||||
|
||||
@Schema(description = "品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Schema(description = "管理后台 - 品牌精简信息 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ProductBrandSimpleRespVO {
|
||||
|
||||
@Schema(description = "品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "品牌名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "苹果")
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.brand.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 商品品牌更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductBrandUpdateReqVO extends ProductBrandBaseVO {
|
||||
|
||||
@Schema(description = "品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "品牌编号不能为空")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.category;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryCreateReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.product.convert.category.ProductCategoryConvert;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
|
||||
import cn.iocoder.yudao.module.product.service.category.ProductCategoryService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 商品分类")
|
||||
@RestController
|
||||
@RequestMapping("/product/category")
|
||||
@Validated
|
||||
public class ProductCategoryController {
|
||||
|
||||
@Resource
|
||||
private ProductCategoryService categoryService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建商品分类")
|
||||
@PreAuthorize("@ss.hasPermission('product:category:create')")
|
||||
public CommonResult<Long> createCategory(@Valid @RequestBody ProductCategoryCreateReqVO createReqVO) {
|
||||
return success(categoryService.createCategory(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新商品分类")
|
||||
@PreAuthorize("@ss.hasPermission('product:category:update')")
|
||||
public CommonResult<Boolean> updateCategory(@Valid @RequestBody ProductCategoryUpdateReqVO updateReqVO) {
|
||||
categoryService.updateCategory(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除商品分类")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('product:category:delete')")
|
||||
public CommonResult<Boolean> deleteCategory(@RequestParam("id") Long id) {
|
||||
categoryService.deleteCategory(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得商品分类")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('product:category:query')")
|
||||
public CommonResult<ProductCategoryRespVO> getCategory(@RequestParam("id") Long id) {
|
||||
ProductCategoryDO category = categoryService.getCategory(id);
|
||||
return success(ProductCategoryConvert.INSTANCE.convert(category));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得商品分类列表")
|
||||
@PreAuthorize("@ss.hasPermission('product:category:query')")
|
||||
public CommonResult<List<ProductCategoryRespVO>> getCategoryList(@Valid ProductCategoryListReqVO treeListReqVO) {
|
||||
List<ProductCategoryDO> list = categoryService.getEnableCategoryList(treeListReqVO);
|
||||
list.sort(Comparator.comparing(ProductCategoryDO::getSort));
|
||||
return success(ProductCategoryConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.category.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 商品分类 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
*/
|
||||
@Data
|
||||
public class ProductCategoryBaseVO {
|
||||
|
||||
@Schema(description = "父分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "父分类编号不能为空")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "办公文具")
|
||||
@NotBlank(message = "分类名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "移动端分类图", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "移动端分类图不能为空")
|
||||
private String picUrl;
|
||||
|
||||
@Schema(description = "PC 端分类图")
|
||||
private String bigPicUrl;
|
||||
|
||||
@Schema(description = "分类排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "开启状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.category.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Schema(description = "管理后台 - 商品分类创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductCategoryCreateReqVO extends ProductCategoryBaseVO {
|
||||
|
||||
@Schema(description = "分类描述", example = "描述")
|
||||
private String description;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.category.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 商品分类列表查询 Request VO")
|
||||
@Data
|
||||
public class ProductCategoryListReqVO {
|
||||
|
||||
@Schema(description = "分类名称", example = "办公文具")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "开启状态", example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "父分类编号", example = "1")
|
||||
private Long parentId;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.category.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 商品分类 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductCategoryRespVO extends ProductCategoryBaseVO {
|
||||
|
||||
@Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.category.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 商品分类更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductCategoryUpdateReqVO extends ProductCategoryBaseVO {
|
||||
|
||||
@Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@NotNull(message = "分类编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "分类描述", example = "描述")
|
||||
private String description;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.comment;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.comment.vo.*;
|
||||
import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
|
||||
import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - 商品评价")
|
||||
@RestController
|
||||
@RequestMapping("/product/comment")
|
||||
@Validated
|
||||
public class ProductCommentController {
|
||||
|
||||
@Resource
|
||||
private ProductCommentService productCommentService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得商品评价分页")
|
||||
@PreAuthorize("@ss.hasPermission('product:comment:query')")
|
||||
public CommonResult<PageResult<ProductCommentRespVO>> getCommentPage(@Valid ProductCommentPageReqVO pageVO) {
|
||||
PageResult<ProductCommentDO> pageResult = productCommentService.getCommentPage(pageVO);
|
||||
return success(ProductCommentConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@PutMapping("/update-visible")
|
||||
@Operation(summary = "显示 / 隐藏评论")
|
||||
@PreAuthorize("@ss.hasPermission('product:comment:update')")
|
||||
public CommonResult<Boolean> updateCommentVisible(@Valid @RequestBody ProductCommentUpdateVisibleReqVO updateReqVO) {
|
||||
productCommentService.updateCommentVisible(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/reply")
|
||||
@Operation(summary = "商家回复")
|
||||
@PreAuthorize("@ss.hasPermission('product:comment:update')")
|
||||
public CommonResult<Boolean> commentReply(@Valid @RequestBody ProductCommentReplyReqVO replyVO) {
|
||||
productCommentService.replyComment(replyVO, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "添加自评")
|
||||
@PreAuthorize("@ss.hasPermission('product:comment:update')")
|
||||
public CommonResult<Boolean> createComment(@Valid @RequestBody ProductCommentCreateReqVO createReqVO) {
|
||||
productCommentService.createComment(createReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.comment.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ProductCommentBaseVO {
|
||||
|
||||
@Schema(description = "评价人", requiredMode = Schema.RequiredMode.REQUIRED, example = "16868")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "评价订单项", requiredMode = Schema.RequiredMode.REQUIRED, example = "19292")
|
||||
private Long orderItemId;
|
||||
|
||||
@Schema(description = "评价人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小姑凉")
|
||||
@NotNull(message = "评价人名称不能为空")
|
||||
private String userNickname;
|
||||
|
||||
@Schema(description = "评价人头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
|
||||
@NotNull(message = "评价人头像不能为空")
|
||||
private String userAvatar;
|
||||
|
||||
@Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "商品 SKU 编号不能为空")
|
||||
private Long skuId;
|
||||
|
||||
@Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
|
||||
@NotNull(message = "描述星级不能为空")
|
||||
private Integer descriptionScores;
|
||||
|
||||
@Schema(description = "服务星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
|
||||
@NotNull(message = "服务星级分不能为空")
|
||||
private Integer benefitScores;
|
||||
|
||||
@Schema(description = "评论内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "穿起来非常丝滑凉快")
|
||||
@NotNull(message = "评论内容不能为空")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "评论图片地址数组,以逗号分隔最多上传 9 张", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/xx.png]")
|
||||
@Size(max = 9, message = "评论图片地址数组长度不能超过 9 张")
|
||||
private List<String> picUrls;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.comment.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 商品评价创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductCommentCreateReqVO extends ProductCommentBaseVO {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.comment.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.product.enums.comment.ProductCommentScoresEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 商品评价分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductCommentPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "评价人名称", example = "王二狗")
|
||||
private String userNickname;
|
||||
|
||||
@Schema(description = "交易订单编号", example = "24428")
|
||||
private Long orderId;
|
||||
|
||||
@Schema(description = "商品SPU编号", example = "29502")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "商品SPU名称", example = "感冒药")
|
||||
private String spuName;
|
||||
|
||||
@Schema(description = "评分星级 1-5 分", example = "5")
|
||||
@InEnum(ProductCommentScoresEnum.class)
|
||||
private Integer scores;
|
||||
|
||||
@Schema(description = "商家是否回复", example = "true")
|
||||
private Boolean replyStatus;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.comment.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 商品评价的商家回复 Request VO")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class ProductCommentReplyReqVO {
|
||||
|
||||
@Schema(description = "评价编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15721")
|
||||
@NotNull(message = "评价编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "商家回复内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "谢谢亲")
|
||||
@NotEmpty(message = "商家回复内容不能为空")
|
||||
private String replyContent;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.comment.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 商品评价 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductCommentRespVO extends ProductCommentBaseVO {
|
||||
|
||||
@Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24965")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "是否匿名", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||
private Boolean anonymous;
|
||||
|
||||
@Schema(description = "交易订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24428")
|
||||
private Long orderId;
|
||||
|
||||
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Boolean visible;
|
||||
|
||||
@Schema(description = "商家是否回复", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Boolean replyStatus;
|
||||
|
||||
@Schema(description = "回复管理员编号", example = "9527")
|
||||
private Long replyUserId;
|
||||
|
||||
@Schema(description = "商家回复内容", example = "感谢好评哦亲(づ ̄3 ̄)づ╭❤~")
|
||||
private String replyContent;
|
||||
|
||||
@Schema(description = "商家回复时间", example = "2023-08-08 12:20:55")
|
||||
private LocalDateTime replyTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
|
||||
private Integer scores;
|
||||
|
||||
@Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑透气小短袖")
|
||||
@NotNull(message = "商品 SPU 编号不能为空")
|
||||
private Long spuId;
|
||||
|
||||
@Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
|
||||
@NotNull(message = "商品 SPU 名称不能为空")
|
||||
private String spuName;
|
||||
|
||||
@Schema(description = "商品 SKU 图片地址", example = "https://www.iocoder.cn/yudao.jpg")
|
||||
private String skuPicUrl;
|
||||
|
||||
@Schema(description = "商品 SKU 规格值数组")
|
||||
private List<ProductSkuBaseVO.Property> skuProperties;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.comment.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 商品评价可见修改 Request VO")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class ProductCommentUpdateVisibleReqVO {
|
||||
|
||||
@Schema(description = "评价编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15721")
|
||||
@NotNull(message = "评价编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||
@NotNull(message = "是否可见不能为空")
|
||||
private Boolean visible;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*;
|
||||
import cn.iocoder.yudao.module.product.convert.property.ProductPropertyConvert;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
|
||||
import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
|
||||
import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@Tag(name = "管理后台 - 商品属性项")
|
||||
@RestController
|
||||
@RequestMapping("/product/property")
|
||||
@Validated
|
||||
public class ProductPropertyController {
|
||||
|
||||
@Resource
|
||||
private ProductPropertyService productPropertyService;
|
||||
@Resource
|
||||
private ProductPropertyValueService productPropertyValueService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建属性项")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:create')")
|
||||
public CommonResult<Long> createProperty(@Valid @RequestBody ProductPropertyCreateReqVO createReqVO) {
|
||||
return success(productPropertyService.createProperty(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新属性项")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:update')")
|
||||
public CommonResult<Boolean> updateProperty(@Valid @RequestBody ProductPropertyUpdateReqVO updateReqVO) {
|
||||
productPropertyService.updateProperty(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除属性项")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('product:property:delete')")
|
||||
public CommonResult<Boolean> deleteProperty(@RequestParam("id") Long id) {
|
||||
productPropertyService.deleteProperty(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得属性项")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:query')")
|
||||
public CommonResult<ProductPropertyRespVO> getProperty(@RequestParam("id") Long id) {
|
||||
return success(ProductPropertyConvert.INSTANCE.convert(productPropertyService.getProperty(id)));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得属性项列表")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:query')")
|
||||
public CommonResult<List<ProductPropertyRespVO>> getPropertyList(@Valid ProductPropertyListReqVO listReqVO) {
|
||||
return success(ProductPropertyConvert.INSTANCE.convertList(productPropertyService.getPropertyList(listReqVO)));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得属性项分页")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:query')")
|
||||
public CommonResult<PageResult<ProductPropertyRespVO>> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) {
|
||||
return success(ProductPropertyConvert.INSTANCE.convertPage(productPropertyService.getPropertyPage(pageVO)));
|
||||
}
|
||||
|
||||
@PostMapping("/get-value-list")
|
||||
@Operation(summary = "获得属性项列表")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:query')")
|
||||
public CommonResult<List<ProductPropertyAndValueRespVO>> getPropertyAndValueList(
|
||||
@Valid @RequestBody ProductPropertyListReqVO listReqVO) {
|
||||
// 查询属性项
|
||||
List<ProductPropertyDO> keys = productPropertyService.getPropertyList(listReqVO);
|
||||
if (CollUtil.isEmpty(keys)) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
// 查询属性值
|
||||
List<ProductPropertyValueDO> values = productPropertyValueService.getPropertyValueListByPropertyId(
|
||||
convertSet(keys, ProductPropertyDO::getId));
|
||||
return success(ProductPropertyConvert.INSTANCE.convertList(keys, values));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.product.convert.property.ProductPropertyValueConvert;
|
||||
import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 商品属性值")
|
||||
@RestController
|
||||
@RequestMapping("/product/property/value")
|
||||
@Validated
|
||||
public class ProductPropertyValueController {
|
||||
|
||||
@Resource
|
||||
private ProductPropertyValueService productPropertyValueService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建属性值")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:create')")
|
||||
public CommonResult<Long> createPropertyValue(@Valid @RequestBody ProductPropertyValueCreateReqVO createReqVO) {
|
||||
return success(productPropertyValueService.createPropertyValue(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新属性值")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:update')")
|
||||
public CommonResult<Boolean> updatePropertyValue(@Valid @RequestBody ProductPropertyValueUpdateReqVO updateReqVO) {
|
||||
productPropertyValueService.updatePropertyValue(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除属性值")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:delete')")
|
||||
public CommonResult<Boolean> deletePropertyValue(@RequestParam("id") Long id) {
|
||||
productPropertyValueService.deletePropertyValue(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得属性值")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:query')")
|
||||
public CommonResult<ProductPropertyValueRespVO> getPropertyValue(@RequestParam("id") Long id) {
|
||||
return success(ProductPropertyValueConvert.INSTANCE.convert(productPropertyValueService.getPropertyValue(id)));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得属性值分页")
|
||||
@PreAuthorize("@ss.hasPermission('product:property:query')")
|
||||
public CommonResult<PageResult<ProductPropertyValueRespVO>> getPropertyValuePage(@Valid ProductPropertyValuePageReqVO pageVO) {
|
||||
return success(ProductPropertyValueConvert.INSTANCE.convertPage(productPropertyValueService.getPropertyValuePage(pageVO)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 商品属性项 + 属性值 Response VO")
|
||||
@Data
|
||||
public class ProductPropertyAndValueRespVO {
|
||||
|
||||
@Schema(description = "属性项的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "属性项的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 属性值的集合
|
||||
*/
|
||||
private List<Value> values;
|
||||
|
||||
@Schema(description = "管理后台 - 属性值的简单 Response VO")
|
||||
@Data
|
||||
public static class Value {
|
||||
|
||||
@Schema(description = "属性值的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "属性值的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色")
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 商品属性项 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
*/
|
||||
@Data
|
||||
public class ProductPropertyBaseVO {
|
||||
|
||||
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色")
|
||||
@NotBlank(message = "名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "备注", example = "颜色")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 属性项创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyCreateReqVO extends ProductPropertyBaseVO {
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 属性项 List Request VO")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyListReqVO {
|
||||
|
||||
@Schema(description = "属性名称", example = "颜色")
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 属性项 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "名称", example = "颜色")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 属性项 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyRespVO extends ProductPropertyBaseVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 属性项更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyUpdateReqVO extends ProductPropertyBaseVO {
|
||||
|
||||
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "主键不能为空")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.value;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 属性值 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
*/
|
||||
@Data
|
||||
public class ProductPropertyValueBaseVO {
|
||||
|
||||
@Schema(description = "属性项的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "属性项的编号不能为空")
|
||||
private Long propertyId;
|
||||
|
||||
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色")
|
||||
@NotEmpty(message = "名称名字不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "备注", example = "颜色")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.value;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 商品属性值创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyValueCreateReqVO extends ProductPropertyValueBaseVO {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.value;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 商品属性值的明细 Response VO")
|
||||
@Data
|
||||
public class ProductPropertyValueDetailRespVO {
|
||||
|
||||
@Schema(description = "属性的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long propertyId;
|
||||
|
||||
@Schema(description = "属性的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色")
|
||||
private String propertyName;
|
||||
|
||||
@Schema(description = "属性值的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long valueId;
|
||||
|
||||
@Schema(description = "属性值的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色")
|
||||
private String valueName;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.value;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 商品属性值分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyValuePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "属性项的编号", example = "1024")
|
||||
private String propertyId;
|
||||
|
||||
@Schema(description = "名称", example = "红色")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.value;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 商品属性值 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyValueRespVO extends ProductPropertyValueBaseVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.property.vo.value;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 商品属性值更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductPropertyValueUpdateReqVO extends ProductPropertyValueBaseVO {
|
||||
|
||||
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "主键不能为空")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.sku;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "管理后台 - 商品 SKU")
|
||||
@RestController
|
||||
@RequestMapping("/product/sku")
|
||||
@Validated
|
||||
public class ProductSkuController {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.sku.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商品 SKU Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
*/
|
||||
@Data
|
||||
public class ProductSkuBaseVO {
|
||||
|
||||
@Schema(description = "商品 SKU 名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖")
|
||||
@NotEmpty(message = "商品 SKU 名字不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "销售价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999")
|
||||
@NotNull(message = "销售价格,单位:分不能为空")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "市场价", example = "2999")
|
||||
private Integer marketPrice;
|
||||
|
||||
@Schema(description = "成本价", example = "19")
|
||||
private Integer costPrice;
|
||||
|
||||
@Schema(description = "条形码", example = "15156165456")
|
||||
private String barCode;
|
||||
|
||||
@Schema(description = "图片地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
|
||||
@NotNull(message = "图片地址不能为空")
|
||||
private String picUrl;
|
||||
|
||||
@Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
@NotNull(message = "库存不能为空")
|
||||
private Integer stock;
|
||||
|
||||
@Schema(description = "预警预存", example = "10")
|
||||
private Integer warnStock;
|
||||
|
||||
@Schema(description = "商品重量,单位:kg 千克", example = "1.2")
|
||||
private Double weight;
|
||||
|
||||
@Schema(description = "商品体积,单位:m^3 平米", example = "2.5")
|
||||
private Double volume;
|
||||
|
||||
@Schema(description = "一级分销的佣金,单位:分", example = "199")
|
||||
private Integer firstBrokeragePrice;
|
||||
|
||||
@Schema(description = "二级分销的佣金,单位:分", example = "19")
|
||||
private Integer secondBrokeragePrice;
|
||||
|
||||
@Schema(description = "属性数组")
|
||||
private List<Property> properties;
|
||||
|
||||
@Schema(description = "商品属性")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Property {
|
||||
|
||||
@Schema(description = "属性编号", example = "10")
|
||||
private Long propertyId;
|
||||
|
||||
@Schema(description = "属性名字", example = "颜色")
|
||||
private String propertyName;
|
||||
|
||||
@Schema(description = "属性值编号", example = "10")
|
||||
private Long valueId;
|
||||
|
||||
@Schema(description = "属性值名字", example = "红色")
|
||||
private String valueName;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.sku.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SKU 创建/更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductSkuCreateOrUpdateReqVO extends ProductSkuBaseVO {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.sku.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SKU Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductSkuRespVO extends ProductSkuBaseVO {
|
||||
|
||||
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
### 获得商品 SPU 明细
|
||||
GET {{baseUrl}}/product/spu/get-detail?id=4
|
||||
Authorization: Bearer {{token}}
|
||||
tenant-id: {{adminTenentId}}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
|
||||
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
|
||||
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
|
||||
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
|
||||
import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
|
||||
//import cn.iocoder.yudao.module.promotion.api.coupon.CouponTemplateApi;
|
||||
//import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponTemplateRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
|
||||
|
||||
@Tag(name = "管理后台 - 商品 SPU")
|
||||
@RestController
|
||||
@RequestMapping("/product/spu")
|
||||
@Validated
|
||||
public class ProductSpuController {
|
||||
|
||||
@Resource
|
||||
private ProductSpuService productSpuService;
|
||||
@Resource
|
||||
private ProductSkuService productSkuService;
|
||||
//
|
||||
// @Resource
|
||||
// private CouponTemplateApi couponTemplateApi;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建商品 SPU")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:create')")
|
||||
public CommonResult<Long> createProductSpu(@Valid @RequestBody ProductSpuCreateReqVO createReqVO) {
|
||||
return success(productSpuService.createSpu(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新商品 SPU")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:update')")
|
||||
public CommonResult<Boolean> updateSpu(@Valid @RequestBody ProductSpuUpdateReqVO updateReqVO) {
|
||||
productSpuService.updateSpu(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-status")
|
||||
@Operation(summary = "更新商品 SPU Status")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:update')")
|
||||
public CommonResult<Boolean> updateStatus(@Valid @RequestBody ProductSpuUpdateStatusReqVO updateReqVO) {
|
||||
productSpuService.updateSpuStatus(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除商品 SPU")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:delete')")
|
||||
public CommonResult<Boolean> deleteSpu(@RequestParam("id") Long id) {
|
||||
productSpuService.deleteSpu(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get-detail")
|
||||
@Operation(summary = "获得商品 SPU 明细")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:query')")
|
||||
public CommonResult<ProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) {
|
||||
// 获得商品 SPU
|
||||
ProductSpuDO spu = productSpuService.getSpu(id);
|
||||
if (spu == null) {
|
||||
throw exception(SPU_NOT_EXISTS);
|
||||
}
|
||||
// 查询商品 SKU
|
||||
List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId());
|
||||
// 查询优惠卷
|
||||
// TODO @puhui999:优惠劵的信息,要不交给前端读取?主要是为了避免商品依赖 promotion 模块哈;
|
||||
// List<CouponTemplateRespDTO> couponTemplateList = couponTemplateApi.getCouponTemplateListByIds(
|
||||
// spu.getGiveCouponTemplateIds());
|
||||
return success(ProductSpuConvert.INSTANCE.convertForSpuDetailRespVO(spu, skus));
|
||||
}
|
||||
|
||||
@GetMapping("/list-all-simple")
|
||||
@Operation(summary = "获得商品 SPU 精简列表")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:query')")
|
||||
public CommonResult<List<ProductSpuSimpleRespVO>> getSpuSimpleList() {
|
||||
List<ProductSpuDO> list = productSpuService.getSpuListByStatus(ProductSpuStatusEnum.ENABLE.getStatus());
|
||||
// 降序排序后,返回给前端
|
||||
list.sort(Comparator.comparing(ProductSpuDO::getSort).reversed());
|
||||
return success(ProductSpuConvert.INSTANCE.convertList02(list));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得商品 SPU 详情列表")
|
||||
@Parameter(name = "spuIds", description = "spu 编号列表", required = true, example = "[1,2,3]")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:query')")
|
||||
public CommonResult<List<ProductSpuDetailRespVO>> getSpuList(@RequestParam("spuIds") Collection<Long> spuIds) {
|
||||
return success(ProductSpuConvert.INSTANCE.convertForSpuDetailRespListVO(
|
||||
productSpuService.getSpuList(spuIds), productSkuService.getSkuListBySpuId(spuIds)));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得商品 SPU 分页")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:query')")
|
||||
public CommonResult<PageResult<ProductSpuRespVO>> getSpuPage(@Valid ProductSpuPageReqVO pageVO) {
|
||||
return success(ProductSpuConvert.INSTANCE.convertPage(productSpuService.getSpuPage(pageVO)));
|
||||
}
|
||||
|
||||
@GetMapping("/get-count")
|
||||
@Operation(summary = "获得商品 SPU 分页 tab count")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:query')")
|
||||
public CommonResult<Map<Integer, Long>> getSpuCount() {
|
||||
return success(productSpuService.getTabsCount());
|
||||
}
|
||||
|
||||
@GetMapping("/export")
|
||||
@Operation(summary = "导出商品")
|
||||
@PreAuthorize("@ss.hasPermission('product:spu:export')")
|
||||
@OperateLog(type = EXPORT)
|
||||
public void exportUserList(@Validated ProductSpuExportReqVO reqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
List<ProductSpuDO> spuList = productSpuService.getSpuList(reqVO);
|
||||
// 导出 Excel
|
||||
List<ProductSpuExcelVO> datas = ProductSpuConvert.INSTANCE.convertList03(spuList);
|
||||
ExcelUtils.write(response, "商品列表.xls", "数据", ProductSpuExcelVO.class, datas);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商品 SPU Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Data
|
||||
public class ProductSpuBaseVO {
|
||||
|
||||
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖")
|
||||
@NotEmpty(message = "商品名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "关键字", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑不出汗")
|
||||
@NotEmpty(message = "商品关键字不能为空")
|
||||
private String keyword;
|
||||
|
||||
@Schema(description = "商品简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖简介")
|
||||
@NotEmpty(message = "商品简介不能为空")
|
||||
private String introduction;
|
||||
|
||||
@Schema(description = "商品详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖详情")
|
||||
@NotEmpty(message = "商品详情不能为空")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "商品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "商品分类不能为空")
|
||||
private Long categoryId;
|
||||
|
||||
@Schema(description = "商品品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "商品品牌不能为空")
|
||||
private Long brandId;
|
||||
|
||||
@Schema(description = "商品封面图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
|
||||
@NotEmpty(message = "商品封面图不能为空")
|
||||
private String picUrl;
|
||||
|
||||
@Schema(description = "商品轮播图", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/xx.png, https://www.iocoder.cn/xxx.png]")
|
||||
private List<String> sliderPicUrls;
|
||||
|
||||
@Schema(description = "商品视频", example = "https://www.iocoder.cn/xx.mp4")
|
||||
private String videoUrl;
|
||||
|
||||
@Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "商品单位不能为空")
|
||||
private Integer unit;
|
||||
|
||||
@Schema(description = "排序字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "商品排序字段不能为空")
|
||||
private Integer sort;
|
||||
|
||||
// ========== SKU 相关字段 =========
|
||||
|
||||
@Schema(description = "规格类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "商品规格类型不能为空")
|
||||
private Boolean specType;
|
||||
|
||||
// ========== 物流相关字段 =========
|
||||
|
||||
@Schema(description = "物流配置模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "111")
|
||||
@NotNull(message = "物流配置模板编号不能为空")
|
||||
private Long deliveryTemplateId;
|
||||
|
||||
// ========== 营销相关字段 =========
|
||||
|
||||
@Schema(description = "是否热卖推荐", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "商品推荐不能为空")
|
||||
private Boolean recommendHot;
|
||||
|
||||
@Schema(description = "是否优惠推荐", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "商品推荐不能为空")
|
||||
private Boolean recommendBenefit;
|
||||
|
||||
@Schema(description = "是否精品推荐", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "商品推荐不能为空")
|
||||
private Boolean recommendBest;
|
||||
|
||||
@Schema(description = "是否新品推荐", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "商品推荐不能为空")
|
||||
private Boolean recommendNew;
|
||||
|
||||
@Schema(description = "是否优品推荐", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "商品推荐不能为空")
|
||||
private Boolean recommendGood;
|
||||
|
||||
@Schema(description = "赠送积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "111")
|
||||
@NotNull(message = "商品赠送积分不能为空")
|
||||
private Integer giveIntegral;
|
||||
|
||||
@Schema(description = "赠送的优惠劵数组包含优惠券编号和名称")
|
||||
private List<GiveCouponTemplate> giveCouponTemplates;
|
||||
|
||||
@Schema(description = "分销类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "商品分销类型不能为空")
|
||||
private Boolean subCommissionType;
|
||||
|
||||
@Schema(description = "活动展示顺序", example = "[1, 3, 2, 4, 5]")
|
||||
private List<Integer> activityOrders;
|
||||
|
||||
// ========== 统计相关字段 =========
|
||||
|
||||
@Schema(description = "虚拟销量", example = "66")
|
||||
private Integer virtualSalesCount;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SPU 赠送的优惠卷")
|
||||
@Data
|
||||
public static class GiveCouponTemplate {
|
||||
|
||||
@Schema(description = "模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "优惠劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节送送送")
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SPU 创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductSpuCreateReqVO extends ProductSpuBaseVO {
|
||||
|
||||
// ========== SKU 相关字段 =========
|
||||
|
||||
@Schema(description = "SKU 数组")
|
||||
@Valid
|
||||
private List<ProductSkuCreateOrUpdateReqVO> skus;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SPU 详细 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductSpuDetailRespVO extends ProductSpuBaseVO {
|
||||
|
||||
@Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1212")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
|
||||
private Integer salesCount;
|
||||
|
||||
@Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20000")
|
||||
private Integer browseCount;
|
||||
|
||||
@Schema(description = "商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
// ========== SKU 相关字段 =========
|
||||
|
||||
@Schema(description = "SKU 数组")
|
||||
private List<ProductSkuRespVO> skus;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||
import cn.iocoder.yudao.module.product.enums.DictTypeConstants;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 商品 Spu Excel 导出 VO TODO 暂定
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Data
|
||||
public class ProductSpuExcelVO {
|
||||
|
||||
@ExcelProperty("商品编号")
|
||||
private Long id;
|
||||
|
||||
@ExcelProperty("商品名称")
|
||||
private String name;
|
||||
|
||||
@ExcelProperty("关键字")
|
||||
private String keyword;
|
||||
|
||||
@ExcelProperty("商品简介")
|
||||
private String introduction;
|
||||
|
||||
@ExcelProperty("商品详情")
|
||||
private String description;
|
||||
|
||||
@ExcelProperty("条形码")
|
||||
private String barCode;
|
||||
|
||||
@ExcelProperty("商品分类编号")
|
||||
private Long categoryId;
|
||||
|
||||
@ExcelProperty("商品品牌编号")
|
||||
private Long brandId;
|
||||
|
||||
@ExcelProperty("商品封面图")
|
||||
private String picUrl;
|
||||
|
||||
@ExcelProperty("商品视频")
|
||||
private String videoUrl;
|
||||
|
||||
@ExcelProperty(value = "商品单位", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.PRODUCT_UNIT)
|
||||
private Integer unit;
|
||||
|
||||
@ExcelProperty("排序字段")
|
||||
private Integer sort;
|
||||
|
||||
@ExcelProperty(value = "商品状态", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.PRODUCT_SPU_STATUS)
|
||||
private Integer status;
|
||||
|
||||
@ExcelProperty("规格类型")
|
||||
private Boolean specType;
|
||||
|
||||
@ExcelProperty("商品价格")
|
||||
private Integer price;
|
||||
|
||||
@ExcelProperty("市场价")
|
||||
private Integer marketPrice;
|
||||
|
||||
@ExcelProperty("成本价")
|
||||
private Integer costPrice;
|
||||
|
||||
@ExcelProperty("库存")
|
||||
private Integer stock;
|
||||
|
||||
@ExcelProperty("物流配置模板编号")
|
||||
private Long deliveryTemplateId;
|
||||
|
||||
@ExcelProperty("是否热卖推荐")
|
||||
private Boolean recommendHot;
|
||||
|
||||
@ExcelProperty("是否优惠推荐")
|
||||
private Boolean recommendBenefit;
|
||||
|
||||
@ExcelProperty("是否精品推荐")
|
||||
private Boolean recommendBest;
|
||||
|
||||
@ExcelProperty("是否新品推荐")
|
||||
private Boolean recommendNew;
|
||||
|
||||
@ExcelProperty("是否优品推荐")
|
||||
private Boolean recommendGood;
|
||||
|
||||
@ExcelProperty("赠送积分")
|
||||
private Integer giveIntegral;
|
||||
|
||||
@ExcelProperty("分销类型")
|
||||
private Boolean subCommissionType;
|
||||
|
||||
@ExcelProperty("商品销量")
|
||||
private Integer salesCount;
|
||||
|
||||
@ExcelProperty("虚拟销量")
|
||||
private Integer virtualSalesCount;
|
||||
|
||||
@ExcelProperty("商品点击量")
|
||||
private Integer browseCount;
|
||||
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SPU 导出 Request VO,参数和 ProductSpuPageReqVO 是一致的")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ProductSpuExportReqVO {
|
||||
|
||||
@Schema(description = "商品名称", example = "清凉小短袖")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "前端请求的tab类型", example = "1")
|
||||
private Integer tabType;
|
||||
|
||||
@Schema(description = "商品分类编号", example = "100")
|
||||
private Long categoryId;
|
||||
|
||||
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SPU 分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductSpuPageReqVO extends PageParam {
|
||||
|
||||
/**
|
||||
* 出售中商品
|
||||
*/
|
||||
public static final Integer FOR_SALE = 0;
|
||||
|
||||
/**
|
||||
* 仓库中商品
|
||||
*/
|
||||
public static final Integer IN_WAREHOUSE = 1;
|
||||
|
||||
/**
|
||||
* 已售空商品
|
||||
*/
|
||||
public static final Integer SOLD_OUT = 2;
|
||||
|
||||
/**
|
||||
* 警戒库存
|
||||
*/
|
||||
public static final Integer ALERT_STOCK = 3;
|
||||
|
||||
/**
|
||||
* 商品回收站
|
||||
*/
|
||||
public static final Integer RECYCLE_BIN = 4;
|
||||
|
||||
@Schema(description = "商品名称", example = "清凉小短袖")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "前端请求的tab类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer tabType;
|
||||
|
||||
@Schema(description = "商品分类编号", example = "1")
|
||||
private Long categoryId;
|
||||
|
||||
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SPU Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductSpuRespVO extends ProductSpuBaseVO {
|
||||
|
||||
@Schema(description = "spuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "111")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "商品价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000")
|
||||
private Integer salesCount;
|
||||
|
||||
@Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "199")
|
||||
private Integer marketPrice;
|
||||
|
||||
@Schema(description = "成本价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "19")
|
||||
private Integer costPrice;
|
||||
|
||||
@Schema(description = "商品库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000")
|
||||
private Integer stock;
|
||||
|
||||
@Schema(description = "商品创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-05-24 00:00:00")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "888")
|
||||
private Integer browseCount;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SPU 精简 Response VO")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class ProductSpuSimpleRespVO {
|
||||
|
||||
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "213")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "商品价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "商品市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "199")
|
||||
private Integer marketPrice;
|
||||
|
||||
@Schema(description = "商品成本价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "19")
|
||||
private Integer costPrice;
|
||||
|
||||
@Schema(description = "商品库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000")
|
||||
private Integer stock;
|
||||
|
||||
// ========== 统计相关字段 =========
|
||||
|
||||
@Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
private Integer salesCount;
|
||||
|
||||
@Schema(description = "商品虚拟销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20000")
|
||||
private Integer virtualSalesCount;
|
||||
|
||||
@Schema(description = "商品浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000")
|
||||
private Integer browseCount;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 商品 SPU 更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ProductSpuUpdateReqVO extends ProductSpuBaseVO {
|
||||
|
||||
@Schema(description = "商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "商品编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999")
|
||||
private Integer salesCount;
|
||||
|
||||
@Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999")
|
||||
private Integer browseCount;
|
||||
|
||||
@Schema(description = "商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@InEnum(ProductSpuStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
// ========== SKU 相关字段 =========
|
||||
|
||||
@Schema(description = "SKU 数组")
|
||||
@Valid
|
||||
private List<ProductSkuCreateOrUpdateReqVO> skus;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue