Compare commits

...

2 Commits

Author SHA1 Message Date
YuanFeng 3514966d47 Merge branch 'dev' of https://git.yfgame.vip/r/hangtag into dev
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2024-10-18 10:09:50 +08:00
YuanFeng 75aad6a93d 优化 下单页面,新增客户地址管理,新增查询条件构建工具类 2024-10-18 10:08:43 +08:00
88 changed files with 4347 additions and 605 deletions

View File

@ -367,6 +367,26 @@ public class FuncUtil extends StringUtils {
public static List<String> toStrList(String str) {
return Arrays.asList(toStrArray(str));
}
public static List<String> toStrListByArray(Object[] objects) {
if(isEmpty(objects)){
return null;
}
List<String> list = new ArrayList<>();
for (Object o : objects) {
list.add(toStr(o,null));
}
return list;
}
public static List<String> toStrListByCollection(Collection<Object> objects) {
if(isEmpty(objects)){
return null;
}
List<String> list = new ArrayList<>();
for (Object o : objects) {
list.add(toStr(o,null));
}
return list;
}
public static List<String> toStrList(String split, String str) {
return Arrays.asList(toStrArray(split, str));

View File

@ -0,0 +1,118 @@
package cn.hangtag.framework.common.util;
import cn.hutool.core.bean.BeanUtil;
import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Function;
/**
* 安全使用值
*
* @author YuanFeng
* @date 2024/5/16
*/
public class SafeUseUtil extends BeanUtil {
// 缓存结果的 Map
private static final Map<Object, Object> cache = new HashMap<>();
private static final int CACHE_LIMIT = 1000; // 设置缓存大小限制
/**
* Optional 的简单版
* 安全使用值 对象中能取值则使用对象的值否则返回默认值
*
* @param obj obj
* @param extractor 提取器
* @return {@link R }
*/
public static <T, R> R use(T obj, Function<T, R> extractor) {
return use(obj, extractor, null);
}
/**
* 安全使用值 对象中能取值则使用对象的值否则返回默认值
*
* @param obj obj
* @param extractor 提取器
* @param defaultValue 默认值
* @return {@link R }
*/
public static <T, R> R use(T obj, Function<T, R> extractor, R defaultValue) {
if (obj == null) return defaultValue;
// 使用简单键例如 obj 的哈希值
Object key = generateCacheKey(obj, extractor,defaultValue);
if (cache.containsKey(key)) {
return (R) cache.get(key); // 从缓存中获取结果
}
R result = defaultValue;
try {
result = extractor.apply(obj);
} catch (Exception e) {
e.printStackTrace();
}
putCacheKey(key, result);
return result;
}
private static <R> void putCacheKey(Object key, R result) {
if (cache.size() >= CACHE_LIMIT) {
// 进行简单的缓存清理
cache.clear();
}
cache.put(key, result); // 缓存结果
}
/**
* 安全使用值 对象不为空 能取值并且不为空时 使用对象的中值
*
* @param obj obj
* @param extractor 提取器
* @param defaultValue 默认值
* @return {@link R }
*/
public static <T, R> R useNotEmpty(T obj, Function<T, R> extractor, R defaultValue) {
if (isEmpty(obj)) return defaultValue;
R result = use(obj, extractor, defaultValue);
if (!isEmpty(result)) {
return result;
}
return defaultValue; // 如果结果为空返回默认值
}
public static boolean isEmpty(final Object object) {
if (object == null) return true;
if (object instanceof Collection) {
return ((Collection<?>) object).isEmpty();
} else if (object instanceof Map) {
return ((Map<?,?>) object).isEmpty();
} else if (object instanceof CharSequence) {
return ((CharSequence) object).length() == 0;
} else if (object.getClass().isArray()) {
return Array.getLength(object) == 0;
}
return false;
}
// 生成缓存键
private static Object generateCacheKey(Object obj, Function<?, ?> extractor,Object val) {
return Objects.hash(obj, extractor, val);
}
// public static void main(String[] args) {
// User2 user2 = new User2();
//
// user2.setName("yuanfeng");
// Dept2 dept3 = new Dept2();
// dept3.setName("parent");
// Dept2 dept2 = new Dept2();
// dept2.setParent(dept3);
// dept2.setName("dept");
// user2.setDept(dept2);
// String name = use(use(use(user2, User2::getDept), Dept2::getParent),Dept2::getName);
//
// System.out.println(name);
// }
}

View File

@ -0,0 +1,23 @@
package cn.hangtag.framework.mybatis.build;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import lombok.Data;
import java.io.Serializable;
@Data
public class FilterItem implements Serializable {
/**
* 类型 = > >= < <= != in notIn like likeLef likeRight keyword
* {@link QueryFilterTypeEnum}
*/
private String type = QueryFilterTypeEnum.EQ.getValue();
/**
* 条件为 或关系
*/
private boolean or;
}

View File

@ -0,0 +1,85 @@
package cn.hangtag.framework.mybatis.build;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import lombok.Data;
import java.io.Serializable;
import java.util.*;
/**
* 过滤条件配置
*
* @author YuanFeng
*/
@Data
public class FilterItemConfig implements Serializable {
// 排序字段 多个使用逗号分隔 name asc,createTime desc
private String orderBy = ""; // 排序规则 name,createTime desc 这个默认使用 asc
private String groupBy = ""; // 分组 name,createTime desc 这个默认使用 asc
private Set<String> ignoreFields = new HashSet<>(); // 忽略字段 多个使用逗号分隔 : userName,age
private String dateFields = ""; //声明哪些是 日期字段 避免搜索错误 多个使用逗号分隔 createTime,updateTime
private String defaultFilterType = QueryFilterTypeEnum.EQ.getValue();
// 关键字搜索值多个使用空格间隔 查询条件 where (name like %% or name or like %%) or (code like %% or code or like %%)
private String keywordSearch; // 关键字搜索值多个使用空格间隔
private String keywordFields; // 关键字段多个使用逗号 name,code
private String easyOption = ""; // 简单配置 多个使用逗号号间隔; name@like,age@> 条件 where like '%?%' and age > ?
private Map<String, FilterItem> options; // 条件过滤配置
public Set<String> getIgnoreFieldsKeys() {
if(ignoreFields == null){
ignoreFields = new HashSet<>();
}
return ignoreFields;
}
public void setIgnoreFields(String config) {
if(QueryConfigUtils.isNotEmpty(config)){
List<String> strList = QueryConfigUtils.toStrList(config);
getIgnoreFieldsKeys().addAll(strList);
}
}
public String getIgnoreFields(){
if(getIgnoreFieldsKeys().isEmpty()){
return "";
}
return String.join(QueryConfigUtils.SPLIT_CHAR, getIgnoreFieldsKeys());
}
public Map<String, FilterItem> getOptions() {
if(options == null){
options = new HashMap<>();
}
return options;
}
// @条件(QueryFilterTypeEnum) 多个使用逗号号间隔; name@like,age@> 条件 where like '%?%' and age > ?
public void setEasyOption(String options){
if (QueryConfigUtils.isNotEmpty(options)) {
String[] split = options.split(QueryConfigUtils.SPLIT_CHAR);
for (String s : split) {
if(QueryConfigUtils.isNotEmpty(s.trim())){
String[] split1 = s.trim().split(QueryConfigUtils.SPLIT_CONDITIONS);
FilterItem item = new FilterItem();
// 简单模式设置条件为都为 and 模式
item.setOr(false);
item.setType(getDefaultFilterType());
if(split1.length == 2){
// 获取条件类型
QueryFilterTypeEnum byValue = QueryFilterTypeEnum.getByValue(split1[1]);
if(byValue != null){
item.setType(byValue.getValue());
}
}
if(QueryConfigUtils.isEmpty(getOptions().get(split1[0].trim()))){
//没有配置时候才将 简单条件添加到配置中
getOptions().put(split1[0].trim(), item);
}
}
}
}
}
}

View File

@ -0,0 +1,105 @@
package cn.hangtag.framework.mybatis.build;
import java.util.*;
/**
* 高性能有序Map
*
* @author YuanFeng
* @date 2020/9/14
*/
public class HighPerformanceOrderedMap<K, V> extends AbstractMap<K, V> {
private final Map<K, V> map; // 存储数据的 HashMap
private final List<K> order; // 维护插入顺序的 List
// 构造函数
public HighPerformanceOrderedMap() {
this.map = new HashMap<>();
this.order = new ArrayList<>();
}
@Override
public Set<Entry<K, V>> entrySet() {
Set<Entry<K, V>> entrySet = new LinkedHashSet<>();
for (K key : order) {
entrySet.add(new SimpleEntry<>(key, map.get(key)));
}
return entrySet;
}
/**
* 移除第一
*
* @return {@link K }
*/
public K removeFirst(){
if(!isEmpty()){
K k = this.order.get(0);
remove(k);
return k;
}
return null;
}
public List<K> keyList(){
return order;
}
@Override
public Set<K> keySet(){
return new LinkedHashSet<>(order);
}
@Override
public List<V> values(){
return new ArrayList<>(map.values());
}
@Override
public V put(K key, V value) {
if (!map.containsKey(key)) {
order.add(key); // 只在新插入时添加顺序
}
return map.put(key, value);
}
@Override
public V get(Object key) {
return map.get(key);
}
@Override
public V remove(Object key) {
if (map.containsKey(key)) {
order.remove(key); // 移除顺序中的键
}
return map.remove(key);
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return map.containsValue(value);
}
@Override
public int size() {
return map.size();
}
@Override
public void clear() {
map.clear();
order.clear();
}
// 打印所有键值对
public void printEntries() {
for (K key : order) {
System.out.println(key + ": " + map.get(key));
}
}
}

View File

@ -0,0 +1,446 @@
package cn.hangtag.framework.mybatis.build;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.lang.reflect.Field;
import java.util.*;
/**
* mybatisPlus 查询条件构建工具
*
* @author YuanFeng
* @date 2023/5/14
*/
public class MybatisPlusUtil {
public static String[] defaultIgnoreFilters = {"pageNo", "pageSize", "PAGE_NO", "PAGE_SIZE", "PAGE_SIZE_NONE"};
/**
* 弱类型 生成非空值查询 指定转成的实体类型
*
* @param entity 实体
* @param clazz clazz 返回QueryWrapper泛型的类型
* @param ignoreField ignore字段
* @return {@link QueryWrapper }<{@link T }>
*/
public static <T> QueryWrapper<T> buildQueryFor(Object entity,
Class<T> clazz,
String... ignoreField) {
return buildQueryFor(null, entity, QueryFilterTypeEnum.EQ, clazz, ignoreField);
}
/**
* 弱类型 生成非空值查询 指定转成的实体类型
*
* @param conditions 条件 @条件(QueryFilterTypeEnum) 多个使用逗号号间隔; name@like,age@> 条件 where like '%?%' and age > ?
* @param entity 实体
* @param typeEnum 类型列举 没有指定过滤类型时候的默认条件类型
* @param clazz clazz 返回QueryWrapper泛型的类型
* @param ignoreField ignore字段
* @return {@link QueryWrapper }<{@link T }>
*/
public static <T> QueryWrapper<T> buildQueryFor(String conditions,
Object entity,
QueryFilterTypeEnum typeEnum,
Class<T> clazz,
String... ignoreField) {
QueryFilterInfo queryFilterInfo = toFilter(conditions, entity, typeEnum, ignoreField);
return parseQuery(queryFilterInfo, true, ignoreField);
}
/**
* 弱类型 实体转成查询条件
* 实体可能是vo 但是查询 Db实体的时候使用
*
* @param conditions 条件 @条件(QueryFilterTypeEnum) 多个使用逗号号间隔; name@like,age@> 条件 where like '%?%' and age > ?
* @param entity 实体
* @param clazz clazz 返回QueryWrapper泛型的类型
* @param ignoreField ignore字段
* @return {@link QueryWrapper }<{@link T }>
*/
public static <T> QueryWrapper<T> buildQueryFor(String conditions,
Object entity,
Class<T> clazz,
String... ignoreField) {
return buildQueryFor(conditions, entity, QueryFilterTypeEnum.EQ, clazz, ignoreField);
}
/**
* 弱类型 实体转成查询条件
* 实体可能是vo 但是查询 Db 实体的时候使用
*
* @param entity 实体
* @param typeEnum 类型列举 没有指定过滤类型时候的默认条件类型
* @param clazz clazz 返回QueryWrapper泛型的类型
* @param ignoreField ignore字段
* @return {@link QueryWrapper }<{@link T }>
*/
public static <T> QueryWrapper<T> buildQueryFor(Object entity,
QueryFilterTypeEnum typeEnum,
Class<T> clazz,
String... ignoreField) {
return buildQueryFor(null, entity, typeEnum, clazz, ignoreField);
}
/**
* 实体转成查询条件
*
* @param entity 实体
* @param ignoreField ignore字段
* @return {@link QueryWrapper }<{@link T }>
*/
public static <T> QueryWrapper<T> buildQuery(T entity, String... ignoreField) {
return buildQuery(null, entity, QueryFilterTypeEnum.EQ, ignoreField);
}
/**
* 实体转成查询条件
*
* @param conditions 条件
* @param entity 实体
* @param ignoreField ignore字段
* @return {@link QueryWrapper }<{@link T }>
*/
public static <T> QueryWrapper<T> buildQuery(String conditions, T entity, String... ignoreField) {
return buildQuery(conditions, entity, QueryFilterTypeEnum.EQ, ignoreField);
}
/**
* 生成非空值查询
*
* @param entity 实体
* @param typeEnum 类型列举 没有指定过滤类型时候的默认条件类型
* @param ignoreField ignore字段
* @return {@link QueryWrapper }<{@link T }>
*/
public static <T> QueryWrapper<T> buildQuery(T entity, QueryFilterTypeEnum typeEnum, String... ignoreField) {
return buildQuery(null, entity, typeEnum, ignoreField);
}
/**
* 生成非空值查询 根据泛型返回类型
*
* @param conditions 简单条件 @条件(QueryFilterTypeEnum) 多个使用逗号号间隔; name@like,age@> 条件 where like '%?%' and age > ?
* @param entity 实体
* @param typeEnum 类型列举 没有指定过滤类型时候的默认条件类型
* @param ignoreField ignore字段
* @return {@link QueryWrapper }<{@link T }>
*/
public static <T> QueryWrapper<T> buildQuery(String conditions, T entity, QueryFilterTypeEnum typeEnum, String... ignoreField) {
QueryFilterInfo<T> queryFilterInfo = toFilter(conditions, entity, typeEnum, ignoreField);
QueryWrapper<T> queryWrapper = parseQuery(queryFilterInfo, true, ignoreField);
return queryWrapper;
}
public static <E> QueryFilterInfo<E> toFilter(E entity, QueryFilterTypeEnum typeEnum, String... ignoreField) {
return toFilter(null, entity, typeEnum, ignoreField);
}
/**
* 实体转成 过滤信息对象
*
* @param conditions 条件 name@like,age@>,code@= 简单配置 字段名称@条件
* @param entity 实体
* @param typeEnum 类型列举 没有指定过滤类型时候的默认条件类型
* @param ignoreField ignore字段
* @return {@link QueryFilterInfo }<{@link E }>
*/
public static <E> QueryFilterInfo<E> toFilter(String conditions, E entity, QueryFilterTypeEnum typeEnum, String... ignoreField) {
Set<String> ignoreList = new HashSet<>();
if (QueryConfigUtils.isNotEmpty(ignoreField)) {
for (String ignoreColumn : ignoreField) {
// 忽略字段 类中的字段转成下划线命名
ignoreList.add(QueryConfigUtils.humpToLine(ignoreColumn));
}
}
QueryFilterInfo<E> queryFilterInfo = new QueryFilterInfo<E>();
queryFilterInfo.easyOptions(conditions);
queryFilterInfo.setDefaultFilterType(typeEnum);
queryFilterInfo.appendIgnoreFields(ignoreList);
handlerEntityField(entity, queryFilterInfo, QueryConfigUtils.getDeclaredFields(entity.getClass()));
// 处理父类
Class<?> superclass = entity.getClass().getSuperclass();
while (superclass != null) {
handlerEntityField(entity, queryFilterInfo, QueryConfigUtils.getDeclaredFields(superclass));
superclass = superclass.getSuperclass();
}
return queryFilterInfo;
}
/**
* 处理实体字段 字段转成 查询条件
*
* @param entity 实体
* @param queryFilterInfo 查询过滤器信息
* @param declaredFields 声明字段
*/
private static <T> void handlerEntityField(T entity, QueryFilterInfo<T> queryFilterInfo, Field[] declaredFields) {
// 字段过滤条件类型
Map<String, QueryFilterTypeEnum> filterMap = new HashMap<>();
// 取出过滤条件类型
Map<String, FilterItem> options = queryFilterInfo.getOptions();
// 或者关系条件的字段集合
Set<String> orKeys = new HashSet<>();
if (QueryConfigUtils.isNotEmpty(options)) {
Set<String> keySet = options.keySet();
for (String s : keySet) {
FilterItem item = options.get(s);
String type = item.getType();
QueryFilterTypeEnum queryFilterTypeEnum = QueryFilterTypeEnum.getByValue(type);
// 类中的字段转成下划线命名
String field = QueryConfigUtils.humpToLine(s);
if (queryFilterTypeEnum != null) {
filterMap.put(field, queryFilterTypeEnum);
} else {
filterMap.put(field, QueryFilterTypeEnum.getByValue(queryFilterInfo.getDefaultFilterType()));
}
if (item.isOr()) {
orKeys.add(field);
}
}
}
Set<String> ignoreList = queryFilterInfo.getIgnoreFieldsKeys();
for (Field field : declaredFields) {
field.setAccessible(true);
try {
//序列化 字段 属性为空不查询
if (QueryConfigUtils.shouldSkipField(field, ignoreList)) {
queryFilterInfo.appendIgnoreFields(ignoreList);
continue;
}
String column = QueryConfigUtils.humpToLine(field.getName());
//主键 注解TableId
TableId tableId = field.getAnnotation(TableId.class);
if (tableId != null && field.get(entity) != null) {
//主键
if (QueryConfigUtils.isNotEmpty(tableId.value())) {
column = tableId.value();
}
} else {
//数据库中字段名和实体类属性不一致 注解TableField
TableField tableField = field.getAnnotation(TableField.class);
if (tableField != null && !tableField.exist()) {
// @TableField(exist = false) 不是表中内容 不形成查询条件
if (QueryConfigUtils.isNotEmpty(tableField.value())) {
column = tableField.value();
}
ignoreList.add(column);
queryFilterInfo.appendIgnoreFields(ignoreList);
continue;
}
}
// 属性不为null 值在过滤条件中
if (field.get(entity) != null) {
Object inputVal = field.get(entity);
Class<?> type = field.getType();
Object val;
// 是否有指定的过滤条件
QueryFilterTypeEnum filterTypeEnum = filterMap.get(column);
if (filterTypeEnum == null) {
filterTypeEnum = QueryFilterTypeEnum.getByValue(queryFilterInfo.getDefaultFilterType());
}
if (QueryConfigUtils.isArr(inputVal)) {
val = QueryConfigUtils.objToArray(inputVal, Object.class);
} else if (QueryConfigUtils.isList(inputVal)) {
val = QueryConfigUtils.objToArray(inputVal, Object.class);
} else {
val = TypeConverter.convertValue(inputVal, type);
if (val == null) {
// 没有转换成功
val = inputVal.toString();
}
}
queryFilterInfo.build(column, val, filterTypeEnum, orKeys.contains(column));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
/**
* 解析为查询条件
*
* @param queryFilterInfo 查询过滤器信息
* @param isToLine 是否转成 下划线命名
* @param clazz clazz 返回QueryWrapper泛型的类型
* @param ignoreField 忽略字段
* @return {@link QueryWrapper }<{@link T }>
*/
public static <T> QueryWrapper<T> parseQuery(QueryFilterInfo queryFilterInfo, boolean isToLine, Class<T> clazz, String... ignoreField) {
QueryWrapper<T> queryWrapper = parseQuery(queryFilterInfo, isToLine, ignoreField);
return queryWrapper;
}
/**
* 解析为查询条件
*
* @param filterInfo 查询过滤器信息
* @param isToLine 是否转成 下划线命名
* @param ignoreField 忽略字段
* @return {@link QueryWrapper }<{@link T }>
*/
public static <T> QueryWrapper<T> parseQuery(QueryFilterInfo<T> filterInfo, boolean isToLine, String... ignoreField) {
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
queryWrapper.and((q) -> {
q.eq("1", 1);
});
String keywordFields = filterInfo.getConfig().getKeywordFields();
String keywordSearch = filterInfo.getConfig().getKeywordSearch();
if (QueryConfigUtils.isEmpty(filterInfo)) {
return queryWrapper;
}
Map<String, Object> filter = filterInfo.getFilter();
Map<String, FilterItem> options = filterInfo.getOptions();
String str = filterInfo.getConfig().getOrderBy();
Set<String> ignoreFieldsKeys = filterInfo.getIgnoreFieldsKeys();
if(QueryConfigUtils.isNotEmpty(ignoreField)){
ignoreFieldsKeys.addAll(Arrays.asList(ignoreField));
}
Set<String> ignoreKeys = new HashSet<>();
for (String ignoreFieldsKey : ignoreFieldsKeys) {
ignoreKeys.add(isToLine ? QueryConfigUtils.humpToLine(ignoreFieldsKey) : ignoreFieldsKey);
}
if (QueryConfigUtils.isNotEmpty(str)) {
String[] split = str.split(QueryConfigUtils.SPLIT_CHAR);
for (String s1 : split) {
String[] s2 = s1.split(" ");
String orderField = s2[0];
if (isToLine) {
orderField = QueryConfigUtils.humpToLine(orderField);
}
// 说明字段不存在 或者不参与排序
if (ignoreKeys.contains(orderField)) {
continue;
}
if ("desc".equalsIgnoreCase(QueryConfigUtils.toStr(s2[1],""))) {
queryWrapper.orderByDesc(orderField);
} else {
queryWrapper.orderByAsc(orderField);
}
}
}
// 处理关键字查询
if (QueryConfigUtils.isNotEmpty(keywordSearch) && QueryConfigUtils.isNotEmpty(keywordFields)) {
String finalKeywordSearch = keywordSearch.trim();
if (QueryConfigUtils.isNotEmpty(finalKeywordSearch)) {
String[] split = keywordFields.split(QueryConfigUtils.SPLIT_CHAR);
queryWrapper.and((c) -> {
for (String s : split) {
s = isToLine ? QueryConfigUtils.humpToLine(s) : s;
// 说明字段不存在 或者不参与搜索
if (ignoreKeys.contains(s)) {
continue;
}
// name like '%%' or name like '%%' or name like '%%'
// 多个关键字空格间隔
String[] keyList = finalKeywordSearch.split(" ");
for (String key : keyList) {
c.or();
// 关键字过滤 key
c.like(s, key.trim());
}
c.or();
}
});
}
}
// 条件查询
if (QueryConfigUtils.isNotEmpty(filter)) {
Set<String> keySet = options.keySet();
Map<String, FilterItem> filterMap = new HashMap<>();
for (String s : keySet) {
// 处理驼峰字段
filterMap.put(isToLine ? QueryConfigUtils.humpToLine(s) : s, options.get(s));
}
// 日期字段
Set<String> dateSet = new HashSet<>();
String dateFields = filterInfo.getConfig().getDateFields();
if (QueryConfigUtils.isNotEmpty(dateFields)) {
String[] split = dateFields.split(QueryConfigUtils.SPLIT_CHAR);
for (String s : split) {
if (QueryConfigUtils.isNotEmpty(s.trim())) {
dateSet.add(isToLine ? QueryConfigUtils.humpToLine(s.trim()) : s.trim());
}
}
}
// 遍历过滤条件
Set<String> fieldKey = filter.keySet();
for (String objKey : fieldKey) {
// 取出过滤的值
Object value = filter.get(objKey);
if (QueryConfigUtils.skipData(value)) {
// 跳过数据
continue;
}
String field = isToLine ? QueryConfigUtils.humpToLine(objKey) : objKey;
// 说明字段不存在 或者不参与条件查询
if (ignoreKeys.contains(field)) {
continue;
}
FilterItem item = filterMap.get(field);
if (item == null) {
//找不到指定的过滤类型 默认过滤类型
item = new FilterItem();
// 默认过滤类型
item.setType(filterInfo.getDefaultFilterType());
// 判断是否是数组
if (QueryConfigUtils.isArr(value) || QueryConfigUtils.isList(value)) {
item.setType(QueryFilterTypeEnum.BETWEEN.getValue());
}
item.setOr(false);
}
// 判断是否是or
if (item.isOr()) {
queryWrapper.or();
}
QueryFilterTypeEnum byValue = QueryFilterTypeEnum.getByValue(item.getType());
if(byValue == null){
byValue = QueryFilterTypeEnum.EQ;
}
// 条件处理器
queryWrapper = QueryConfigUtils.whereHandler(queryWrapper, byValue, dateSet, field, value);
}
}
// 分组
List<String> strList = QueryConfigUtils.toStrList(filterInfo.getConfig().getGroupBy());
if (QueryConfigUtils.isNotEmpty(strList)) {
List<String> strSet = new ArrayList<>();
for (String s : strList) {
String s1 = isToLine ? QueryConfigUtils.humpToLine(s) : s;
if (ignoreKeys.contains(s1)) {
continue;
}
strSet.add(s1);
}
if (QueryConfigUtils.isNotEmpty(strSet)) {
queryWrapper.groupBy(strSet);
}
}
return queryWrapper;
}
}

View File

@ -0,0 +1,474 @@
package cn.hangtag.framework.mybatis.build;
import cn.hangtag.framework.mybatis.build.enums.DbTypeEnum;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.handler.*;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class QueryConfigUtils {
private static final Map<String, Function<Object, Boolean>> SKIP_HANDLER = new HashMap<>();
public static int MAX_LINE_CACHE = 100000;
/**
* 分隔符
*/
public static final String SPLIT_CHAR = ",";
/**
* 分裂条件
*/
public static final String SPLIT_CONDITIONS = "@";
private static final Pattern HUMP_PATTERN = Pattern.compile("[A-Z]");
private static DbTypeEnum currentType = DbTypeEnum.MYSQL;
public static DbTypeEnum getDbType() {
return currentType;
}
public static void setDbType(String dbType) {
currentType = DbTypeEnum.getDbType(dbType);
}
private static final ThreadLocal<String> LOCAL_HANDLER = new ThreadLocal<>();
/**
* 注册一个跳过数据处理方法名称为key
*
* @param name 名称
* @param handler 处理程序
*/
public static void registerSkipHandler(String name, Function<Object, Boolean> handler) {
SKIP_HANDLER.put(name, handler);
}
static {
// 默认
registerSkipHandler("null", (obj) -> {
return obj == null || obj.equals("null");
});
resetWrapperHandler();
}
public static void resetWrapperHandler(){
registerWrapperHandler(new Between2Handler<>());
registerWrapperHandler(new BetweenHandler<>());
registerWrapperHandler(new EqHandler<>());
registerWrapperHandler(new GeHandler<>());
registerWrapperHandler(new InHandler<>());
registerWrapperHandler(new InSetHandler<>());
registerWrapperHandler(new KeywordHandler<>());
registerWrapperHandler(new LeHandler<>());
registerWrapperHandler(new LikeHandler<>());
registerWrapperHandler(new LikeLeftHandler<>());
registerWrapperHandler(new LikeRightHandler<>());
registerWrapperHandler(new LtHandler<>());
registerWrapperHandler(new NeHandler<>());
registerWrapperHandler(new NotInHandler<>());
registerWrapperHandler(new NotLikeHandler<>());
}
public static void registerWrapperHandler(WhereWrapper<?> whereWrapper) {
WrapperHandler.registerWrapperHandler(whereWrapper);
}
/**
* 使用跳过逻辑处理方法名称
*
* @param name 名称
*/
public static void useSkipHandler(String name) {
// 线程绑定
LOCAL_HANDLER.set(name);
}
private static Function<Object, Boolean> getSkipHandler(String name) {
Function<Object, Boolean> function = null;
if (name != null) {
function = SKIP_HANDLER.get(name);
}
if (function == null) {
// 使用默认
return QueryConfigUtils::isEmpty;
}
return function;
}
/**
* 获取 sql 字段为 id1,id2,id3 , 条件如 id1
* 使用 方法 queryWrapper.apply(MybatisPlusUtil.getIdsToApply(user_ids"),id)
*
* @param columnName 列名
* @return {@link String }
*/
public static String getIdsToApply(String columnName) {
return getIdsToApply(getDbType(), columnName);
}
/**
* 获取身份证申请
*
* @param dbType db类型
* @param columnName 列名
* @return {@link String }
*/
public static String getIdsToApply(DbTypeEnum dbType, String columnName) {
switch (dbType) {
case MYSQL:
return "FIND_IN_SET ({0}, " + columnName + ")";
case POSTGRE_SQL:
return "'{0}' = ANY (string_to_array(" + columnName + ", ','))";
default:
return "FIND_IN_SET ({0}, " + columnName + ")";
}
}
/**
* 转成下线缓存
*/
private static final HighPerformanceOrderedMap<String, String> TO_LINE_CACHE = new HighPerformanceOrderedMap<>();
/**
* 驼峰转下划线
*
* @param str str
* @return {@link String}
*/
public static String humpToLine(String str) {
if (isNotEmpty(str)) {
String s = TO_LINE_CACHE.get(str);
if (isNotEmpty(s)) {
return s;
}
str = str.substring(0, 1).toLowerCase() + str.substring(1);
Matcher matcher = HUMP_PATTERN.matcher(str);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
}
matcher.appendTail(sb);
String string = sb.toString();
TO_LINE_CACHE.put(str, string);
if (TO_LINE_CACHE.size() > MAX_LINE_CACHE) {
TO_LINE_CACHE.removeFirst();
}
return string;
}
return str;
}
/**
* 转为骆驼
*
* @param s S
* @return {@link String }
*/
public static String toCamelCase(String s) {
if (isEmpty(s) || !s.contains("_")) {
return s;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '_') {
upperCase = true;
} else if (upperCase) {
sb.append(Character.toUpperCase(c));
upperCase = false;
} else {
sb.append(c);
}
}
return sb.toString();
}
public static boolean shouldSkipField(Field field, Set<String> ignoreList) {
if ("serialVersionUID".equals(field.getName())) return true;
if (ignoreList.contains(humpToLine(field.getName()))) return true;
// 过滤字段 只写字段
if (field.getAnnotation(JsonProperty.class) != null
&& field.getAnnotation(JsonProperty.class).access() == JsonProperty.Access.WRITE_ONLY) {
ignoreList.add(humpToLine(field.getName()));
return true;
}
// 在序列化和反序列化时忽略的属性
if (field.getAnnotation(JsonIgnore.class) != null) {
ignoreList.add(humpToLine(field.getName()));
return true;
}
return false;
}
private static final Map<Class<?>, Field[]> fieldCache = new HashMap<>();
public static Field[] getDeclaredFields(Class<?> clazz) {
return fieldCache.computeIfAbsent(clazz, Class::getDeclaredFields);
}
// 去除空白
public static List<String> toStrList(String str) {
if (isEmpty(str)) {
return new ArrayList<>();
}
String[] split = str.split(QueryConfigUtils.SPLIT_CHAR);
return Arrays.stream(split).filter(s -> !isEmpty(s)).collect(Collectors.toList());
}
public static String[] toStrArr(String str) {
List<String> strList = toStrList(str);
if (isEmpty(strList)) {
return null;
}
return strList.toArray(new String[strList.size()]);
}
public static boolean isNotEmpty(final Object object) {
return !isEmpty(object);
}
public static boolean isEmpty(final Object object) {
if (object == null) {
return true;
}
if (object instanceof CharSequence) {
return ((CharSequence) object).length() == 0;
}
if (object.getClass().isArray()) {
return Array.getLength(object) == 0;
}
if (object instanceof Collection<?>) {
return ((Collection<?>) object).isEmpty();
}
if (object instanceof Map<?, ?>) {
return ((Map<?, ?>) object).isEmpty();
}
return false;
}
/**
* 是否支持日期搜索的类型 的关键字
*
* @param input 输入
* @return boolean
*/
public static boolean isDateValue(String input) {
try {
LocalDate.parse(input, DateTimeFormatter.ISO_LOCAL_DATE);
return true;
} catch (Exception e) {
try {
Long.valueOf(input);
return true;
} catch (Exception e2) {
}
}
return false;
}
public static String toStr(Object str) {
return toStr(str, "");
}
public static String toStr(Object str, String defaultValue) {
return null != str ? str.toString() : defaultValue;
}
/**
* 对象到数组
*
* @param obj obj
* @param clazz clazz
* @return {@link T[] }
*/
public static <T> T[] objToArray(Object obj, Class<T> clazz) {
if (obj == null) {
return (T[]) Array.newInstance(clazz, 0); // 返回空数组
}
if (obj.getClass().isArray()) {
return (T[]) obj; // 已经是数组直接转换
}
if (obj instanceof List<?>) {
List<?> list = (List<?>) obj;
// 使用传入的类型创建数组
return list.toArray((T[]) Array.newInstance(clazz, list.size()));
}
// 单个对象转换为包含该对象的数组
T[] array = (T[]) Array.newInstance(clazz, 1);
array[0] = (T) obj;
return array;
}
/**
* 日期格式
*
* @param localDateTime 当地日期时间
* @return {@link String }
*/
public static String dateFormat(LocalDateTime localDateTime) {
return DateUtil.format(localDateTime, "yyyy-MM-dd HH:mm:ss");
}
/**
* // 将对象转换为 List支持泛型
*
* @param obj obj
* @param clazz clazz
* @return {@link List }<{@link T }>
*/
public static <T> List<T> objToList(Object obj, Class<T> clazz) {
if (obj == null) {
return new ArrayList<>(); // 返回空 List
}
if (obj.getClass().isArray()) {
// 数组转换为 List
int length = Array.getLength(obj);
List<T> list = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
list.add((T) Array.get(obj, i));
}
return list;
}
if (obj instanceof List<?>) {
return new ArrayList<>((List<T>) obj); // 已经是 List直接转换
}
// 单个对象转换为包含该对象的 List
return new ArrayList<>(Collections.singletonList((T) obj));
}
/**
* 对象是否为数组类型
*
* @param obj obj
* @return boolean
*/
public static boolean isArr(Object obj) {
if (obj == null) {
return false;
}
// 检查是否为数组
if (obj.getClass().isArray()) {
return true;
}
return false;
}
/**
* 是否为List 类型的数据
*
* @param obj obj
* @return boolean
*/
public static boolean isList(Object obj) {
if (obj == null) {
return false;
}
// 检查是否为 List
if (obj instanceof List) {
return true;
}
return false;
}
/**
* 字符串添加
*
* @param str str
* @param field 领域
* @return {@link String }
*/
public static String strAdd(String str, String... field) {
if (QueryConfigUtils.isNotEmpty(field)) {
for (String s : field) {
if (QueryConfigUtils.isNotEmpty(s.trim())) {
str += (s.trim() + QueryConfigUtils.SPLIT_CHAR);
}
}
}
return str;
}
/**
* 字符串删除
*
* @param str str
* @param keys
* @return {@link String }
*/
public static String strRemove(String str, String... keys) {
if (QueryConfigUtils.isNotEmpty(keys)) {
String[] split = str.split(QueryConfigUtils.SPLIT_CHAR);
StringBuilder builder = new StringBuilder();
List<String> strList = QueryConfigUtils.toStrList(String.join(QueryConfigUtils.SPLIT_CHAR, keys));
for (int i = 0; i < split.length; i++) {
if (strList.contains(split[i])) {
continue;
}
builder.append(split[i]).append(QueryConfigUtils.SPLIT_CHAR);
}
str = builder.toString();
}
return str;
}
/**
* 跳过数据
*
* @param str str
* @return boolean
*/
public static boolean skipData(Object str) {
return getSkipHandler(LOCAL_HANDLER.get()).apply(str);
}
/**
* where 条件处理
*
* @param value str
* @return boolean
*/
public static <T> QueryWrapper<T> whereHandler(QueryWrapper<T> queryWrapper,
QueryFilterTypeEnum type,
Set<String> dateField,
String filed,
Object value) {
return WrapperHandler.exeWrapperHandler(queryWrapper, type,dateField, filed, value);
}
}

View File

@ -0,0 +1,216 @@
package cn.hangtag.framework.mybatis.build;
import cn.hangtag.framework.common.pojo.PageParam;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
import java.io.Serializable;
import java.util.*;
/*
前端条件 条件
where
(userName like '%%' or nickname like '%%')
and (age > 18)
and (userName in ('陈海瑶', '冯雨馨')
or nickname like '%%')
{
"pager": {
"current": 1,
"size": 10
},
"config": {
"keywordSearch": "",
"keywordFields": "userName,nickname",
"orderBy": "age desc;name asc",
"options": {
"age": {
"type": ">",
"or": false
},
"userName": {
"type": "in",
"or": false
},
"nickname": {
"type": "like",
"or": true
}
}
},
"filter": {
"age": 18,
"userName": [
"陈海瑶",
"冯雨馨"
],
"nickname": ""
}
}
*/
@Data
public class QueryFilterInfo<T> implements Serializable {
private FilterItemConfig config; // 配置
private PageParam pager = new PageParam(); // 分页
// 查询条件
private Map<String, Object> filter = new HighPerformanceOrderedMap<>();
public FilterItemConfig getConfig() {
if(config == null){
config = new FilterItemConfig();
}
return config;
}
public String getDefaultFilterType() {
return getConfig().getDefaultFilterType();
}
public Map<String, Object> getFilter() {
if (filter == null) {
filter = new HighPerformanceOrderedMap<>();
}
return filter;
}
// @条件(QueryFilterTypeEnum) 多个使用逗号号间隔; name@like,age@> 条件 where like '%?%' and age > ?
public void easyOptions(String options){
this.getConfig().setEasyOption(options);
}
public Map<String, FilterItem> getOptions() {
return this.getConfig().getOptions();
}
/**
* 建立或
*
* @param field 字段
* @param value
* @param type 类型
* @return {@link FilterItem }
*/
public FilterItem buildOr(String field, Object value, QueryFilterTypeEnum type) {
return buildFilter(field, value, type, true);
}
public void appendKeywordFields(String ...field){
QueryConfigUtils.strAdd(this.getConfig().getKeywordFields(),field);
}
public void delKeywordFields(String... keys){
QueryConfigUtils.strRemove(this.getConfig().getKeywordFields(), keys);
}
public void appendDateFields(String ...field){
QueryConfigUtils.strAdd(this.getConfig().getDateFields(),field);
}
public void delDateFields(String... keys){
QueryConfigUtils.strRemove(this.getConfig().getDateFields(),keys);
}
public void appendGroupBy(String ...field){
QueryConfigUtils.strAdd(this.getConfig().getGroupBy(),field);
}
public void delGroupBy(String... keys){
QueryConfigUtils.strRemove(this.getConfig().getGroupBy(),keys);
}
public boolean containsIgnoredKeys(String key) {
return this.getConfig().getIgnoreFields().contains(key);
}
public Set<String> getIgnoreFieldsKeys(){
return this.getConfig().getIgnoreFieldsKeys();
}
public void appendIgnoreFields(String ...field){
Set<String> set = new HashSet<>();
if(QueryConfigUtils.isNotEmpty(field)){
set.addAll(Arrays.asList(field));
}
appendIgnoreFields(set);
}
public void setDefaultFilterType(QueryFilterTypeEnum type){
this.getConfig().setDefaultFilterType(type.getValue());
}
public void appendIgnoreFields(Set<String> field){
if(QueryConfigUtils.isNotEmpty(field)){
for (String s : field) {
if(QueryConfigUtils.isNotEmpty(s.trim())){
this.getConfig().getIgnoreFieldsKeys().add(s.trim());
}
}
}
}
public void delIgnoreFields(String... keys){
if(QueryConfigUtils.isNotEmpty(keys)){
for (String key : keys) {
this.getConfig().getIgnoreFieldsKeys().remove(key);
}
}
}
public void appendOrderByDesc(String ...field){
appendOrderBy("DESC",field);
}
private void appendOrderBy(String type,String ...field){
if(QueryConfigUtils.isNotEmpty(field)){
StringBuilder builder = new StringBuilder();
List<String> strList = QueryConfigUtils.toStrList(this.getConfig().getOrderBy());
for (String s : field) {
if (QueryConfigUtils.isNotEmpty(s.trim())) {
String key = s.trim() + " "+type;
if(strList.contains(key)){
strList.remove(key);
}
builder.append(s.trim()).append(" ").append(type).append(",");
}
}
// 移除重复的排序
StringBuilder res = new StringBuilder();
for (String s : strList) {
res.append(s).append(",");
}
String tmp = res.toString();
tmp += builder.toString();
this.getConfig().setOrderBy(tmp);
}
}
public void appendOrderByAsc(String ...field){
appendOrderBy("ASC",field);
}
public void delOrderBy(String... keys){
QueryConfigUtils.strRemove(this.getConfig().getOrderBy(), keys);
}
/**
* 构建
*
* @param field 字段
* @param value
* @param type 类型
* @return {@link FilterItem }
*/
public FilterItem build(String field, Object value, QueryFilterTypeEnum type) {
return build(field, value, type, false);
}
public FilterItem build(String field, Object value, QueryFilterTypeEnum type, boolean isOr) {
return buildFilter(field, value, type, isOr);
}
private FilterItem buildFilter(String field, Object value, QueryFilterTypeEnum type, boolean isOr) {
filter.put(field, value);
FilterItem item = new FilterItem();
item.setOr(isOr);
item.setType(type.getValue());
this.getConfig().getOptions().put(field, item);
return item;
}
}

View File

@ -0,0 +1,113 @@
package cn.hangtag.framework.mybatis.build;
import cn.hutool.core.date.DateUtil;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* 类型 取值转换器
*
* @author YuanFeng
* @date 2024/10/16
*/
public class TypeConverter {
// 用于存储类型和其对应的转换逻辑
private static final Map<Class<?>, Function<Object, Object>> converters = new HashMap<>();
// 注册类型转换器
public static <T> void registerConverter(Class<T> type, Function<T, Object> converter) {
converters.put(type, (Function<Object, Object>) converter);
}
// 根据类型进行转换
public static Object convertValue(Object inputVal, Class<?> targetType) {
Function<Object, Object> converter = converters.get(targetType);
if (converter == null) {
// 如果没有注册转换器返回原始值
return null;
}
// 如果有对应类型的转换器执行转换
return converter.apply(inputVal);
}
static {
rest();
}
public static void rest(){
restLocalDateTime();
restDate();
restString();
restLong();
restDouble();
restInteger();
restBoolean();
restBigDecimal();
restBigInteger();
}
public static void restLocalDateTime(){
// 注册LocalDate的转换器
TypeConverter.registerConverter(LocalDateTime.class, inputVal -> {
if (inputVal != null) {
return QueryConfigUtils.dateFormat(inputVal);
}
return null;
});
}
public static void restDate(){
// 注册Date的转换器
TypeConverter.registerConverter(Date.class, inputVal -> {
if (inputVal != null) {
return DateUtil.formatDate(inputVal);
}
return null;
});
}
public static void restString(){
// 注册字符的转换器
TypeConverter.registerConverter(String.class, inputVal -> {
return inputVal;
});
}
public static void restLong(){
TypeConverter.registerConverter(Long.class, inputVal -> {
return inputVal;
});
}public static void restDouble(){
TypeConverter.registerConverter(Double.class, inputVal -> {
return inputVal;
});
}
public static void restInteger(){
TypeConverter.registerConverter(Integer.class, inputVal -> {
return inputVal;
});
}public static void restBoolean(){
TypeConverter.registerConverter(Boolean.class, inputVal -> {
return inputVal;
});
}
public static void restBigDecimal() {
TypeConverter.registerConverter(BigDecimal.class, inputVal -> {
if (inputVal != null) {
return new BigDecimal(inputVal.toString()).toString();
}
return null;
});
}
public static void restBigInteger() {
TypeConverter.registerConverter(BigInteger.class, inputVal -> {
if (inputVal != null) {
return new BigInteger(inputVal.toString());
}
return null;
});
}
}

View File

@ -0,0 +1,52 @@
package cn.hangtag.framework.mybatis.build;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class WrapperHandler {
private static final Map<QueryFilterTypeEnum, WhereWrapper<?>> QUERY_WRAPPER_HANDLER = new HashMap<>();
public static void registerWrapperHandler(WhereWrapper<?> whereWrapper) {
if(whereWrapper != null){
QUERY_WRAPPER_HANDLER.put(whereWrapper.getType(), whereWrapper);
}
}
public static <T> QueryWrapper<T> exeWrapperHandler(QueryWrapper<T> queryWrapper,
QueryFilterTypeEnum type,
Set<String> dateField,
String field, Object value) {
if (queryWrapper == null) {
queryWrapper = new QueryWrapper<>();
}
WhereWrapper<?> whereWrapper = QUERY_WRAPPER_HANDLER.get(type);
WrapperInfo<T> wrapperInfo = new WrapperInfo<>(queryWrapper, field, value,dateField);
if (whereWrapper == null) {
//没有找到处理器 使用默认
if (QueryConfigUtils.isArr(value)) {
Object[] strings = QueryConfigUtils.objToArray(value, Object.class);
if (QueryConfigUtils.isNotEmpty(strings)) {
return queryWrapper.between(field, strings[0], strings[strings.length - 1]);
}
}
if (QueryConfigUtils.isList(value)) {
List<Object> list = QueryConfigUtils.objToList(value, Object.class);
if (QueryConfigUtils.isNotEmpty(list)) {
return queryWrapper.between(field, list.get(0), list.get(list.size() - 1));
}
}
return queryWrapper.eq(field, value);
}
// 执行
return ((WhereWrapper<T>)whereWrapper).handler(wrapperInfo);
}
}

View File

@ -0,0 +1,37 @@
package cn.hangtag.framework.mybatis.build;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.HashSet;
import java.util.Set;
/**
* 包装信息
*
* @author YuanFeng
*/
@Data
@AllArgsConstructor
public class WrapperInfo<T> {
private QueryWrapper<T> queryWrapper;
private String field;
private Object value;
private Set<String> dateFields;
public Set<String> getDateFields() {
if (dateFields == null) {
dateFields = new HashSet<>();
}
return dateFields;
}
public QueryWrapper<T> getQueryWrapper() {
if (queryWrapper == null) {
queryWrapper = new QueryWrapper<>();
}
return queryWrapper;
}
}

View File

@ -0,0 +1,70 @@
package cn.hangtag.framework.mybatis.build.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum DbTypeEnum {
MYSQL("mysql", "MySql数据库"),
MARIADB("mariadb", "MariaDB数据库"),
ORACLE("oracle", "Oracle11g及以下数据库(高版本推荐使用ORACLE_NEW)"),
ORACLE_12C("oracle12c", "Oracle12c+数据库"),
DB2("db2", "DB2数据库"),
H2("h2", "H2数据库"),
HSQL("hsql", "HSQL数据库"),
SQLITE("sqlite", "SQLite数据库"),
POSTGRE_SQL("postgresql", "Postgre数据库"),
SQL_SERVER2005("sqlserver2005", "SQLServer2005数据库"),
SQL_SERVER("sqlserver", "SQLServer数据库"),
DM("dm", "达梦数据库"),
XU_GU("xugu", "虚谷数据库"),
KINGBASE_ES("kingbasees", "人大金仓数据库"),
PHOENIX("phoenix", "Phoenix HBase数据库"),
GAUSS("zenith", "Gauss 数据库"),
CLICK_HOUSE("clickhouse", "clickhouse 数据库"),
GBASE("gbase", "南大通用(华库)数据库"),
GBASE_8S("gbase-8s", "南大通用数据库 GBase 8s"),
GBASE8S_PG("gbase8s-pg", "南大通用数据库 GBase 8s兼容pg"),
GBASE_8C("gbase8c", "南大通用数据库 GBase 8c"),
SINODB("sinodb", "星瑞格数据库"),
OSCAR("oscar", "神通数据库"),
SYBASE("sybase", "Sybase ASE 数据库"),
OCEAN_BASE("oceanbase", "OceanBase 数据库"),
FIREBIRD("Firebird", "Firebird 数据库"),
HIGH_GO("highgo", "瀚高数据库"),
CUBRID("cubrid", "CUBRID数据库"),
SUNDB("sundb", "SUNDB数据库"),
SAP_HANA("hana", "SAP_HANA数据库"),
IMPALA("impala", "impala数据库"),
VERTICA("vertica", "vertica数据库"),
XCloud("xcloud", "行云数据库"),
REDSHIFT("redshift", "亚马逊redshift数据库"),
OPENGAUSS("openGauss", "华为 opengauss 数据库"),
TDENGINE("TDengine", "TDengine数据库"),
INFORMIX("informix", "Informix数据库"),
UXDB("uxdb", "优炫数据库"),
LEALONE("lealone", "Lealone数据库"),
TRINO("trino", "Trino数据库"),
PRESTO("presto", "Presto数据库"),
OTHER("other", "其他数据库");
private final String db;
private final String desc;
public static DbTypeEnum getDbType(String dbType) {
DbTypeEnum[] var1 = values();
int var2 = var1.length;
for (int var3 = 0; var3 < var2; ++var3) {
DbTypeEnum type = var1[var3];
if (type.db.equalsIgnoreCase(dbType)) {
return type;
}
}
return OTHER;
}
}

View File

@ -0,0 +1,50 @@
package cn.hangtag.framework.mybatis.build.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum QueryFilterTypeEnum {
GT("大于", ">"),
GE("大于等于", ">="),
LT("小于", "<"),
LE("小于等于", "<="),
NE("不等于", "!="),
EQ("等于", "="),
IN("在...之内", "in"),
NOTIN("不在...之内", "notIn"),
BETWEEN("之间", "between"),
BETWEEN2("之间", "><"),
LIKE("模糊匹配", "like"),
NOT_LIKE("模糊匹配", "notLike"),
LIKE_LEFT("左模糊匹配", "likeLeft"),
LIKE_RIGHT("右模糊匹配", "likeRight"),
/**
* 查询以逗号分隔的组合字段数据
* 使用条件FIND_IN_SET({0}, columnName) 进行查询
* 示例
* - 字段值为数据1: 123,234,345数据2: 23,456数据3: 123,567
* - 当条件为 23 仅匹配包含 23 的数据即数据2
*/
IN_SET("查询以逗号分隔的组合字段数据", "inSet"),
KEYWORD("关键字", "keyword")
;
private final String msg;
private final String value;
public static QueryFilterTypeEnum getByValue(String value){
if(value != null && !value.isEmpty()){
for( QueryFilterTypeEnum enumItem: QueryFilterTypeEnum.values()) {
if (enumItem.getValue().equalsIgnoreCase(value)) {
return enumItem;
}
}
}
return null;
}
}

View File

@ -0,0 +1,11 @@
package cn.hangtag.framework.mybatis.build.where;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
public interface WhereWrapper<T> {
QueryFilterTypeEnum getType();
QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo);
}

View File

@ -0,0 +1,29 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class Between2Handler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.BETWEEN2;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
if (QueryConfigUtils.isArr(wrapperInfo.getValue())) {
Object[] strings = QueryConfigUtils.objToArray(wrapperInfo.getValue(), Object.class);
wrapperInfo.getQueryWrapper().between(wrapperInfo.getField(), strings[0], strings[strings.length - 1]);
} else if (QueryConfigUtils.isList(wrapperInfo.getValue())) {
List<Object> list = QueryConfigUtils.objToList(wrapperInfo.getValue(), Object.class);
wrapperInfo.getQueryWrapper().between(wrapperInfo.getField(), list.get(0), list.get(list.size() - 1));
}
return wrapperInfo.getQueryWrapper();
}
}

View File

@ -0,0 +1,28 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class BetweenHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.BETWEEN;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
if (QueryConfigUtils.isArr(wrapperInfo.getValue())) {
Object[] strings = QueryConfigUtils.objToArray(wrapperInfo.getValue(), Object.class);
wrapperInfo.getQueryWrapper().between(wrapperInfo.getField(), strings[0], strings[strings.length - 1]);
} else if (QueryConfigUtils.isList(wrapperInfo.getValue())) {
List<Object> list = QueryConfigUtils.objToList(wrapperInfo.getValue(), Object.class);
wrapperInfo.getQueryWrapper().between(wrapperInfo.getField(), list.get(0), list.get(list.size() - 1));
}
return wrapperInfo.getQueryWrapper();
}
}

View File

@ -0,0 +1,21 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class EqHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.EQ;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
return wrapperInfo.getQueryWrapper().eq(wrapperInfo.getField(), wrapperInfo.getValue());
}
}

View File

@ -0,0 +1,21 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class GeHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.GE;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
return wrapperInfo.getQueryWrapper().ge(wrapperInfo.getField(), wrapperInfo.getValue());
}
}

View File

@ -0,0 +1,21 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class InHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.IN;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
return wrapperInfo.getQueryWrapper().in(wrapperInfo.getField(), wrapperInfo.getValue());
}
}

View File

@ -0,0 +1,33 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class InSetHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.IN_SET;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
// 查询逗号组合数据
String str2 = QueryConfigUtils.toStr(wrapperInfo.getValue());
String[] arr = str2.split(QueryConfigUtils.SPLIT_CHAR);
wrapperInfo.getQueryWrapper().and(w -> {
for (int i = 0; i < arr.length; i++) {
String s = arr[i];
w.apply(QueryConfigUtils.getIdsToApply(wrapperInfo.getField()), s);
if (i < arr.length - 1) {
wrapperInfo.getQueryWrapper().or();
}
}
});
return wrapperInfo.getQueryWrapper();
}
}

View File

@ -0,0 +1,33 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class KeywordHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.KEYWORD;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
String str1 = QueryConfigUtils.toStr(wrapperInfo.getValue());
// 多个关键字 空格间隔 张三 条件 where (name like '%%' or name like '%%' )
String[] arr2 = str1.split(" ");
wrapperInfo.getQueryWrapper().and(w -> {
for (int i = 0; i < arr2.length; i++) {
String s = arr2[i];
w.like(wrapperInfo.getField(), s);
if (i < arr2.length - 1) {
w.or();
}
}
});
return wrapperInfo.getQueryWrapper();
}
}

View File

@ -0,0 +1,21 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class LeHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.LE;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
return wrapperInfo.getQueryWrapper().le(wrapperInfo.getField(), wrapperInfo.getValue());
}
}

View File

@ -0,0 +1,28 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class LikeHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.LIKE;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
if (wrapperInfo.getDateFields().contains(wrapperInfo.getField()) && !QueryConfigUtils.isDateValue(QueryConfigUtils.toStr(wrapperInfo.getValue()))) {
//字段为日期 但是关键字的值 又不能支持 like 跳过条件
// 设置一个不能的匹配的条件
wrapperInfo.getQueryWrapper().eq("1", "2");
} else {
wrapperInfo.getQueryWrapper().like(wrapperInfo.getField(), wrapperInfo.getValue());
}
return wrapperInfo.getQueryWrapper();
}
}

View File

@ -0,0 +1,28 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class LikeLeftHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.LIKE_LEFT;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
if (wrapperInfo.getDateFields().contains(wrapperInfo.getField()) && !QueryConfigUtils.isDateValue(QueryConfigUtils.toStr(wrapperInfo.getValue()))) {
//字段为日期 但是关键字的值 又不能支持 like 跳过条件
// 设置一个不能的匹配的条件
wrapperInfo.getQueryWrapper().eq("1", "2");
} else {
wrapperInfo.getQueryWrapper().likeLeft(wrapperInfo.getField(), wrapperInfo.getValue());
}
return wrapperInfo.getQueryWrapper();
}
}

View File

@ -0,0 +1,28 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class LikeRightHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.LIKE_RIGHT;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
if (wrapperInfo.getDateFields().contains(wrapperInfo.getField()) && !QueryConfigUtils.isDateValue(QueryConfigUtils.toStr(wrapperInfo.getValue()))) {
//字段为日期 但是关键字的值 又不能支持 like 跳过条件
// 设置一个不能的匹配的条件
wrapperInfo.getQueryWrapper().eq("1", "2");
} else {
wrapperInfo.getQueryWrapper().likeRight(wrapperInfo.getField(), wrapperInfo.getValue());
}
return wrapperInfo.getQueryWrapper();
}
}

View File

@ -0,0 +1,21 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class LtHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.LT;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
return wrapperInfo.getQueryWrapper().lt(wrapperInfo.getField(), wrapperInfo.getValue());
}
}

View File

@ -0,0 +1,21 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class NeHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.NE;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
return wrapperInfo.getQueryWrapper().ne(wrapperInfo.getField(), wrapperInfo.getValue());
}
}

View File

@ -0,0 +1,21 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class NotInHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.NOTIN;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
return wrapperInfo.getQueryWrapper().notIn(wrapperInfo.getField(), wrapperInfo.getValue());
}
}

View File

@ -0,0 +1,28 @@
package cn.hangtag.framework.mybatis.build.where.handler;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hangtag.framework.mybatis.build.WrapperInfo;
import cn.hangtag.framework.mybatis.build.enums.QueryFilterTypeEnum;
import cn.hangtag.framework.mybatis.build.where.WhereWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.List;
public class NotLikeHandler<T> implements WhereWrapper<T> {
@Override
public QueryFilterTypeEnum getType() {
return QueryFilterTypeEnum.NOT_LIKE;
}
@Override
public QueryWrapper<T> handler(WrapperInfo<T> wrapperInfo) {
if (wrapperInfo.getDateFields().contains(wrapperInfo.getField()) && !QueryConfigUtils.isDateValue(QueryConfigUtils.toStr(wrapperInfo.getValue()))) {
//字段为日期 但是关键字的值 又不能支持 like 跳过条件
// 设置一个不能的匹配的条件
wrapperInfo.getQueryWrapper().eq("1", "2");
} else {
wrapperInfo.getQueryWrapper().notLike(wrapperInfo.getField(), wrapperInfo.getValue());
}
return wrapperInfo.getQueryWrapper();
}
}

View File

@ -1,5 +1,6 @@
package cn.hangtag.framework.mybatis.config;
import cn.hangtag.framework.mybatis.build.QueryConfigUtils;
import cn.hutool.core.util.StrUtil;
import cn.hangtag.framework.mybatis.core.handler.DefaultDBFieldHandler;
import com.baomidou.mybatisplus.annotation.DbType;
@ -26,6 +27,7 @@ import org.springframework.core.env.ConfigurableEnvironment;
lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载目前仅用于单元测试
public class HangtagMybatisAutoConfiguration {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
@ -43,6 +45,7 @@ public class HangtagMybatisAutoConfiguration {
public IKeyGenerator keyGenerator(ConfigurableEnvironment environment) {
DbType dbType = IdTypeEnvironmentPostProcessor.getDbType(environment);
if (dbType != null) {
QueryConfigUtils.setDbType(dbType.getDb());
switch (dbType) {
case POSTGRE_SQL:
return new PostgreKeyGenerator();

View File

@ -8,6 +8,8 @@ public interface ErrorCodeConstants extends cn.hangtag.module.system.enums.Erro
ErrorCode PRODUCT_INFO_NOT_EXISTS = new ErrorCode(3200, "产品资料 不存在");
ErrorCode PRODUCT_PROCESS_NOT_EXISTS = new ErrorCode(3201, "产品工艺 不存在");
ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(3300, "客户不存在");
ErrorCode CUSTOMER_LOGIN_STATUS_DISABLE = new ErrorCode(3301, "客户已被禁用!请联系管理员");
ErrorCode CUSTOMER_ADDRESS_NOT_EXISTS = new ErrorCode(3302, "地址信息数据 不存在");
ErrorCode SHAPE_TEMPLATE_NOT_EXISTS = new ErrorCode(3400, "图形模板管理 不存在");
ErrorCode DRAFT_DESIGN_DATA_NOT_EXISTS = new ErrorCode(3500, "稿件模板数据 不存在");
ErrorCode SALE_ORDER_NOT_EXISTS = new ErrorCode(3600, "OMS销售订单不存在");

View File

@ -39,6 +39,11 @@ public class BrandRespVO {
@ExcelProperty("官网")
private String website;
@Schema(description = "品牌数量")
@ExcelProperty("品牌数量")
private Integer productCount;
@Schema(description = "语言标识 字典-language_locale")
@ExcelProperty("语言标识 字典-language_locale")
private String locale;

View File

@ -0,0 +1,84 @@
package cn.hangtag.module.oms.controller.admin.customer.front;
import cn.hangtag.framework.common.pojo.CommonResult;
import cn.hangtag.framework.common.pojo.PageResult;
import cn.hangtag.framework.common.util.FuncUtil;
import cn.hangtag.framework.common.util.object.BeanUtils;
import cn.hangtag.framework.ip.core.Area;
import cn.hangtag.framework.ip.core.utils.AreaUtils;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.AddressInfoVO;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.AddressInfoValidate;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.AddressReqVO;
import cn.hangtag.module.oms.service.customer.CustomerAddressService;
import cn.hangtag.module.oms.service.customer.CustomerService;
import cn.hangtag.module.system.controller.app.ip.vo.AppAreaNodeRespVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import static cn.hangtag.framework.common.pojo.CommonResult.success;
@Tag(name = "前台 - 客户")
@RestController
@RequestMapping("/front/oms/address")
@Validated
@AllArgsConstructor
public class AddressFrontController {
private final CustomerService customerService;
private final CustomerAddressService addressService;
@PostMapping("/submit")
@Operation(summary = "更新品牌管理 ")
// todo 权限
public CommonResult<Long> submit(@Valid @RequestBody AddressInfoValidate info) {
Long id = addressService.submit(info);
return success(id);
}
@DeleteMapping("/{id}")
@Operation(summary = "删除 ")
@Parameter(name = "id", description = "主键id", required = true)
public CommonResult<Boolean> delete(@PathVariable("id") Long id) {
addressService.delById(id);
return success(true);
}
@GetMapping("/{id}")
@Operation(summary = "获取明细 ")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<AddressInfoVO> getBrand(@PathVariable("id") Long id) {
AddressInfoVO vo = addressService.getAddressInfo(id);
return success(vo);
}
@PutMapping("/default/{id}")
@Operation(summary = "获取明细 ")
@Parameter(name = "id", description = "编号")
public CommonResult<Boolean> setDefaultAddress(@PathVariable("id") Long id) {
addressService.setDefaultAddress(id);
return success(true);
}
@GetMapping("/page")
@Operation(summary = "获得品牌管理 分页")
public CommonResult<PageResult<AddressInfoVO>> getBrandPage(@Valid AddressReqVO vo) {
PageResult<AddressInfoVO> pageResult = addressService.queryPage(vo);
return success(pageResult);
}
@GetMapping("/area-tree/{type}")
public CommonResult<List<AppAreaNodeRespVO>> getAreaTree(@PathVariable Integer type) {
int anInt = FuncUtil.toInt(type, 0);
Area area = AreaUtils.getArea(anInt == 1 ? 1 : 0);
return success(BeanUtils.toBean(area.getChildren(), AppAreaNodeRespVO.class));
}
}

View File

@ -0,0 +1,38 @@
package cn.hangtag.module.oms.controller.admin.customer.front;
import cn.hangtag.framework.common.pojo.CommonResult;
import cn.hangtag.framework.security.core.LoginUser;
import cn.hangtag.framework.security.core.util.SecurityFrameworkUtils;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.CustomerInfoVO;
import cn.hangtag.module.oms.service.customer.CustomerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import static cn.hangtag.framework.common.pojo.CommonResult.success;
@Tag(name = "前台 - 客户")
@RestController
@RequestMapping("/front/oms/customer")
@Validated
@AllArgsConstructor
public class CustomerFrontController {
private final CustomerService customerService;
@GetMapping("/info")
@Operation(summary = "获得客户")
public CommonResult<CustomerInfoVO> getCustomer() {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
CustomerInfoVO vo = customerService.queryLoginCustomerInfo(loginUser.getId());
return success(vo);
}
}

View File

@ -0,0 +1,48 @@
package cn.hangtag.module.oms.controller.admin.customer.front.vo;
import cn.hangtag.framework.common.util.SafeUseUtil;
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerAddressDO;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
public class AddressInfoVO implements Serializable {
/**
* ID
*/
@TableId
private Long id;
/**
* 关联到客户的ID外键指向客户表
*/
private Long customerId;
/**
* 收货人姓名
*/
private String name;
/**
* 联系电话
*/
private String phone;
/**
* /
*/
private Integer areaId;
/**
* 详细地址
*/
private String address;
/**
* 是否为默认地址0表示否1表示是
*/
private Boolean isDefault;
public AddressInfoVO(CustomerAddressDO addressDO) {
SafeUseUtil.copyProperties(addressDO,this);
}
}

View File

@ -0,0 +1,64 @@
package cn.hangtag.module.oms.controller.admin.customer.front.vo;
import cn.hangtag.framework.common.util.SafeUseUtil;
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerAddressDO;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 地址信息验证
*
* @author YuanFeng
* @date 2024/10/15
*/
@Data
@NoArgsConstructor
public class AddressInfoValidate implements Serializable {
/**
* ID
*/
@TableId
private Long id;
private Long customerId;
@NotEmpty(message = "名称不能为空")
@Length(min = 1, max = 64, message = "名称 name不能大于64个字符")
private String name;
@NotEmpty(message = "联系电话 phone不能为空")
private String phone;
/**
* /
*/
@NotNull(message = "areaId 地区不能为空")
private Integer areaId;
/**
* 详细地址
*/
@NotEmpty(message = "详细地址 不能为空")
@Length(min = 1, max = 512, message = "详细地址 name不能大于512个字符")
private String address;
/**
* 是否为默认地址0表示否1表示是
*/
private Boolean isDefault;
public Boolean getIsDefault() {
if(this.isDefault == null){
isDefault = false;
}
return isDefault;
}
public AddressInfoValidate(CustomerAddressDO addressDO) {
SafeUseUtil.copyProperties(addressDO,this);
}
}

View File

@ -0,0 +1,46 @@
package cn.hangtag.module.oms.controller.admin.customer.front.vo;
import cn.hangtag.framework.common.pojo.PageParam;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "前台 - 客户地址分页 ")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class AddressReqVO extends PageParam {
/**
* ID
*/
@TableId
private Long id;
/**
* 关联到客户的ID外键指向客户表
*/
private Long customerId;
/**
* 收货人姓名
*/
private String name;
/**
* 联系电话
*/
private String phone;
/**
* /
*/
private Integer areaId;
/**
* 详细地址
*/
private String address;
/**
* 是否为默认地址0表示否1表示是
*/
private Boolean isDefault;
}

View File

@ -0,0 +1,74 @@
package cn.hangtag.module.oms.controller.admin.customer.front.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
import java.util.List;
@Schema(description = "客户信息 VO")
@Data
@ToString(callSuper = true)
public class CustomerInfoVO implements Serializable {
@Schema(description = "ID")
private Long id;
@Schema(description = "编码")
private String number;
@Schema(description = "名称")
private String name;
@Schema(description = "公司")
private String company;
@Schema(description = "类型")
private String type;
@Schema(description = "数据状态")
private String status;
/**
* 公司地址
*/
private String companyAddress;
/**
* 邮箱
*/
private String email;
/**
* 联系人
*/
private String contacts;
/**
* 联系人手机号
*/
private String phone;
/**
* 跟单员
*/
private String gdperson;
/**
* 销售员
*/
private String saleperson;
private String invoiceCode;
private String invoiceName;
private String invoiceAddress;
/**
* 所属地区
*/
private List<AddressInfoVO> addressList;
/**
* 备注
*/
private String remarks;
}

View File

@ -59,4 +59,9 @@ public class DraftDesignDataRespVO {
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "产品计数")
@ExcelProperty("产品计数")
private Integer productCount;
}

View File

@ -1,5 +1,6 @@
package cn.hangtag.module.oms.controller.admin.productinfo;
import cn.hangtag.framework.mybatis.build.QueryFilterInfo;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
@ -8,7 +9,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
@ -79,6 +79,15 @@ public class ProductInfoController {
return success(BeanUtils.toBean(pageResult, ProductInfoRespVO.class));
}
@PostMapping("/query")
@Operation(summary = "获得产品资料 分页")
@PreAuthorize("@ss.hasPermission('oms:product-info:query')")
public CommonResult<PageResult<ProductInfoRespVO>> queryPage(@RequestBody QueryFilterInfo<ProductInfoPageReqVO> queryFilterInfo) {
PageResult<ProductInfoDO> pageResult = productInfoService.queryPage(queryFilterInfo);
return success(BeanUtils.toBean(pageResult, ProductInfoRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出产品资料 Excel")
@PreAuthorize("@ss.hasPermission('oms:product-info:export')")

View File

@ -1,64 +0,0 @@
package cn.hangtag.module.oms.controller.admin.saleorder;
import cn.hangtag.framework.apilog.core.annotation.ApiAccessLog;
import cn.hangtag.framework.common.pojo.CommonResult;
import cn.hangtag.framework.common.pojo.PageParam;
import cn.hangtag.framework.common.pojo.PageResult;
import cn.hangtag.framework.common.util.number.NumberUtils;
import cn.hangtag.framework.common.util.object.BeanUtils;
import cn.hangtag.framework.excel.core.util.ExcelUtils;
import cn.hangtag.module.oms.controller.admin.saleorder.dto.CreateSaleOrderDTO;
import cn.hangtag.module.oms.controller.admin.saleorder.vo.SaleOrderPageReqVO;
import cn.hangtag.module.oms.controller.admin.saleorder.vo.SaleOrderRemarkReqVO;
import cn.hangtag.module.oms.controller.admin.saleorder.vo.SaleOrderRespVO;
import cn.hangtag.module.oms.controller.admin.saleorder.vo.SaleOrderSaveReqVO;
import cn.hangtag.module.oms.convert.saleorder.SaleOrderConvert;
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerDO;
import cn.hangtag.module.oms.dal.dataobject.saleorder.SaleOrderDO;
import cn.hangtag.module.oms.dal.dataobject.saleorderentry.SaleOrderEntryDO;
import cn.hangtag.module.oms.service.customer.CustomerService;
import cn.hangtag.module.oms.service.saleorder.SaleOrderService;
import cn.hangtag.module.system.api.user.AdminUserApi;
import cn.hangtag.module.system.api.user.dto.AdminUserRespDTO;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONObject;
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.annotation.security.PermitAll;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static cn.hangtag.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.hangtag.framework.common.pojo.CommonResult.success;
@Tag(name = "销售订单")
@RestController
@RequestMapping("/front/oms/sale-order")
@Validated
public class SaleOrderFrontController {
@Resource
private SaleOrderService saleOrderService;
@Resource
private CustomerService customerService;
@Resource
private AdminUserApi adminUserApi;
@PostMapping("/placeOrder")
@Operation(summary = "下单")
public CommonResult<Long> placeOrder(@Valid @RequestBody CreateSaleOrderDTO dto) {
return success(saleOrderService.placeOrder(dto));
}
}

View File

@ -0,0 +1,38 @@
package cn.hangtag.module.oms.controller.admin.saleorder.front;
import cn.hangtag.framework.common.pojo.CommonResult;
import cn.hangtag.module.oms.controller.admin.saleorder.front.dto.CreateSaleOrderDTO;
import cn.hangtag.module.oms.service.customer.CustomerService;
import cn.hangtag.module.oms.service.saleorder.SaleOrderService;
import cn.hangtag.module.system.api.user.AdminUserApi;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.hangtag.framework.common.pojo.CommonResult.success;
@Tag(name = "销售订单")
@RestController
@RequestMapping("/front/oms/sale-order")
@Validated
public class SaleOrderFrontController {
@Resource
private SaleOrderService saleOrderService;
@Resource
private CustomerService customerService;
@Resource
private AdminUserApi adminUserApi;
@PostMapping("/placeOrder")
@Operation(summary = "下单")
public CommonResult<Long> placeOrder(@Valid @RequestBody CreateSaleOrderDTO dto) {
return success(saleOrderService.placeOrder(dto));
}
}

View File

@ -1,10 +1,9 @@
package cn.hangtag.module.oms.controller.admin.saleorder.dto;
package cn.hangtag.module.oms.controller.admin.saleorder.front.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Data
@ -80,11 +79,24 @@ public class CreateSaleOrderDTO implements Serializable {
*/
private Long plansenddate;
/**
* 交货地址
*/
private String deliveryAddress;
/**
* 交货备注
*/
private String deliveryRemark;
/**
* 是否分批交货
*/
private Boolean isBatch;
private List<SaleOrderEntryItemDTO> saleOrderEntry;
}

View File

@ -1,4 +1,4 @@
package cn.hangtag.module.oms.controller.admin.saleorder.dto;
package cn.hangtag.module.oms.controller.admin.saleorder.front.dto;
import lombok.Data;

View File

@ -1,4 +1,4 @@
package cn.hangtag.module.oms.controller.admin.saleorder.dto;
package cn.hangtag.module.oms.controller.admin.saleorder.front.dto;
import lombok.Data;

View File

@ -1,4 +1,4 @@
package cn.hangtag.module.oms.controller.admin.saleorder.dto;
package cn.hangtag.module.oms.controller.admin.saleorder.front.dto;
import lombok.Data;

View File

@ -1,5 +1,8 @@
package cn.hangtag.module.oms.dal.dataobject.brand;
import cn.hangtag.framework.common.util.FuncUtil;
import cn.hangtag.module.oms.dal.dataobject.productinfo.ProductInfoDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
@ -62,4 +65,10 @@ public class BrandDO extends BaseDO {
*/
private String remark;
/**
* 产品计数
*/
private Integer productCount;
}

View File

@ -66,4 +66,10 @@ public class DraftDesignDataDO extends BaseDO {
*/
private String propDefault;
/**
* 产品计数
*/
private Integer productCount;
}

View File

@ -1,16 +1,10 @@
package cn.hangtag.module.oms.dal.dataobject.saleorder;
import cn.hangtag.module.oms.controller.admin.saleorder.dto.CreateSaleOrderDTO;
import cn.hangtag.module.oms.controller.admin.saleorder.front.dto.CreateSaleOrderDTO;
import cn.hutool.core.bean.BeanUtil;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.math.BigDecimal;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
@ -100,6 +94,17 @@ public class SaleOrderDO extends BaseDO {
* 发票名称
*/
private String invoiceName;
/**
* 发票地址
*/
private String invoiceAddress;
/**
* 发票备注
*/
private String invoiceRemarks;
/**
* 地址
*/
@ -108,10 +113,7 @@ public class SaleOrderDO extends BaseDO {
* 货币
*/
private String currency;
/**
* 发票备注
*/
private String invoiceRemarks;
/**
* 驳回原因
*/
@ -145,10 +147,7 @@ public class SaleOrderDO extends BaseDO {
* 零售商单号
*/
private String retailerCode;
/**
* 发票地址
*/
private String invoiceAddress;
/**
@ -161,7 +160,15 @@ public class SaleOrderDO extends BaseDO {
*/
private Boolean isBatch;
/**
* 交货地址
*/
private String deliveryAddress;
/**
* 交货备注
*/
private String deliveryRemark;
public SaleOrderDO(CreateSaleOrderDTO dto) {
BeanUtil.copyProperties(dto, this,"bizdate","plansenddate");

View File

@ -25,4 +25,5 @@ public interface CustomerAddressMapper extends BaseMapperX<CustomerAddressDO> {
return delete(CustomerAddressDO::getCustomerId, customerId);
}
int restDefaultAddress(Long customerId);
}

View File

@ -2,10 +2,16 @@ package cn.hangtag.module.oms.dal.mysql.productinfo;
import java.util.*;
import cn.hangtag.framework.common.pojo.PageParam;
import cn.hangtag.framework.common.pojo.PageResult;
import cn.hangtag.framework.mybatis.build.MybatisPlusUtil;
import cn.hangtag.framework.mybatis.build.QueryFilterInfo;
import cn.hangtag.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.hangtag.framework.mybatis.core.mapper.BaseMapperX;
import cn.hangtag.module.oms.dal.dataobject.productinfo.ProductInfoDO;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import cn.hangtag.module.oms.controller.admin.productinfo.vo.*;
@ -33,4 +39,16 @@ public interface ProductInfoMapper extends BaseMapperX<ProductInfoDO> {
.orderByDesc(ProductInfoDO::getId));
}
default PageResult<ProductInfoDO> selectPagePlus(QueryFilterInfo<ProductInfoPageReqVO> queryFilterInfo) {
PageParam pager = queryFilterInfo.getPager();
QueryWrapper<ProductInfoDO> queryWrapper = MybatisPlusUtil
.parseQuery(queryFilterInfo, true,ProductInfoDO.class,
"pageNo", "pageSize", "PAGE_NO", "PAGE_SIZE", "PAGE_SIZE_NONE");
queryWrapper.orderByDesc("id");
PageResult<ProductInfoDO> productInfoDOPageResult = selectPage(pager, queryWrapper);
return productInfoDOPageResult;
}
}

View File

@ -69,4 +69,13 @@ public interface BrandService {
* @return 品牌编号集合
*/
Set<Long> getCustomerBrandListByCustomerId(Collection<Long> customerIds);
/**
* 更新产品计数
*
* @param id ID 品牌id
* @return {@link Integer }
*/
Integer updateProductCount(Long id);
}

View File

@ -6,7 +6,9 @@ import cn.hangtag.framework.common.util.FuncUtil;
import cn.hangtag.framework.mybatis.core.dataobject.BaseDO;
import cn.hangtag.module.oms.base.dal.dataobject.producttype.ProductTypeDO;
import cn.hangtag.module.oms.dal.dataobject.customerbrand.CustomerBrandDO;
import cn.hangtag.module.oms.dal.dataobject.productinfo.ProductInfoDO;
import cn.hangtag.module.oms.dal.mysql.customerbrand.CustomerBrandMapper;
import cn.hangtag.module.oms.dal.mysql.productinfo.ProductInfoMapper;
import cn.hangtag.module.oms.enums.BrandErrorCodeConstants;
import cn.hangtag.module.oms.serialnumber.CodingRulesUtils;
import cn.hangtag.module.system.dal.dataobject.permission.MenuDO;
@ -14,15 +16,19 @@ import cn.hangtag.module.system.dal.dataobject.permission.RoleMenuDO;
import cn.hangtag.module.system.dal.mysql.permission.RoleMenuMapper;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.hangtag.module.oms.controller.admin.brand.vo.*;
import cn.hangtag.module.oms.dal.dataobject.brand.BrandDO;
import cn.hangtag.framework.common.pojo.PageResult;
@ -43,21 +49,21 @@ import static java.util.Collections.singleton;
@Service
@Validated
@Slf4j
@AllArgsConstructor
public class BrandServiceImpl implements BrandService {
@Resource
private BrandMapper brandMapper;
@Resource
private CustomerBrandMapper customerBrandMapper;
private final BrandMapper brandMapper;
private final ProductInfoMapper productInfoMapper;
private final CustomerBrandMapper customerBrandMapper;
@Override
public Long createBrand(BrandSaveReqVO createReqVO) {
// 插入
BrandDO brand = BeanUtils.toBean(createReqVO, BrandDO.class);
String code = brand.getCode();
if(FuncUtil.isNotEmpty(code)){
checkCode(brand.getId(),code);
}else {
if (FuncUtil.isNotEmpty(code)) {
checkCode(brand.getId(), code);
} else {
brand.setCode(getNewCode());
}
brandMapper.insert(brand);
@ -72,15 +78,30 @@ public class BrandServiceImpl implements BrandService {
// 更新
BrandDO updateObj = BeanUtils.toBean(updateReqVO, BrandDO.class);
String code = updateObj.getCode();
if(FuncUtil.isNotEmpty(code)){
checkCode(updateObj.getId(),code);
}else {
if (FuncUtil.isNotEmpty(code)) {
checkCode(updateObj.getId(), code);
} else {
updateObj.setCode(getNewCode());
}
brandMapper.updateById(updateObj);
}
@Override
public Integer updateProductCount(Long id) {
LambdaQueryWrapper<ProductInfoDO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ProductInfoDO::getBrandId, id);
queryWrapper.eq(ProductInfoDO::getDeleted, 0);
Long l = productInfoMapper.selectCount(queryWrapper);
int count = FuncUtil.toInt(l, 0);
// 更新数量
BrandDO brandDO = new BrandDO();
brandDO.setId(id);
brandDO.setProductCount(count);
brandMapper.updateById(brandDO);
return count;
}
@Override
public void deleteBrand(Long id) {
// 校验存在
@ -109,15 +130,15 @@ public class BrandServiceImpl implements BrandService {
public String getNewCode() {
String s = "";
int count = 10;
while (true){
count --;
while (true) {
count--;
try {
s = CodingRulesUtils.generateCode(2L, false);
checkCode(null,s);
return s;
}catch (ServiceException e){
s = CodingRulesUtils.generateCode(2L, false);
checkCode(null, s);
return s;
} catch (ServiceException e) {
log.warn("重复或者下一个编码");
if(count < 0){
if (count < 0) {
log.error("编码获取失败");
return "";
}
@ -140,20 +161,20 @@ public class BrandServiceImpl implements BrandService {
}
private void checkCode(Long id,String code){
if(FuncUtil.isNotEmpty(code)){
private void checkCode(Long id, String code) {
if (FuncUtil.isNotEmpty(code)) {
LambdaQueryWrapper<BrandDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.select(BrandDO::getId,BrandDO::getCode, BaseDO::getDeleted);
lambdaQueryWrapper.select(BrandDO::getId, BrandDO::getCode, BaseDO::getDeleted);
lambdaQueryWrapper.eq(BrandDO::getCode, code);
lambdaQueryWrapper.eq(BrandDO::getDeleted,false);
lambdaQueryWrapper.eq(BrandDO::getDeleted, false);
List<BrandDO> dos = brandMapper.selectList(lambdaQueryWrapper);
if(FuncUtil.isEmpty(id) && FuncUtil.isNotEmpty(dos)){
if (FuncUtil.isEmpty(id) && FuncUtil.isNotEmpty(dos)) {
throw exception(GlobalErrorCodeConstants.DATA_DUPLICATE);
}
if (FuncUtil.isNotEmpty(id) && FuncUtil.isNotEmpty(dos)) {
for (BrandDO aDo : dos) {
// 出现重复并当前id 不一致
if(!FuncUtil.equals(aDo.getId(), id)){
if (!FuncUtil.equals(aDo.getId(), id)) {
throw exception(GlobalErrorCodeConstants.DATA_DUPLICATE);
}
}

View File

@ -0,0 +1,35 @@
package cn.hangtag.module.oms.service.customer;
import cn.hangtag.framework.common.pojo.PageResult;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.AddressInfoVO;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.AddressInfoValidate;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.AddressReqVO;
/**
* 客户 Service 接口
*
* @author wwb
*/
public interface CustomerAddressService {
Long submit(AddressInfoValidate addressInfo);
void delById(Long id);
AddressInfoVO getAddressInfo(Long id);
/**
* 查询页
*
* @param vo vo
* @return {@link PageResult }<{@link AddressInfoVO }>
*/
PageResult<AddressInfoVO> queryPage(AddressReqVO vo);
/**
* 设置默认地址
*
* @param id ID
*/
void setDefaultAddress(Long id);
}

View File

@ -0,0 +1,144 @@
package cn.hangtag.module.oms.service.customer;
import cn.hangtag.framework.common.exception.ServiceException;
import cn.hangtag.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.hangtag.framework.common.pojo.PageParam;
import cn.hangtag.framework.common.pojo.PageResult;
import cn.hangtag.framework.common.util.FuncUtil;
import cn.hangtag.framework.common.util.SafeUseUtil;
import cn.hangtag.framework.common.util.object.BeanUtils;
import cn.hangtag.framework.common.util.validation.AssertUtil;
import cn.hangtag.framework.mybatis.build.MybatisPlusUtil;
import cn.hangtag.framework.mybatis.core.dataobject.BaseDO;
import cn.hangtag.framework.security.core.LoginUser;
import cn.hangtag.framework.security.core.util.SecurityFrameworkUtils;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.AddressInfoVO;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.AddressInfoValidate;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.AddressReqVO;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.CustomerInfoVO;
import cn.hangtag.module.oms.controller.admin.customer.vo.CustomerPageReqVO;
import cn.hangtag.module.oms.controller.admin.customer.vo.CustomerSaveReqVO;
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerAddressDO;
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerDO;
import cn.hangtag.module.oms.dal.mysql.customer.CustomerAddressMapper;
import cn.hangtag.module.oms.dal.mysql.customer.CustomerMapper;
import cn.hangtag.module.oms.serialnumber.CodingRulesUtils;
import cn.hangtag.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.hangtag.module.system.service.permission.PermissionService;
import cn.hangtag.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.*;
import static cn.hangtag.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.hangtag.module.oms.enums.ErrorCodeConstants.*;
/**
* 客户 Service 实现类
*
* @author wwb
*/
@Service
@Validated
@AllArgsConstructor
@Slf4j
public class CustomerAddressServiceImpl implements CustomerAddressService {
private CustomerAddressMapper customerAddressMapper;
private CustomerMapper customerMapper;
private CustomerService customerService;
@Override
public Long submit(AddressInfoValidate addressInfo) {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
CustomerDO customerDO = customerService.getCanUseCustomer(loginUser.getId());
// 客户档案可用
CustomerAddressDO addressDO = new CustomerAddressDO();
Long id = addressInfo.getId();
SafeUseUtil.copyProperties(addressInfo, addressDO);
addressDO.setCustomerId(customerDO.getId());
if(FuncUtil.isEmpty(id)){
customerAddressMapper.insert(addressDO);
id = addressDO.getId();
}else {
customerAddressMapper.updateById(addressDO);
}
if(addressDO.getIsDefault()){
setDefaultAddress(id);
}
return id;
}
@Override
public void delById(Long id) {
CustomerAddressDO addressDO = customerAddressMapper.selectById(id);
AssertUtil.isEmpty(addressDO, CUSTOMER_ADDRESS_NOT_EXISTS.getMsg());
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
CustomerDO customerDO = customerService.getCanUseCustomer(loginUser.getId());
Long customerId = addressDO.getCustomerId();
if(!FuncUtil.equals(customerDO, customerId)){
// 删除非本客户档案
throw exception(AUTH_USER_NOT_PERMISSION);
}
// 删除客户地址
customerAddressMapper.deleteById(id);
}
@Override
public AddressInfoVO getAddressInfo(Long id) {
CustomerAddressDO addressDO = customerAddressMapper.selectById(id);
AssertUtil.isEmpty(addressDO, CUSTOMER_ADDRESS_NOT_EXISTS.getMsg());
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
CustomerDO customerDO = customerService.getCanUseCustomer(loginUser.getId());
Long customerId = addressDO.getCustomerId();
if(!FuncUtil.equals(customerDO.getId(), customerId)){
// 非本客户档案
throw exception(AUTH_USER_NOT_PERMISSION);
}
return new AddressInfoVO(addressDO);
}
@Override
public PageResult<AddressInfoVO> queryPage(AddressReqVO vo) {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
CustomerDO customerDO = customerService.getCanUseCustomer(loginUser.getId());
PageParam pageParam = new PageParam();
pageParam.setPageNo(vo.getPageNo());
pageParam.setPageSize(vo.getPageSize());
vo.setCustomerId(customerDO.getId());
QueryWrapper<CustomerAddressDO> queryWrapper = MybatisPlusUtil.buildQueryFor("customerId@=,name@like,address@like,phone@like",
vo,
CustomerAddressDO.class, MybatisPlusUtil.defaultIgnoreFilters);
PageResult<CustomerAddressDO> result = customerAddressMapper.selectPage(pageParam, queryWrapper);
List<CustomerAddressDO> list = result.getList();
List<AddressInfoVO> addressInfos = new ArrayList<>();
for (CustomerAddressDO addressDO : list) {
addressInfos.add(new AddressInfoVO(addressDO));
}
PageResult<AddressInfoVO> result2 = new PageResult<>(addressInfos, result.getTotal());
return result2;
}
@Override
public void setDefaultAddress(Long id) {
CustomerAddressDO addressDO = customerAddressMapper.selectById(id);
AssertUtil.isEmpty(addressDO, CUSTOMER_ADDRESS_NOT_EXISTS.getMsg());
Long customerId = addressDO.getCustomerId();
customerAddressMapper.restDefaultAddress(customerId);
CustomerAddressDO addressDO1 = new CustomerAddressDO();
addressDO1.setId(id);
addressDO1.setIsDefault(true);
customerAddressMapper.updateById(addressDO1);
}
}

View File

@ -3,10 +3,10 @@ package cn.hangtag.module.oms.service.customer;
import java.util.*;
import javax.validation.*;
import cn.hangtag.module.oms.controller.admin.customer.vo.*;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.CustomerInfoVO;
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerDO;
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerAddressDO;
import cn.hangtag.framework.common.pojo.PageResult;
import cn.hangtag.framework.common.pojo.PageParam;
/**
* 客户 Service 接口
@ -65,4 +65,19 @@ public interface CustomerService {
CustomerDO getCustomerByUserId(Long userId);
/**
* 前台 带出查询登录客户信息 包含地址
*
* @param userId 用户id
* @return {@link CustomerInfoVO }
*/
CustomerInfoVO queryLoginCustomerInfo(Long userId);
/**
* 获取可以使用客户
*
* @param userId 用户id
* @return {@link CustomerDO }
*/
CustomerDO getCanUseCustomer(Long userId);
}

View File

@ -3,13 +3,20 @@ package cn.hangtag.module.oms.service.customer;
import cn.hangtag.framework.common.exception.ServiceException;
import cn.hangtag.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.hangtag.framework.common.util.FuncUtil;
import cn.hangtag.framework.common.util.SafeUseUtil;
import cn.hangtag.framework.common.util.validation.AssertUtil;
import cn.hangtag.framework.mybatis.build.MybatisPlusUtil;
import cn.hangtag.framework.mybatis.core.dataobject.BaseDO;
import cn.hangtag.module.oms.dal.dataobject.produceorder.ProduceOrderDO;
import cn.hangtag.framework.security.core.LoginUser;
import cn.hangtag.framework.security.core.util.SecurityFrameworkUtils;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.AddressInfoVO;
import cn.hangtag.module.oms.controller.admin.customer.front.vo.CustomerInfoVO;
import cn.hangtag.module.oms.serialnumber.CodingRulesUtils;
import cn.hangtag.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.hangtag.module.system.service.permission.PermissionService;
import cn.hangtag.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
@ -23,7 +30,6 @@ import cn.hangtag.module.oms.controller.admin.customer.vo.*;
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerDO;
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerAddressDO;
import cn.hangtag.framework.common.pojo.PageResult;
import cn.hangtag.framework.common.pojo.PageParam;
import cn.hangtag.framework.common.util.object.BeanUtils;
import cn.hangtag.module.oms.dal.mysql.customer.CustomerMapper;
@ -172,6 +178,31 @@ public class CustomerServiceImpl implements CustomerService {
return customerDO;
}
@Override
public CustomerInfoVO queryLoginCustomerInfo(Long userId) {
CustomerDO customerDO = customerMapper.selectOne(CustomerDO::getUserId, userId);
String status = customerDO.getStatus();
if("0".equals(status)){
throw exception(CUSTOMER_LOGIN_STATUS_DISABLE);
}
CustomerInfoVO infoVO = new CustomerInfoVO();
SafeUseUtil.copyProperties(customerDO,infoVO);
CustomerAddressDO addressDO = new CustomerAddressDO();
addressDO.setCustomerId(customerDO.getId());
addressDO.setDeleted(false);
QueryWrapper<CustomerAddressDO> queryWrapper = MybatisPlusUtil.buildQuery(addressDO);
queryWrapper.orderByDesc("is_default");
List<CustomerAddressDO> list = customerAddressMapper.selectList(queryWrapper);
List<AddressInfoVO> addressInfos = new ArrayList<>();
for (CustomerAddressDO aDo : list) {
AddressInfoVO infoVO1 = new AddressInfoVO(aDo);
addressInfos.add(infoVO1);
}
infoVO.setAddressList(addressInfos);
return infoVO;
}
private void createCustomerAddressList(Long customerId, List<CustomerAddressDO> list) {
list.forEach(o -> o.setCustomerId(customerId));
customerAddressMapper.insertBatch(list);
@ -230,4 +261,23 @@ public class CustomerServiceImpl implements CustomerService {
}
}
/**
* 获取可以使用客户
*
* @param userId 用户id
* @return {@link CustomerDO }
*/
@Override
public CustomerDO getCanUseCustomer(Long userId) {
LambdaQueryWrapper<CustomerDO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(CustomerDO::getUserId, userId);
queryWrapper.eq(CustomerDO::getDeleted, false);
queryWrapper.orderByDesc(BaseDO::getCreateTime);
CustomerDO customerDO = customerMapper.selectOne(queryWrapper,false);
AssertUtil.isEmpty(customerDO,CUSTOMER_NOT_EXISTS.getMsg());
String status = customerDO.getStatus();
AssertUtil.isFalse(status.equals("1"), CUSTOMER_LOGIN_STATUS_DISABLE.getMsg());
return customerDO;
}
}

View File

@ -53,4 +53,12 @@ public interface DraftDesignDataService {
PageResult<DraftDesignDataDO> getDraftDesignDataPage(DraftDesignDataPageReqVO pageReqVO);
String getNewCode();
/**
* 更新产品计数
*
* @param id ID
* @return {@link Integer }
*/
Boolean updateProductCount(String id);
}

View File

@ -3,21 +3,23 @@ package cn.hangtag.module.oms.service.draftdesigndata;
import cn.hangtag.framework.common.exception.ServiceException;
import cn.hangtag.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.hangtag.framework.common.util.FuncUtil;
import cn.hangtag.framework.mybatis.build.MybatisPlusUtil;
import cn.hangtag.framework.mybatis.core.dataobject.BaseDO;
import cn.hangtag.module.oms.dal.dataobject.brand.BrandDO;
import cn.hangtag.module.oms.dal.dataobject.productinfo.ProductInfoDO;
import cn.hangtag.module.oms.dal.mysql.productinfo.ProductInfoMapper;
import cn.hangtag.module.oms.serialnumber.CodingRulesUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.hangtag.module.oms.controller.admin.draftdesigndata.vo.*;
import cn.hangtag.module.oms.dal.dataobject.draftdesigndata.DraftDesignDataDO;
import cn.hangtag.framework.common.pojo.PageResult;
import cn.hangtag.framework.common.pojo.PageParam;
import cn.hangtag.framework.common.util.object.BeanUtils;
import cn.hangtag.module.oms.dal.mysql.draftdesigndata.DraftDesignDataMapper;
@ -33,10 +35,11 @@ import static cn.hangtag.module.oms.enums.ErrorCodeConstants.*;
@Service
@Validated
@Slf4j
@AllArgsConstructor
public class DraftDesignDataServiceImpl implements DraftDesignDataService {
@Resource
private DraftDesignDataMapper draftDesignDataMapper;
private final DraftDesignDataMapper draftDesignDataMapper;
private final ProductInfoMapper productInfoMapper;
@Override
public Long createDraftDesignData(DraftDesignDataSaveReqVO createReqVO) {
@ -98,6 +101,27 @@ public class DraftDesignDataServiceImpl implements DraftDesignDataService {
return draftDesignDataMapper.selectPage(pageReqVO);
}
@Override
public Boolean updateProductCount(String id) {
List<Long> list = FuncUtil.toLongList(",", id);
for (Long draftId : list) {
ProductInfoDO productInfoDO = new ProductInfoDO();
productInfoDO.setDraftDesignDataId(draftId.toString());
QueryWrapper<ProductInfoDO> queryWrapper = MybatisPlusUtil.buildQuery("draft_design_data_id@inSet", productInfoDO);
Long l = productInfoMapper.selectCount(queryWrapper);
int count = FuncUtil.toInt(l, 0);
// 更新数量
DraftDesignDataDO designDataDO = new DraftDesignDataDO();
designDataDO.setId(draftId);
designDataDO.setProductCount(count);
draftDesignDataMapper.updateById(designDataDO);
}
return true;
}
@Override
public String getNewCode() {
String s = "";

View File

@ -1,11 +1,12 @@
package cn.hangtag.module.oms.service.productinfo;
import java.util.*;
import javax.validation.*;
import cn.hangtag.framework.mybatis.build.QueryFilterInfo;
import cn.hangtag.module.oms.controller.admin.productinfo.vo.*;
import cn.hangtag.module.oms.dal.dataobject.productinfo.ProductInfoDO;
import cn.hangtag.framework.common.pojo.PageResult;
import cn.hangtag.framework.common.pojo.PageParam;
/**
* 产品资料 Service 接口
@ -52,6 +53,8 @@ public interface ProductInfoService {
*/
PageResult<ProductInfoDO> getProductInfoPage(ProductInfoPageReqVO pageReqVO);
PageResult<ProductInfoDO> queryPage(QueryFilterInfo<ProductInfoPageReqVO> queryFilterInfo);
/**
* 获取编码
*

View File

@ -3,6 +3,8 @@ package cn.hangtag.module.oms.service.productinfo;
import cn.hangtag.framework.common.exception.ServiceException;
import cn.hangtag.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.hangtag.framework.common.util.FuncUtil;
import cn.hangtag.framework.mybatis.build.QueryFilterInfo;
import cn.hangtag.framework.mybatis.core.dataobject.BaseDO;
import cn.hangtag.module.oms.base.dal.dataobject.producttype.ProductTypeDO;
import cn.hangtag.module.oms.base.dal.mysql.producttype.ProductTypeMapper;
@ -14,7 +16,11 @@ import cn.hangtag.module.oms.dal.dataobject.productprocess.ProductProcessDO;
import cn.hangtag.module.oms.dal.mysql.brand.BrandMapper;
import cn.hangtag.module.oms.dal.mysql.productprocess.ProductProcessMapper;
import cn.hangtag.module.oms.serialnumber.CodingRulesUtils;
import cn.hangtag.module.oms.service.brand.BrandService;
import cn.hangtag.module.oms.service.draftdesigndata.DraftDesignDataService;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@ -51,8 +57,11 @@ public class ProductInfoServiceImpl implements ProductInfoService {
private final BrandMapper brandMapper;
private final ProductTypeMapper productTypeMapper;
private final ProductProcessMapper productProcessMapper;
private final BrandService brandService;
private final DraftDesignDataService draftDesignDataService;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createProductInfo(ProductInfoSaveReqVO createReqVO) {
// 插入
ProductInfoDO productInfo = BeanUtils.toBean(createReqVO, ProductInfoDO.class);
@ -77,13 +86,17 @@ public class ProductInfoServiceImpl implements ProductInfoService {
}
productProcessMapper.insertBatch(subList);
}
brandService.updateProductCount(productInfo.getBrandId());
draftDesignDataService.updateProductCount(productInfo.getDraftDesignDataId());
return productInfo.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateProductInfo(ProductInfoSaveReqVO updateReqVO) {
// 校验存在
validateProductInfoExists(updateReqVO.getId());
ProductInfoDO productInfoDO = validateProductInfoExists(updateReqVO.getId());
String code = updateReqVO.getCode();
if(FuncUtil.isNotEmpty(code)){
@ -118,20 +131,35 @@ public class ProductInfoServiceImpl implements ProductInfoService {
// 更新
ProductInfoDO updateObj = BeanUtils.toBean(updateReqVO, ProductInfoDO.class);
productInfoMapper.updateById(updateObj);
if (!FuncUtil.equals(productInfoDO.getBrandId(),updateReqVO.getBrandId())) {
// 产品的品牌发生变化时
brandService.updateProductCount(updateReqVO.getBrandId());
brandService.updateProductCount(productInfoDO.getBrandId());
}
if (!FuncUtil.equals(productInfoDO.getDraftDesignDataId(),updateReqVO.getDraftDesignDataId())) {
// 产品的品牌发生变化时
draftDesignDataService.updateProductCount(productInfoDO.getDraftDesignDataId());
draftDesignDataService.updateProductCount(updateReqVO.getDraftDesignDataId());
}
}
@Override
public void deleteProductInfo(Long id) {
// 校验存在
validateProductInfoExists(id);
ProductInfoDO productInfoDO = validateProductInfoExists(id);
// 删除
productInfoMapper.deleteById(id);
brandService.updateProductCount(productInfoDO.getBrandId());
draftDesignDataService.updateProductCount(productInfoDO.getDraftDesignDataId());
}
private void validateProductInfoExists(Long id) {
if (productInfoMapper.selectById(id) == null) {
private ProductInfoDO validateProductInfoExists(Long id) {
ProductInfoDO productInfoDO = productInfoMapper.selectById(id);
if (productInfoDO == null) {
throw exception(PRODUCT_INFO_NOT_EXISTS);
}
return productInfoDO;
}
@Override
@ -161,7 +189,30 @@ public class ProductInfoServiceImpl implements ProductInfoService {
return productInfoDOPageResult;
}
private void checkCode(Long id,String code){
@Override
public PageResult<ProductInfoDO> queryPage(QueryFilterInfo<ProductInfoPageReqVO> queryFilterInfo) {
PageResult<ProductInfoDO> productInfoDOPageResult = productInfoMapper.selectPagePlus(queryFilterInfo);
List<ProductInfoDO> list = productInfoDOPageResult.getList();
list.forEach(productInfoDO -> {
if(FuncUtil.isNotEmpty(productInfoDO.getBrandId())){
BrandDO brandDO = brandMapper.selectById(productInfoDO.getBrandId());
if(FuncUtil.isNotEmpty(brandDO)){
productInfoDO.setBrandName(brandDO.getName());
}
}
if(FuncUtil.isNotEmpty(productInfoDO.getProductTypeId())){
ProductTypeDO productTypeDO = productTypeMapper.selectById(productInfoDO.getProductTypeId());
if(FuncUtil.isNotEmpty(productTypeDO)){
productInfoDO.setProductTypeName(productTypeDO.getLabel());
}
}
});
productInfoDOPageResult.setList(list);
return productInfoDOPageResult;
}
private void checkCode(Long id, String code){
if(FuncUtil.isNotEmpty(code)){
LambdaQueryWrapper<ProductInfoDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.select(ProductInfoDO::getId,ProductInfoDO::getCode, BaseDO::getDeleted);

View File

@ -6,7 +6,7 @@ import javax.servlet.http.HttpServletResponse;
import javax.validation.*;
import cn.hangtag.module.oms.controller.admin.common.vo.DataComparisonRespVO;
import cn.hangtag.module.oms.controller.admin.saleorder.dto.CreateSaleOrderDTO;
import cn.hangtag.module.oms.controller.admin.saleorder.front.dto.CreateSaleOrderDTO;
import cn.hangtag.module.oms.controller.admin.saleorder.vo.*;
import cn.hangtag.module.oms.controller.admin.trade.vo.TradeOrderSummaryRespVO;
import cn.hangtag.module.oms.controller.admin.trade.vo.TradeOrderTrendReqVO;

View File

@ -14,9 +14,9 @@ import cn.hangtag.module.oms.common.utils.WKHtmlToPdfUtil;
import cn.hangtag.module.oms.controller.admin.common.vo.DataComparisonRespVO;
import cn.hangtag.module.oms.controller.admin.produceorder.vo.ProduceOrderSaveReqVO;
import cn.hangtag.module.oms.controller.admin.product.vo.ProductPriceSaveReqVO;
import cn.hangtag.module.oms.controller.admin.saleorder.dto.CreateSaleOrderDTO;
import cn.hangtag.module.oms.controller.admin.saleorder.dto.SaleOrderEntryItemDTO;
import cn.hangtag.module.oms.controller.admin.saleorder.dto.SaleOrderSkuDTO;
import cn.hangtag.module.oms.controller.admin.saleorder.front.dto.CreateSaleOrderDTO;
import cn.hangtag.module.oms.controller.admin.saleorder.front.dto.SaleOrderEntryItemDTO;
import cn.hangtag.module.oms.controller.admin.saleorder.front.dto.SaleOrderSkuDTO;
import cn.hangtag.module.oms.controller.admin.saleorder.vo.SaleOrderPageReqVO;
import cn.hangtag.module.oms.controller.admin.saleorder.vo.SaleOrderRemarkReqVO;
import cn.hangtag.module.oms.controller.admin.saleorder.vo.SaleOrderSaveReqVO;
@ -52,8 +52,6 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -66,7 +64,6 @@ import org.springframework.validation.annotation.Validated;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.File;

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.hangtag.module.oms.dal.mysql.customer.CustomerAddressMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
<update id="restDefaultAddress" parameterType="java.lang.Long">
update oms_customer_address set is_default = 0 where customer_id = #{customerId}
</update>
</mapper>

View File

@ -16,6 +16,7 @@ public interface ErrorCodeConstants {
ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_002_000_005, "未绑定账号,需要进行绑定");
ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1_002_000_006, "Token 已经过期");
ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1_002_000_007, "手机号不存在");
ErrorCode AUTH_USER_NOT_PERMISSION = new ErrorCode(1_002_000_008, "没有相关权限");
// ========== 菜单模块 1-002-001-000 ==========
ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1_002_001_000, "已经存在该名字的菜单");

View File

@ -1,4 +1,5 @@
import request from '@/config/axios'
import {data} from "autoprefixer";
// 产品资料 VO
export interface ProductInfoVO {
@ -26,6 +27,10 @@ export const ProductInfoApi = {
getProductInfoPage: async (params: any) => {
return await request.get({ url: `/oms/product-info/page`, params })
},
// 查询产品资料 分页
queryPage: async (params: any) => {
return await request.post({ url: `/oms/product-info/query`, data:{...params}})
},
// 查询产品资料 详情
getProductInfo: async (id: number) => {

View File

@ -57,34 +57,37 @@
v-loading="loading"
:src="that.previewUrl"/>
</div>
<div style="width: 100%" v-if="that.propOrderByList && that.propOrderByList.length > 0">
<el-scrollbar height="600px">
<el-form label-width="180px">
<el-form-item label="风格主题" v-show="that.draftDesignList.length > 1">
<div class="flex ml-3">
<div>
<el-select class="min-w-100" v-model="that.draftDesignId" @change="changeType">
<el-option
v-for="(item) in that.draftDesignList"
:key="item.id"
:label="item.label"
:value="item.id"
/>
</el-select>
<div class="flex flex-col">
<div>
<el-form label-width="180px">
<el-form-item label="风格样式" v-show="that.draftDesignList.length > 1">
<div class="flex ml-3">
<div>
<el-select class="min-w-100" v-model="that.draftDesignId" @change="changeType">
<el-option
v-for="(item) in that.draftDesignList"
:key="item.id"
:label="item.label"
:value="item.id"
/>
</el-select>
</div>
</div>
</div>
</el-form-item>
<el-form-item
v-for="(tmp) in that.propOrderByList"
:key="tmp.key"
:label="getLabelName(that.propInfo[tmp.key])">
<div
v-if="that.propInfo[tmp.key].multiLanguage && that.propInfo[tmp.key].shape === ShapeType.vueTextCell">
<div
style="padding: 4px">
<div style="display: flex;align-items: center;">
</el-form-item>
</el-form>
</div>
<div style="width: 100%" v-if="that.propOrderByList && that.propOrderByList.length > 0">
<el-scrollbar height="600px">
<el-form label-width="180px">
<el-form-item
v-for="(tmp) in that.propOrderByList"
:key="tmp.key"
:label="getLabelName(that.propInfo[tmp.key])">
<div
v-if="that.propInfo[tmp.key].multiLanguage && that.propInfo[tmp.key].shape === ShapeType.vueTextCell">
<div
style="padding: 4px">
<div style="display: flex;align-items: center;">
<span>
<i
v-if="that.propInfo[tmp.key].canInput"
@ -93,56 +96,56 @@
<i v-else class="icon-lk_cell_add" style="font-size: 20px"> </i>
</span>
<el-select-v2
v-model="that.propInfo[tmp.key].dataInfo[0].showLabel"
filterable
:options="getIngredientInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeData(-1,tmp.key)"
size="large"
style="min-width: 280px;width: 100%"
/>
<div v-if="that.propInfo[tmp.key].groupType === '1'">
<div
style="display: flex;align-items: center; margin-left: 10px; width: 220px">
<el-row>
<el-col span="4">
<div>占比</div>
</el-col>
<el-col span="14">
<el-input-number
:min="-1" :max="100"
v-model="that.propInfo[tmp.key].dataInfo[0].ratio"
@change="changeData(0,tmp.key)"
/>
</el-col>
<el-col span="4">
<div> %</div>
</el-col>
</el-row>
<el-select-v2
v-model="that.propInfo[tmp.key].dataInfo[0].showLabel"
filterable
:options="getIngredientInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeData(-1,tmp.key)"
size="large"
style="min-width: 280px;width: 100%"
/>
<div v-if="that.propInfo[tmp.key].groupType === '1'">
<div
style="display: flex;align-items: center; margin-left: 10px; width: 220px">
<el-row>
<el-col span="4">
<div>占比</div>
</el-col>
<el-col span="14">
<el-input-number
:min="-1" :max="100"
v-model="that.propInfo[tmp.key].dataInfo[0].ratio"
@change="changeData(0,tmp.key)"
/>
</el-col>
<el-col span="4">
<div> %</div>
</el-col>
</el-row>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
</el-button>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
</div>
<div v-else-if="!that.propInfo[tmp.key].isCombo">
<div
v-for="(text,index) in that.propInfo[tmp.key].dataInfo"
:key="index"
style="padding: 4px">
<div style="display: flex;align-items: center;">
<div v-else-if="!that.propInfo[tmp.key].isCombo">
<div
v-for="(text,index) in that.propInfo[tmp.key].dataInfo"
:key="index"
style="padding: 4px">
<div style="display: flex;align-items: center;">
<span>
<i
v-if="that.propInfo[tmp.key].canInput"
@ -150,111 +153,113 @@
style="font-size: 20px"> </i>
<i v-else class="icon-lk_cell_add" style="font-size: 20px"> </i>
</span>
<el-autocomplete
v-if="that.propInfo[tmp.key].canInput"
v-model="that.propInfo[tmp.key].dataInfo[index].showLabel"
:fetch-suggestions="querySearch"
clearable
class="inline-input w-50"
placeholder="Please Input"
@change="changeData"
@select="changeData"
/>
<el-autocomplete
v-if="that.propInfo[tmp.key].canInput"
v-model="that.propInfo[tmp.key].dataInfo[index].showLabel"
:fetch-suggestions="querySearch"
clearable
class="inline-input w-50"
placeholder="Please Input"
@change="changeData"
@select="changeData"
/>
<el-select-v2
v-else
v-model="that.propInfo[tmp.key].dataInfo[index].showLabel"
filterable
:options="getIngredientInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeData(index,tmp.key)"
size="large"
style="min-width: 280px;width: 100%"
/>
<div v-if="that.propInfo[tmp.key].groupType === '1'">
<el-select-v2
v-else
v-model="that.propInfo[tmp.key].dataInfo[index].showLabel"
filterable
:options="getIngredientInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeData(index,tmp.key)"
size="large"
style="min-width: 280px;width: 100%"
/>
<div v-if="that.propInfo[tmp.key].groupType === '1'">
<div
style="display: flex;align-items: center; margin-left: 10px; width: 220px">
<el-row>
<el-col span="4">
<div>占比</div>
</el-col>
<el-col span="14">
<el-input-number
:min="-1" :max="100"
v-model="that.propInfo[tmp.key].dataInfo[index].ratio"
@change="changeData(index,tmp.key)"
/>
</el-col>
<el-col span="4">
<div> %</div>
</el-col>
</el-row>
<div
style="display: flex;align-items: center; margin-left: 10px; width: 220px">
<el-row>
<el-col span="4">
<div>占比</div>
</el-col>
<el-col span="14">
<el-input-number
:min="-1" :max="100"
v-model="that.propInfo[tmp.key].dataInfo[index].ratio"
@change="changeData(index,tmp.key)"
/>
</el-col>
<el-col span="4">
<div> %</div>
</el-col>
</el-row>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
</el-button>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
</div>
<div v-else-if="that.propInfo[tmp.key].shape === ShapeType.vueShapeImage">
<div
v-for="(img,index) in that.propInfo[tmp.key].dataInfo"
:key="index" style="display: flex">
<div class="img-box" v-if="img.url">
<div style="display: flex">
<img :src="img.url" width="60px" height="60px"/>
<el-select-v2
v-model="that.propInfo[tmp.key].dataInfo[0].showLabel"
filterable
:options="washingInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeComboData(that.propInfo[tmp.key],that.propInfo[tmp.key].dataInfo[0].showLabel)"
size="large"
style="min-width: 280px;width: 100%"
>
<template #default="{ item }">
<div style="display: flex;">
<img :src="item.url" width="30px" height="30px"/>
<span>
<div v-else-if="that.propInfo[tmp.key].shape === ShapeType.vueShapeImage">
<div
v-for="(img,index) in that.propInfo[tmp.key].dataInfo"
:key="index" style="display: flex">
<div class="img-box" v-if="img.url">
<div style="display: flex">
<img :src="img.url" width="60px" height="60px"/>
<el-select-v2
v-model="that.propInfo[tmp.key].dataInfo[0].showLabel"
filterable
:options="washingInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeComboData(that.propInfo[tmp.key],that.propInfo[tmp.key].dataInfo[0].showLabel)"
size="large"
style="min-width: 280px;width: 100%"
>
<template #default="{ item }">
<div style="display: flex;">
<img :src="item.url" width="30px" height="30px"/>
<span>
{{ item.label }}
</span>
</div>
</template>
</el-select-v2>
</div>
</template>
</el-select-v2>
</div>
</div>
<div v-else-if="img.label">
<el-input v-model="img.label" disabled/>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
</el-button>
</div>
</div>
<div v-else-if="img.label">
<el-input v-model="img.label" disabled/>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
</el-button>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
</div>
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</div>
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</div>
</div>
<div
@ -520,7 +525,7 @@ const previewByProductId = async (id: string | number, propData = {}, defDraftDe
console.log("prodRes", prodRes)
that.draftDesignList = JSON.parse(prodRes.draftDesignList, '[]')
that.draftDesignId = defDraftDesignId || prodRes.draftDesignDataId
await previewByDraftDesignId(that.draftDesignId, propData)
await previewByDraftDesignId(that.draftDesignId.split(',')[0], propData)
}
}
const loadConfig = (config: object, propData = {}) => {

View File

@ -162,7 +162,7 @@ const uploadInfo = async ()=>{
}
const addNew = async () => {
for (let i = 0; i < fileList.value.length; i++) {
const base64Info = await convertImageToBase64(fileList.value[i].url as string)
// const base64Info = await convertImageToBase64(fileList.value[i].url as string)
let info ={
key: ShapeType.vueShapeImage,
shape: ShapeType.vueShapeImage,
@ -173,11 +173,11 @@ const addNew = async () => {
shape: VueCellShapeType.Image,
style: {
shape:{
href: base64Info,
href: fileList.value[i].url,
},
}
},
icon: base64Info,
icon: fileList.value[i].url,
//@ts-ignore
label: fileList.value[i].filename || '未命名图片',
filterKeyword: function (){ return this.label }

View File

@ -9,14 +9,14 @@
>
<template #title>
<div>
Setting
页面配置
</div>
</template>
<template #default>
<el-form>
<div>
<div>
<el-form-item label="backgroundColor">
<el-form-item label="背景颜色">
<ColorPickerTool
v-model="that.pageConfig.background.areaColor"
:uuid="`background.areaColor`"
@ -26,21 +26,21 @@
</el-form-item>
</div>
<div>
<div style="width: 150px;">
<div>
width
<div style="width: 300px;">
<div style="display: flex;align-items: center">
<span style="padding: 4px"></span>
<el-input-number
v-model="that.pageConfig.editArea.width"
@change="changePageConfig"/>
@change="changePageConfig"/>mm
</div>
<div>
height
<div style="display: flex;align-items: center">
<span style="padding: 4px"></span>
<el-input-number
v-model="that.pageConfig.editArea.height"
@change="changePageConfig"/>
@change="changePageConfig"/>mm
</div>
<div>
onLoadZoom
<div style="display: flex;align-items: center">
<div style="padding: 4px">加载缩放比</div>
<el-input-number
:min="0.1"
:max="10"
@ -132,7 +132,7 @@
<div
style="margin-left: 6px;display: flex;flex-wrap: wrap;align-items: center;height: 100%;max-width: 900px">
<div>
<el-button @click="that.showDialog = true" :title="Setting">Settings</el-button>
<el-button @click="that.showDialog = true" title="页面设置">页面设置</el-button>
</div>
<div>
<el-button @click="that.showOrderByDialog= true" :title="'属性排序'">
@ -298,7 +298,7 @@
:width="60"
:effect="that.effect"
trigger="hover"
content="FillColor"
content="填充颜色"
>
<template #reference>
<div>
@ -324,7 +324,7 @@
:width="60"
:effect="that.effect"
trigger="hover"
content="lineColor"
content="边框颜色"
>
<template #reference>
<div>

View File

@ -12,13 +12,12 @@
transform-origin: left top;
transform: scale(0.1); "
:style="svgStyle"
>
<image
:href="cellInfo.style.shape.href" x="0" y="0"
:href="hrefBase64 || cellInfo.style.shape.href" x="0" y="0"
style="width: 100%;height: 100%;"
:stroke="cellInfo.style.shape.strokeColor"
:stroke-width="cellInfo.style.shape.strokeWidth"
:fill="cellInfo.style.shape.fillColor"
:fill-opacity="cellInfo.style.shape.fillOpacity"
:stroke-dasharray="cellInfo.style.shape.strokeDasharray"
:stroke-dashoffset="cellInfo.style.shape.strokeDashoffset"
@ -27,7 +26,6 @@
:clip-path="cellInfo.style.shape.clipPath"
:filter="cellInfo.style.shape.filter"
/>
</svg>
</div>
</template>
@ -60,11 +58,12 @@ export default defineComponent({
svgStyle() {
const res = {
borderRadius: '',
backgroundColor : this.cellInfo.style.shape.fillColor || "",
width: `1000px`,
height: `1000px`,
transform: ''
}
const tmp = Math.min(this.sizeWInfo.width, this.sizeWInfo.height) - (this.cellInfo.style.shape.strokeWidth * 2)
// const tmp = Math.min(this.sizeWInfo.width, this.sizeWInfo.height) - (this.cellInfo.style.shape.strokeWidth * 2)
const w = (Math.max(this.sizeWInfo.width, 0)) / 1000;
const h = (Math.max(this.sizeWInfo.height, 0)) / 1000;
res.transform = `scaleX(${w}) scaleY(${h})`
@ -108,7 +107,7 @@ export default defineComponent({
y: 0, // y
rx: 0, // x
ry: 0, // y
fillColor: '#000000', //
fillColor: '', //
fillOpacity: '', //
href: '',
hrefBase64: null,
@ -116,8 +115,6 @@ export default defineComponent({
strokeDashoffset: '', // 线
strokeLinecap: undefined, // 线"round" | "butt" | "square" | "inherit" | undefined
strokeLinejoin: undefined, // 线"round" | "inherit" | "miter" | "bevel" | undefined
strokeColor: '', //
strokeWidth: 0, //
strokeDasharray: '', // 线
bottom: 0, //
transform: '', //
@ -246,8 +243,6 @@ export default defineComponent({
strokeDashoffset: '', // 线
strokeLinecap: undefined, // 线"round" | "butt" | "square" | "inherit" | undefined
strokeLinejoin: undefined, // 线"round" | "inherit" | "miter" | "bevel" | undefined
strokeColor: '#000000', //
strokeWidth: 0, //
strokeDasharray: '', // 线
bottom: 0, //
transform: '', //
@ -261,6 +256,7 @@ export default defineComponent({
if(this.cellInfo.style.shape.href){
convertImageToBase64(this.cellInfo.style.shape.href).then((res)=>{
// @ts-ignore
// this.hrefBase64 = res
this.cellInfo.style.shape.href = res
})
}

View File

@ -0,0 +1,22 @@
// filterConfig 格式name@like
export const buildQuery = (params: object, options={}) => {
const query = {
"pager": {
pageNo: params.pageNo || 1,
pageSize: params.pageSize || 10
},
config:{
"keywordSearch": "", // 搜索关键字 张三
"keywordFields": "", // 搜索字段 name,code,summary
"orderBy": "", // age desc;name asc
...options,
},
"filter": {
...params
}
}
console.log("@@@@",query)
return query;
}

View File

@ -98,25 +98,70 @@
<dict-tag :type="DICT_TYPE.BRAND_INDUSTRY_FIELD" :value="scope.row.brandField" />
</template>
</el-table-column>
<el-table-column
v-hasPermi="['oms:product-info:create']"
label="产品数量" align="center" prop="brandField">
<template #default="scope">
<router-link v-if="scope.row.productCount > 0"
:to="'/base/product-info?brandId='+ scope.row.id">
<el-button
link
type="primary">
{{scope.row.productCount}}
</el-button>
</router-link>
<router-link v-else :to="'/base/product-info?brandId='+scope.row.id+'&_add=1'">
<el-button
link
type="primary">
{{scope.row.productCount}}
</el-button>
</router-link>
</template>
</el-table-column>
<el-table-column label="官网" align="center" prop="website" />
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['oms:brand:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['oms:brand:delete']"
>
删除
</el-button>
<div class="flex">
<div>
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['oms:brand:update']"
>
编辑
</el-button>
</div>
<div v-hasPermi="['oms:product-info:create']">
<router-link v-if="scope.row.productCount > 0 "
:to="'/base/product-info?brandId='+ scope.row.id">
<el-button
link
type="primary">
管理产品
</el-button>
</router-link>
<router-link v-else :to="'/base/product-info?brandId='+scope.row.id+'&_add=1'">
<el-button
link
type="primary">
新增产品
</el-button>
</router-link>
</div>
<div>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['oms:brand:delete']"
>
删除
</el-button>
</div>
</div>
</template>
</el-table-column>
</el-table>

View File

@ -92,6 +92,20 @@
<el-table-column label="id" align="center" prop="id" />
<el-table-column label="编码" align="center" prop="code" width="200" />
<el-table-column label="设计稿名称" align="center" prop="name" />
<el-table-column
v-hasPermi="['oms:product-info:create']"
label="使用数量" align="center" prop="brandField">
<template #default="scope">
<router-link
:to="'/base/product-info?draftDesignDataId='+ scope.row.id">
<el-button
link
type="primary">
{{scope.row.productCount}}
</el-button>
</router-link>
</template>
</el-table-column>
<el-table-column label="作者" align="center" prop="author" />
<el-table-column label="启用状态" align="center" prop="enabled">
<template #default="scope">

View File

@ -133,7 +133,7 @@
</div>
</template>
<template #default="scope">
<el-input v-model="scope.row.label" placeholder="请输入风格主色名称"/>
<el-input name="auto_input@draftDesignList_label" autocomplete="on" clearable v-model="scope.row.label" placeholder="请输入风格主色名称"/>
</template>
</el-table-column>
<el-table-column prop="remark">
@ -143,7 +143,7 @@
</div>
</template>
<template #default="scope">
<el-input v-model="scope.row.remark" placeholder="备注说明"/>
<el-input clearable v-model="scope.row.remark" placeholder="备注说明"/>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
@ -251,6 +251,7 @@ import BrandDataListDialog from "@/components/Dialog/src/BrandDataListDialog/ind
/** 产品资料 表单 */
defineOptions({name: 'ProductInfoForm'})
const route = useRoute() //
const {t} = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
@ -275,7 +276,9 @@ const formData = ref({
specSizeThk: 0,
specMaterial: '',
})
const that = reactive({
brandId: undefined,
draftDesignList: [{
remark: '',
label: '',
@ -294,7 +297,7 @@ const that = reactive({
const addRow = () => {
that.draftDesignList.push({
remark: '',
label: '',
label: '默认'+Math.random().toString(36).substring(2, 5),
id: ''
})
}
@ -356,6 +359,7 @@ const open = async (type: string, id?: number) => {
type = type ? type : 'create'
dialogTitle.value = t('action.' + type)
formType.value = type
that.brandId = route.query.brandId
resetForm()
//
if (id) {
@ -454,7 +458,7 @@ const submitForm = async () => {
data.draftDesignList = JSON.stringify(that.draftDesignList)
// 稿
data.draftDesignDataId = ids[0];
data.draftDesignDataId = ids.join(",");
if (formType.value === 'create') {
await ProductInfoApi.createProductInfo(data as ProductInfoVO)
message.success(t('common.createSuccess'))
@ -495,7 +499,7 @@ const resetForm = () => {
code: undefined,
name: undefined,
cover: undefined,
brandId: '',
brandId: that.brandId || '',
productTypeId: '',
draftDesignDataId: undefined,
draftDesignList: '',

View File

@ -60,6 +60,9 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item label="稿件" prop="remark">
<DraftDesignDataListDialog v-model="queryParams.draftDesignDataId"/>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
@ -180,13 +183,14 @@ import download from '@/utils/download'
import {ProductInfoApi, ProductInfoVO} from '@/api/oms/productinfo'
import ProductInfoForm from './ProductInfoForm.vue'
import {ProductTypeApi} from "@/api/base/producttype";
import {buildQuery} from "@/utils/queryUtil";
/** 产品资料 列表 */
defineOptions({name: 'ProductInfo'})
const message = useMessage() //
const {t} = useI18n() //
const route = useRoute() //
const designPreviewDialogRef = ref()
const loading = ref(true) //
const list = ref<ProductInfoVO[]>([]) //
@ -205,6 +209,7 @@ const queryParams = reactive({
details: undefined,
createTime: [],
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
@ -212,7 +217,12 @@ const exportLoading = ref(false) // 导出的加载中
const getList = async () => {
loading.value = true
try {
const data = await ProductInfoApi.getProductInfoPage(queryParams)
const data = await ProductInfoApi.queryPage(buildQuery(queryParams,{
easyOption: "create_time@between,name@like,code@like,draftDesignDataId@inSet",
orderBy: 'create_time desc',
ignoreField: "pageNo,pageSize"
}))
// const data = await ProductInfoApi.queryPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
@ -285,8 +295,20 @@ const init = async () => {
})
})
}
let first_load = true;
/** 初始化 **/
onMounted(() => {
if(first_load){
first_load = false;
queryParams.brandId = route.query.brandId
queryParams.draftDesignDataId = route.query.draftDesignDataId
const tmp = route.query._add
if(tmp == 1){
// url
openForm('create')
}
}
getList();
init();
})

View File

@ -0,0 +1,37 @@
import request from '@/config/axios'
import {i18n} from "@/plugins/vueI18n";
import {useAppStore} from "@/store/modules/app";
const appStore = useAppStore()
// 地址 API
export const AddressApi = {
// 获取当前用户的地址列表
getCustomerAddressList: async (params: any) => {
return await request.get({ url: `/front/oms/address/page`,params })
},
delAddress: async (id: number) => {
return await request.delete({ url: `/front/oms/address/${id}` })
},
getAddressInfo: async (id: number) => {
return await request.get({ url: `/front/oms/address/${id}`})
},
setDefaultAddress: async (id: number) => {
return await request.put({ url: `/front/oms/address/default/${id}`})
},
// 提交表单数据
submit: async (data: any) => {
return await request.post({ url: `/front/oms/address/submit`, data })
},
getAreaTree: async () => {
let type = 0;
try {
type = i18n.global.locale.value == "zh-CN" ? "1" : "0"
}catch (e) {
}
return await request.get({ url: '/front/oms/address/area-tree/'+type })
}
}

View File

@ -44,12 +44,18 @@ export const CustomerApi = {
return await request.download({ url: `/oms/customer/export-excel`, params })
},
// 查询当前登录客户
getCustomerInfo: async () => {
return await request.get({ url: `/front/oms/customer/info`})
},
// ==================== 子表(用户地址) ====================
// 获得用户地址列表
getCustomerAddressListByCustomerId: async (customerId) => {
return await request.get({ url: `/oms/customer/customer-address/list-by-customer-id?customerId=` + customerId })
},
}

View File

@ -0,0 +1,95 @@
<template>
<Dialog :title="dialogTitle" append-to-body v-model="dialogVisible">
<Form :disabled="disabled" ref="formRef" :schema="allSchemas.formSchema" :rules="rules" v-loading="formLoading" >
<template #areaId="data">
<div>
<el-cascader
v-model="data.areaId"
:options="that.areaList"
:props="defaultProps"
class="w-1/1"
clearable
filterable
placeholder="请选择城市"
/>
</div>
</template>
<template #isDefault="data">
<el-checkbox v-model="data.isDefault">默认</el-checkbox>
</template>
</Form>
<template #footer>
<el-button v-if="!disabled" @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { AddressApi } from '@/api/oms/customer/address'
import { rules, allSchemas } from './config.data'
import {defaultProps} from "@/utils/tree";
import {UPDATE_ADDRESS} from "@/constants/EmitEventName";
import {useEmitt} from "@/hooks/web/useEmitt";
const { t } = useI18n() //
const message = useMessage() //
const {emitter} = useEmitt();
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formRef = ref() // Ref
const disabled = computed(() => {
return formType.value !== 'create' && formType.value !== 'update'
})
const that = reactive({
areaList: [],
})
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
AddressApi.getAreaTree().then(res=>{
that.areaList = res;
})
//
if (id) {
formLoading.value = true
try {
const data = await AddressApi.getAddressInfo(id)
formRef.value.setValues(data)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.getElFormRef().validate()
if (!valid) return
//
formLoading.value = true
try {
const data = formRef.value.formModel
await AddressApi.submit(data)
message.success(t(data.id ? 'common.updateSuccess' :'common.createSuccess'))
dialogVisible.value = false
//
emit('success')
emitter.emit(UPDATE_ADDRESS,{
...data
})
} finally {
formLoading.value = false
}
}
</script>

View File

@ -0,0 +1,58 @@
import type { CrudSchema } from '@/hooks/web/useCrudSchemas'
// 表单校验
export const rules = reactive({
code: [required],
name: [required],
})
// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/
const crudSchemas = reactive<CrudSchema[]>([
{
label: 'id',
field: 'id',
isForm: false,
table: {
show: false
},
},
{
label: '名称',
field: 'name',
isSearch: true,
},{
label: '联系电话',
field: 'phone',
isSearch: true,
},{
label: '地区',
field: 'areaId',
table: {
show: false
},
isSearch: false,
},
{
label: '地址',
field: 'address',
isSearch: true,
},
{
label: '默认地址',
field: 'isDefault',
isSearch: true,
},
{
field: 'action',
width: '260px',
label: '操作' ,
form: {
show: false
},
detail: {
show: false
}
}
])
export const { allSchemas } = useCrudSchemas(crudSchemas)

View File

@ -0,0 +1,348 @@
<template>
<slot>
<div>
<el-input
v-model="that.showValue"
clearable
:placeholder="props.placeholder"
@clear="clearData"
@click="viewDetails"
>
<template #append>
<el-button @click.stop="openDialog">
<Icon icon="ep:search"/>
</el-button>
</template>
</el-input>
</div>
</slot>
{{tmp}}
<Dialog
:title="dialogTitle"
width="80%"
append-to-body
v-model="that.visible"
@close="updateVisible(false)">
<div>
<!-- 搜索工作栏 -->
<ContentWrap>
<Search
:schema="allSchemas.searchSchema"
:is-col="false"
@search="setSearchParams"
@reset="setSearchParams">
<!-- 新增等操作按钮 -->
<template #actionMore>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['oms:draft-design-data:create']"
>
<Icon icon="ep:plus" class="mr-5px"/>
新增
</el-button>
</template>
</Search>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<div class="flex justify-between items-center mb-10px">
<div class="flex-1">
<el-button
type="primary"
plain
@click="openForm('create')"
>
<Icon icon="ep:plus" class="mr-5px"/>
新增
</el-button>
</div>
</div>
<Table
:columns="allSchemas.tableColumns"
:data="tableObject.tableList"
:loading="tableObject.loading"
:selection="true"
ref="tableRef"
@selection-change="selectionChange"
:pagination="{
total: tableObject.total
}"
v-model:pageSize="tableObject.pageSize"
v-model:currentPage="tableObject.currentPage"
>
<template #isDefault="{row}">
<div>
<div v-if="row.isDefault">
{{t("size.default")}}
</div>
<div v-else>
<el-button
type="primary"
link
size="mini"
@click="setDefault(row.id)">
设为默认
</el-button>
</div>
</div>
</template>
<template #action="{ row }">
<el-button
link
type="primary"
@click="openForm('update', row.id)"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(row.id)"
>
删除
</el-button>
</template>
</Table>
</ContentWrap>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="updateVisible(false,true)">{{ t('common.cancel') }}</el-button>
<el-button type="primary" @click="submit">{{ t('common.ok') }}</el-button>
</span>
</template>
</Dialog>
<!-- 表单弹窗添加/修改 -->
<DataForm ref="formRef" @success="getList"/>
</template>
<script lang="ts" setup name="ProductInfoListDialog">
import {allSchemas} from './config.data'
import DataForm from './DataForm.vue'
import {AddressApi} from "@/api/oms/customer/address";
import {usePageLoading} from "@/hooks/web/usePageLoading";
import {useEmitt} from "@/hooks/web/useEmitt";
import {UPDATE_ADDRESS} from "@/constants/EmitEventName";
/** 稿件图片库 */
defineOptions({name: 'AddressListDialog'})
const emit = defineEmits(['update:modelValue', 'update:visible', 'submit']) // success
const {t} = useI18n() //
const {emitter} = useEmitt();
const dialogTitle = ref('收货地址管理') //
const pageLoading = usePageLoading();
const props = defineProps({
modelValue: {
type: String,
required: true
},
dataKey: {
type: String,
required: false,
default: 'id'
},
showKey: {
type: String,
required: false,
default: 'name'
},
multiple: {
type: Boolean,
required: false,
default: false
},
placeholder: {
type: String,
required: false,
default: '请选择'
},
width: {
type: String,
required: false,
default: '64px'
},
height: {
type: String,
required: false,
default: '64px'
},
visible: {
type: Boolean,
required: false,
default: false
}
})
const that = reactive({
inputVal: '',
showValue: '',
visible: false,
areaList: [],
})
const setDefault = (id: number)=>{
pageLoading.loadStart();
AddressApi.setDefaultAddress(id).then(res=>{
useMessage().success(t('common.success'))
emitter.emit(UPDATE_ADDRESS,{
id: id
})
getList();
pageLoading.loadDone();
})
}
const openDialog = () => {
updateVisible(true);
}
const viewDetails = () => {
if (that.inputVal) {
openForm("preview", that.inputVal.split(",")[0])
} else {
openDialog();
}
}
//
const tmp = computed(()=>{
setTimeout(()=>{
that.inputVal = toStr(props.modelValue,that.inputVal)
if (that.inputVal) {
initInput();
}
},100)
return ''
},{
deep: true
})
const toStr = (data: any) => {
if (data !== null && data !== undefined) {
return `${data}`
}
return data
}
let map = new Map();
const initInput = async () => {
const dataKey = that.inputVal + ',' + props.dataKey + ',' + props.showKey + ',' + props.multiple;
if (map.has(dataKey)) {
const data = map.get(dataKey)
if (data) {
that.inputVal = data.inputVal
that.showValue = data.showValue
console.log('缓存数据', data)
return;
}
}
const ids = that.inputVal.split(",");
map.set(dataKey, {
inputVal: that.inputVal,
showValue: that.showValue
})
}
watch(() => props.visible, (newVal) => {
that.visible = newVal;
})
const clearData = () => {
that.inputVal = '';
that.showValue = '';
updateValue();
}
const updateVisible = (visible: boolean, clearInput = false) => {
that.visible = visible;
if(that.visible){
getList();
}
emit("update:visible", visible)
if (clearInput) {
clearData();
}
}
const submit = () => {
updateValue();
updateVisible(false)
}
const updateValue = () => {
emit("update:modelValue", that.inputVal)
}
//
const selectionChange = (row) => {
if (row && row.length > 0) {
if (props.multiple) {
let valArr = [];
let showArr = [];
for (let i = 0; i < row.length; i++) {
const tmp = row[i][props.dataKey || 'id']
if(valArr.includes(tmp)){
continue;
}
valArr.push( tmp)
showArr.push(row[i][props.showKey || 'id'])
}
that.inputVal = valArr.join(',')
that.showValue = showArr.join(',')
} else {
if (row.length > 1) {
useMessage().warning('单选数据,已忽略其他')
}
that.showValue = row[row.length - 1][props.showKey || 'id']
that.inputVal = row[row.length - 1][props.dataKey || 'id']
}
} else {
that.inputVal = ''
that.showValue = ''
}
}
const {tableObject, tableMethods} = useTable({
getListApi: AddressApi.getCustomerAddressList, //
delListApi: AddressApi.delAddress //
})
//
const {getList, setSearchParams} = tableMethods
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = (id: number) => {
tableMethods.delList(id, false)
}
/** 初始化 **/
onMounted(() => {
})
defineExpose({
openDialog,
viewDetails
})
</script>
<style lang="scss" scoped>
:deep(.el-input__wrapper) {
position: relative;
.el-input__inner {
padding-right: 18px;
}
.el-input__suffix {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
}
}
</style>

View File

@ -57,34 +57,37 @@
v-loading="loading"
:src="that.previewUrl"/>
</div>
<div style="width: 100%" v-if="that.propOrderByList && that.propOrderByList.length > 0">
<el-scrollbar height="600px">
<el-form label-width="180px">
<el-form-item label="风格主题" v-show="that.draftDesignList.length > 1">
<div class="flex ml-3">
<div>
<el-select class="min-w-100" v-model="that.draftDesignId" @change="changeType">
<el-option
v-for="(item) in that.draftDesignList"
:key="item.id"
:label="item.label"
:value="item.id"
/>
</el-select>
<div class="flex flex-col">
<div>
<el-form label-width="180px">
<el-form-item label="风格样式" v-show="that.draftDesignList.length > 1">
<div class="flex ml-3">
<div>
<el-select class="min-w-100" v-model="that.draftDesignId" @change="changeType">
<el-option
v-for="(item) in that.draftDesignList"
:key="item.id"
:label="item.label"
:value="item.id"
/>
</el-select>
</div>
</div>
</div>
</el-form-item>
<el-form-item
v-for="(tmp) in that.propOrderByList"
:key="tmp.key"
:label="getLabelName(that.propInfo[tmp.key])">
<div
v-if="that.propInfo[tmp.key].multiLanguage && that.propInfo[tmp.key].shape === ShapeType.vueTextCell">
<div
style="padding: 4px">
<div style="display: flex;align-items: center;">
</el-form-item>
</el-form>
</div>
<div style="width: 100%" v-if="that.propOrderByList && that.propOrderByList.length > 0">
<el-scrollbar height="600px">
<el-form label-width="180px">
<el-form-item
v-for="(tmp) in that.propOrderByList"
:key="tmp.key"
:label="getLabelName(that.propInfo[tmp.key])">
<div
v-if="that.propInfo[tmp.key].multiLanguage && that.propInfo[tmp.key].shape === ShapeType.vueTextCell">
<div
style="padding: 4px">
<div style="display: flex;align-items: center;">
<span>
<i
v-if="that.propInfo[tmp.key].canInput"
@ -93,56 +96,56 @@
<i v-else class="icon-lk_cell_add" style="font-size: 20px"> </i>
</span>
<el-select-v2
v-model="that.propInfo[tmp.key].dataInfo[0].showLabel"
filterable
:options="getIngredientInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeData(-1,tmp.key)"
size="large"
style="min-width: 280px;width: 100%"
/>
<div v-if="that.propInfo[tmp.key].groupType === '1'">
<div
style="display: flex;align-items: center; margin-left: 10px; width: 220px">
<el-row>
<el-col span="4">
<div>占比</div>
</el-col>
<el-col span="14">
<el-input-number
:min="-1" :max="100"
v-model="that.propInfo[tmp.key].dataInfo[0].ratio"
@change="changeData(0,tmp.key)"
/>
</el-col>
<el-col span="4">
<div> %</div>
</el-col>
</el-row>
<el-select-v2
v-model="that.propInfo[tmp.key].dataInfo[0].showLabel"
filterable
:options="getIngredientInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeData(-1,tmp.key)"
size="large"
style="min-width: 280px;width: 100%"
/>
<div v-if="that.propInfo[tmp.key].groupType === '1'">
<div
style="display: flex;align-items: center; margin-left: 10px; width: 220px">
<el-row>
<el-col span="4">
<div>占比</div>
</el-col>
<el-col span="14">
<el-input-number
:min="-1" :max="100"
v-model="that.propInfo[tmp.key].dataInfo[0].ratio"
@change="changeData(0,tmp.key)"
/>
</el-col>
<el-col span="4">
<div> %</div>
</el-col>
</el-row>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
</el-button>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
</div>
<div v-else-if="!that.propInfo[tmp.key].isCombo">
<div
v-for="(text,index) in that.propInfo[tmp.key].dataInfo"
:key="index"
style="padding: 4px">
<div style="display: flex;align-items: center;">
<div v-else-if="!that.propInfo[tmp.key].isCombo">
<div
v-for="(text,index) in that.propInfo[tmp.key].dataInfo"
:key="index"
style="padding: 4px">
<div style="display: flex;align-items: center;">
<span>
<i
v-if="that.propInfo[tmp.key].canInput"
@ -150,111 +153,113 @@
style="font-size: 20px"> </i>
<i v-else class="icon-lk_cell_add" style="font-size: 20px"> </i>
</span>
<el-autocomplete
v-if="that.propInfo[tmp.key].canInput"
v-model="that.propInfo[tmp.key].dataInfo[index].showLabel"
:fetch-suggestions="querySearch"
clearable
class="inline-input w-50"
placeholder="Please Input"
@change="changeData"
@select="changeData"
/>
<el-autocomplete
v-if="that.propInfo[tmp.key].canInput"
v-model="that.propInfo[tmp.key].dataInfo[index].showLabel"
:fetch-suggestions="querySearch"
clearable
class="inline-input w-50"
placeholder="Please Input"
@change="changeData"
@select="changeData"
/>
<el-select-v2
v-else
v-model="that.propInfo[tmp.key].dataInfo[index].showLabel"
filterable
:options="getIngredientInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeData(index,tmp.key)"
size="large"
style="min-width: 280px;width: 100%"
/>
<div v-if="that.propInfo[tmp.key].groupType === '1'">
<el-select-v2
v-else
v-model="that.propInfo[tmp.key].dataInfo[index].showLabel"
filterable
:options="getIngredientInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeData(index,tmp.key)"
size="large"
style="min-width: 280px;width: 100%"
/>
<div v-if="that.propInfo[tmp.key].groupType === '1'">
<div
style="display: flex;align-items: center; margin-left: 10px; width: 220px">
<el-row>
<el-col span="4">
<div>占比</div>
</el-col>
<el-col span="14">
<el-input-number
:min="-1" :max="100"
v-model="that.propInfo[tmp.key].dataInfo[index].ratio"
@change="changeData(index,tmp.key)"
/>
</el-col>
<el-col span="4">
<div> %</div>
</el-col>
</el-row>
<div
style="display: flex;align-items: center; margin-left: 10px; width: 220px">
<el-row>
<el-col span="4">
<div>占比</div>
</el-col>
<el-col span="14">
<el-input-number
:min="-1" :max="100"
v-model="that.propInfo[tmp.key].dataInfo[index].ratio"
@change="changeData(index,tmp.key)"
/>
</el-col>
<el-col span="4">
<div> %</div>
</el-col>
</el-row>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
</el-button>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
</div>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
</div>
<div v-else-if="that.propInfo[tmp.key].shape === ShapeType.vueShapeImage">
<div
v-for="(img,index) in that.propInfo[tmp.key].dataInfo"
:key="index" style="display: flex">
<div class="img-box" v-if="img.url">
<div style="display: flex">
<img :src="img.url" width="60px" height="60px"/>
<el-select-v2
v-model="that.propInfo[tmp.key].dataInfo[0].showLabel"
filterable
:options="washingInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeComboData(that.propInfo[tmp.key],that.propInfo[tmp.key].dataInfo[0].showLabel)"
size="large"
style="min-width: 280px;width: 100%"
>
<template #default="{ item }">
<div style="display: flex;">
<img :src="item.url" width="30px" height="30px"/>
<span>
<div v-else-if="that.propInfo[tmp.key].shape === ShapeType.vueShapeImage">
<div
v-for="(img,index) in that.propInfo[tmp.key].dataInfo"
:key="index" style="display: flex">
<div class="img-box" v-if="img.url">
<div style="display: flex">
<img :src="img.url" width="60px" height="60px"/>
<el-select-v2
v-model="that.propInfo[tmp.key].dataInfo[0].showLabel"
filterable
:options="washingInfoListByType(that.propInfo[tmp.key].groupType)"
placeholder="Please select"
@change="changeComboData(that.propInfo[tmp.key],that.propInfo[tmp.key].dataInfo[0].showLabel)"
size="large"
style="min-width: 280px;width: 100%"
>
<template #default="{ item }">
<div style="display: flex;">
<img :src="item.url" width="30px" height="30px"/>
<span>
{{ item.label }}
</span>
</div>
</template>
</el-select-v2>
</div>
</template>
</el-select-v2>
</div>
</div>
<div v-else-if="img.label">
<el-input v-model="img.label" disabled/>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
</el-button>
</div>
</div>
<div v-else-if="img.label">
<el-input v-model="img.label" disabled/>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="deleteList(that.propInfo[tmp.key],index)">
<i class="icon-lk_delete"> </i>
</el-button>
</div>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
<el-button
v-if="that.propInfo[tmp.key].canChange"
@click="appendList(that.propInfo[tmp.key])">
添加
</el-button>
</div>
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</div>
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</div>
</div>
<div
@ -520,7 +525,7 @@ const previewByProductId = async (id: string | number, propData = {}, defDraftDe
console.log("prodRes", prodRes)
that.draftDesignList = JSON.parse(prodRes.draftDesignList, '[]')
that.draftDesignId = defDraftDesignId || prodRes.draftDesignDataId
await previewByDraftDesignId(that.draftDesignId, propData)
await previewByDraftDesignId(that.draftDesignId.split(',')[0], propData)
}
}
const loadConfig = (config: object, propData = {}) => {

View File

@ -162,7 +162,7 @@ const uploadInfo = async ()=>{
}
const addNew = async () => {
for (let i = 0; i < fileList.value.length; i++) {
const base64Info = await convertImageToBase64(fileList.value[i].url as string)
// const base64Info = await convertImageToBase64(fileList.value[i].url as string)
let info ={
key: ShapeType.vueShapeImage,
shape: ShapeType.vueShapeImage,
@ -173,11 +173,11 @@ const addNew = async () => {
shape: VueCellShapeType.Image,
style: {
shape:{
href: base64Info,
href: fileList.value[i].url,
},
}
},
icon: base64Info,
icon: fileList.value[i].url,
//@ts-ignore
label: fileList.value[i].filename || '未命名图片',
filterKeyword: function (){ return this.label }

View File

@ -9,14 +9,14 @@
>
<template #title>
<div>
Setting
页面配置
</div>
</template>
<template #default>
<el-form>
<div>
<div>
<el-form-item label="backgroundColor">
<el-form-item label="背景颜色">
<ColorPickerTool
v-model="that.pageConfig.background.areaColor"
:uuid="`background.areaColor`"
@ -26,21 +26,21 @@
</el-form-item>
</div>
<div>
<div style="width: 150px;">
<div>
width
<div style="width: 300px;">
<div style="display: flex;align-items: center">
<span style="padding: 4px"></span>
<el-input-number
v-model="that.pageConfig.editArea.width"
@change="changePageConfig"/>
@change="changePageConfig"/>mm
</div>
<div>
height
<div style="display: flex;align-items: center">
<span style="padding: 4px"></span>
<el-input-number
v-model="that.pageConfig.editArea.height"
@change="changePageConfig"/>
@change="changePageConfig"/>mm
</div>
<div>
onLoadZoom
<div style="display: flex;align-items: center">
<div style="padding: 4px">加载缩放比</div>
<el-input-number
:min="0.1"
:max="10"
@ -132,7 +132,7 @@
<div
style="margin-left: 6px;display: flex;flex-wrap: wrap;align-items: center;height: 100%;max-width: 900px">
<div>
<el-button @click="that.showDialog = true" :title="Setting">Settings</el-button>
<el-button @click="that.showDialog = true" title="页面设置">页面设置</el-button>
</div>
<div>
<el-button @click="that.showOrderByDialog= true" :title="'属性排序'">
@ -298,7 +298,7 @@
:width="60"
:effect="that.effect"
trigger="hover"
content="FillColor"
content="填充颜色"
>
<template #reference>
<div>
@ -324,7 +324,7 @@
:width="60"
:effect="that.effect"
trigger="hover"
content="lineColor"
content="边框颜色"
>
<template #reference>
<div>

View File

@ -12,13 +12,12 @@
transform-origin: left top;
transform: scale(0.1); "
:style="svgStyle"
>
<image
:href="cellInfo.style.shape.href" x="0" y="0"
:href="hrefBase64 || cellInfo.style.shape.href" x="0" y="0"
style="width: 100%;height: 100%;"
:stroke="cellInfo.style.shape.strokeColor"
:stroke-width="cellInfo.style.shape.strokeWidth"
:fill="cellInfo.style.shape.fillColor"
:fill-opacity="cellInfo.style.shape.fillOpacity"
:stroke-dasharray="cellInfo.style.shape.strokeDasharray"
:stroke-dashoffset="cellInfo.style.shape.strokeDashoffset"
@ -27,7 +26,6 @@
:clip-path="cellInfo.style.shape.clipPath"
:filter="cellInfo.style.shape.filter"
/>
</svg>
</div>
</template>
@ -60,11 +58,12 @@ export default defineComponent({
svgStyle() {
const res = {
borderRadius: '',
backgroundColor : this.cellInfo.style.shape.fillColor || "",
width: `1000px`,
height: `1000px`,
transform: ''
}
const tmp = Math.min(this.sizeWInfo.width, this.sizeWInfo.height) - (this.cellInfo.style.shape.strokeWidth * 2)
// const tmp = Math.min(this.sizeWInfo.width, this.sizeWInfo.height) - (this.cellInfo.style.shape.strokeWidth * 2)
const w = (Math.max(this.sizeWInfo.width, 0)) / 1000;
const h = (Math.max(this.sizeWInfo.height, 0)) / 1000;
res.transform = `scaleX(${w}) scaleY(${h})`
@ -108,7 +107,7 @@ export default defineComponent({
y: 0, // y
rx: 0, // x
ry: 0, // y
fillColor: '#000000', //
fillColor: '', //
fillOpacity: '', //
href: '',
hrefBase64: null,
@ -116,8 +115,6 @@ export default defineComponent({
strokeDashoffset: '', // 线
strokeLinecap: undefined, // 线"round" | "butt" | "square" | "inherit" | undefined
strokeLinejoin: undefined, // 线"round" | "inherit" | "miter" | "bevel" | undefined
strokeColor: '', //
strokeWidth: 0, //
strokeDasharray: '', // 线
bottom: 0, //
transform: '', //
@ -246,8 +243,6 @@ export default defineComponent({
strokeDashoffset: '', // 线
strokeLinecap: undefined, // 线"round" | "butt" | "square" | "inherit" | undefined
strokeLinejoin: undefined, // 线"round" | "inherit" | "miter" | "bevel" | undefined
strokeColor: '#000000', //
strokeWidth: 0, //
strokeDasharray: '', // 线
bottom: 0, //
transform: '', //
@ -261,6 +256,7 @@ export default defineComponent({
if(this.cellInfo.style.shape.href){
convertImageToBase64(this.cellInfo.style.shape.href).then((res)=>{
// @ts-ignore
// this.hrefBase64 = res
this.cellInfo.style.shape.href = res
})
}

View File

@ -56,7 +56,7 @@ export default defineComponent({
emits: ['update:pageSize', 'update:currentPage', 'register','selectionChange'],
setup(props, { attrs, slots, emit, expose }) {
const elTableRef = ref<ComponentRef<typeof ElTable>>()
console.log("slots",slots)
//
onMounted(() => {
const tableRef = unref(elTableRef)

View File

@ -1,2 +1,3 @@
export const STEP0_FINISH:string = 'step0finish'
export const UPDATE_ADDRESS:string = 'update_address'

View File

@ -228,52 +228,123 @@
</el-card>
</el-collapse-item>
<el-collapse-item name="3">
<template #title>
<CardTitle title="发票信息"/>
</template>
<el-card>
<el-row>
<!-- 右上角账户信息 -->
<el-col :span="12" class="detail-info-item"
style="padding-left: 0px; margin-top: 20px">
<el-row>
<el-col :span="12">
<el-form-item label="发票抬头" prop="invoiceCode">
<el-input v-model="formData.invoiceCode" placeholder="请输入发票抬头"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发票名称" prop="invoiceName">
<el-input v-model="formData.invoiceName" placeholder="请输入发票名称"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="发票地址" prop="invoiceAddress">
<el-input
name="auto$input_so_invoiceAddress"
autocomplete="on"
v-model="formData.invoiceAddress"
placeholder="请输入发票地址"/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="发票备注" prop="invoiceRemarks">
<el-input
v-model="formData.invoiceRemarks"
:autosize="{ minRows: 4, maxRows: 6 }"
placeholder="请输入发票备注"
type="textarea"/>
</el-form-item>
</el-col>
</el-row>
</el-col>
<div class="flex">
<el-row>
<el-col :span="12" :xs="24">
<div>
<el-card>
<div class="flex items-center">
<CardTitle title="发票信息"/>
<div class="pl-8px" v-if="false">
<el-button type="primary" link>管理发票信息</el-button>
</div>
</div>
</el-row>
</el-card>
</el-collapse-item>
<el-row>
<!-- 右上角账户信息 -->
<el-col :span="24" class="detail-info-item"
style="padding-left: 0px; margin-top: 20px">
<el-row>
<el-col :span="12">
<el-form-item label="发票抬头" prop="invoiceCode">
<el-input v-model="formData.invoiceCode" placeholder="请输入发票抬头"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发票名称" prop="invoiceName">
<el-input v-model="formData.invoiceName" placeholder="请输入发票名称"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="发票地址" prop="invoiceAddress">
<el-input
name="auto$input_so_invoiceAddress"
autocomplete="on"
v-model="formData.invoiceAddress"
placeholder="请输入发票地址"/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="发票备注" prop="invoiceRemarks">
<el-input
v-model="formData.invoiceRemarks"
:autosize="{ minRows: 2, maxRows: 4 }"
placeholder="请输入发票备注"
type="textarea"/>
</el-form-item>
</el-col>
</el-row>
</el-col>
</el-row>
</el-card>
</div>
</el-col>
<el-col :span="12" :xs="24">
<div>
<el-card>
<div class="flex items-center">
<CardTitle title="收货信息"/>
<div class="pl-8px">
<AddressListDialog ref="addressRef">
<el-button type="primary" link @click="editAddress">管理收货地址</el-button>
</AddressListDialog>
</div>
</div>
<el-row>
<!-- 右上角账户信息 -->
<el-col :span="24" class="detail-info-item"
style="padding-left: 0px; margin-top: 20px">
<el-row>
<el-col :span="24">
<el-form-item label="送货公司">
<el-select filterable
placeholder="选择地址"
v-model="that.addressId"
@change="onChangeAddress">
<el-option v-for="item in that.addressList" :label="item.name" :key="item.id" :value="item.id">
<span>{{ item.name }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="详细地址">
<el-input
name="auto$input_deliveryAddress"
autocomplete="on"
clearable
:autosize="{ minRows: 2, maxRows: 4 }"
v-model="formData.deliveryAddress"
type="textarea"
placeholder="请输入收货地址"/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="送货备注" prop="invoiceRemarks">
<el-input
v-model="formData.deliveryRemark"
:autosize="{ minRows: 2, maxRows: 4 }"
placeholder="请输入送货备注"
clearable
type="textarea"/>
</el-form-item>
</el-col>
</el-row>
</el-col>
</el-row>
</el-card>
</div>
</el-col>
</el-row>
</div>
</el-collapse>
</div>
@ -317,12 +388,13 @@
<script lang="ts" setup>
//@ts-nocheck
import * as BrandApi from "@/api/oms/brand";
import {AddressApi} from "@/api/oms/customer/address";
import {CustomerApi} from "@/api/oms/customer";
import {SaleOrderApi} from "@/api/oms/saleorder";
import OrderAddProductStep from "./components/OrderAddProductStep/index.vue";
import {useEmitt} from "@/hooks/web/useEmitt";
import {STEP0_FINISH} from "@/constants/EmitEventName";
import {STEP0_FINISH, UPDATE_ADDRESS} from "@/constants/EmitEventName";
import {formatDate} from "@/utils/formatTime";
//
@ -346,20 +418,29 @@ const stepRef = ref(null);
const formRef = ref() // Ref
const selectedIndex = ref(-1)
const stepIndex = ref(0)
const addressRef = ref(null);
const editAddress = () => {
addressRef.value.openDialog()
}
useEmitt({
name: UPDATE_ADDRESS,
callback: ()=>{
getCustomerAddressList();
},
});
const that = reactive({
formLoading: false,
addressList: [],
addressId: null,
tmpFormData: {
inputEmail: '',
emailList: [],
planDate: calculateDateAfterDays(7),
},
})
const customerData = ref()
const formData = ref({
contactName: '',
phone: '18122943211',
phone: '',
invoiceAddress: '',
orderStatus: '',
customerId: '',
@ -379,6 +460,8 @@ const formData = ref({
emails: '',
bizdate: undefined,
plansenddate: undefined,
deliveryAddress: '',
deliveryRemark: '',
saleOrderEntry: [],
})
@ -432,18 +515,6 @@ const generateContractCode = () => {
return code;
}
/** 查询列表 */
const getCustomer = async () => {
loading.value = true
try {
const data = await CustomerApi.getCustomerPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
const backStep = async () => {
stepIndex.value = stepIndex.value - 1;
}
@ -470,7 +541,14 @@ const nextStep = async () => {
}
}
const onChangeAddress = (id)=>{
console.log(id)
for (let i = 0; i < that.addressList.length; i++) {
if(that.addressList[i].id === id){
formData.value.deliveryAddress = that.addressList[i].address
}
}
}
const addNewBill = () => {
console.log("stepRef.value.getTableData()", stepRef.value.getTableData())
// todo
@ -503,19 +581,32 @@ const brandList = ref<any[]>([]) // 品牌列表
onMounted(async () => {
//
brandList.value = await BrandApi.getSimpleBrandList()
customerData.value = await CustomerApi.getCustomer()
if (customerData.value) {
formData.value.customerId = customerData.value.id;
formData.value.username = customerData.value.name;
formData.value.company = customerData.value.company;
const customerData = await CustomerApi.getCustomerInfo()
if (customerData) {
that.addressList = customerData.addressList;
formData.value.customerId = customerData.id;
formData.value.username = customerData.name;
formData.value.company = customerData.company;
formData.value.contactName = customerData.contacts;
formData.value.phone = customerData.phone;
if(!formData.value.deliveryAddress && that.addressList.length > 0){
formData.value.deliveryAddress = that.addressList[0].address;
that.addressId = that.addressList[0].id;
}
}
})
const getCustomerAddressList = async () => {
const customerData = await CustomerApi.getCustomerInfo()
if (customerData) {
that.addressList = customerData.addressList;
}
}
const resFrom = (init = {}) => {
formData.value = {
contactName: '',
phone: '18122943211',
phone: '',
invoiceAddress: '',
orderStatus: '',
customerId: '',
@ -538,6 +629,18 @@ const resFrom = (init = {}) => {
saleOrderEntry: [],
...init
}
if (customerData && !init.id) {
that.addressList = customerData.addressList;
formData.value.customerId = customerData.id;
formData.value.username = customerData.name;
formData.value.company = customerData.company;
formData.value.contactName = customerData.contacts;
formData.value.phone = customerData.phone;
formData.value.invoiceCode = customerData.invoiceCode;
formData.value.invoiceName = customerData.invoiceName;
formData.value.invoiceAddress = customerData.invoiceAddress;
console.log("formData",formData)
}
}