package com.sdtool.business.service.mall;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.dySweetFishPlugin.redis.RedisService;
import com.dySweetFishPlugin.sql.TableIdService;
import com.dySweetFishPlugin.sql.dao.TunaService;
import com.dySweetFishPlugin.tool.lang.ThreadFactoryWithNamePrefix;
import com.sdtool.business.dao.DesignDao;
import com.sdtool.common.api.NoSqlKeysService;
import com.sdtool.common.api.PermissionService;
import com.sdtool.common.api.mall.DesignService;
import com.sdtool.common.base.BaseService;
import com.sdtool.common.datas.RedisKeys;
import com.sdtool.common.entity.base.BaseEntity;
import com.sdtool.common.entity.base.ProcessIdItem;
import com.sdtool.common.entity.base.ProcessStringItem;
import com.sdtool.common.entity.design.*;
import com.sdtool.common.entity.design.fabric.FabricMain;
import com.sdtool.common.entity.site.ERPTokenUser;
import com.sdtool.common.tool.ERPUtils;
import com.sweetfish.convert.json.JsonConvert;
import com.sweetfish.convert.json.JsonFactory;
import com.sweetfish.service.Local;
import com.sweetfish.service.RetResult;
import com.sweetfish.source.PageFlipper;
import com.sweetfish.util.AnyValue;
import com.sweetfish.util.AutoLoad;
import com.sweetfish.util.ResourceType;
import com.sweetfish.util.TypeToken;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.rex.RMap;

import javax.annotation.Resource;
import java.awt.*;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Local
@AutoLoad(false)
@ResourceType(DesignService.class)
public class DesignServiceImpl extends BaseService implements DesignService {

    @Resource
    private TunaService tunaService;

    @Resource
    private JsonConvert jsonConvert;

    @Resource
    private RedisService redisService;

    @Resource
    private TableIdService tableIdService;

    @Resource
    private NoSqlKeysService keysService;

    @Resource
    private PermissionService permissionService;

    @Resource
    JsonFactory jsonRootFactory;

    @Resource(name = "APP_HOME")
    private String appHome;

    @Resource(name = "property.PC.Mall.Admin.commonkey")
    private String tokenKey;

    private String designContentRoot;
    private String designOutputRoot;
    private String orderContentRoot;

    private DesignDao designDao;

    private static final int tempTemplateExpire = 60 * 60 * 2;

    private final ScheduledThreadPoolExecutor pdfCallbackExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryWithNamePrefix("[PDF任务回调线程池]"));

    @Override
    public void start(AnyValue config) {
        designDao = tunaService.generate(DesignDao.class);

        designContentRoot = appHome + File.separator + "conf" + File.separator + "designContent";
        designOutputRoot = appHome + File.separator + "conf" + File.separator + "designOutput";
        orderContentRoot = appHome + File.separator + "conf" + File.separator + "orderContent";

        long supplierCode = 1000;//写死1000了,没必要为了这个耽误时间
        String dataSourceId = "erp001";
        pdfCallbackExecutor.scheduleWithFixedDelay(() -> {
            String callBackStr = redisService.lpop(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_PDF_CALLBACK_LIST, supplierCode));
            if (StringUtils.isNotEmpty(callBackStr)) {
                logger.info("接收到PDF生成回调: " + callBackStr);

                PDFCallbackInfo callbackInfo = jsonConvert.convertFrom(PDFCallbackInfo.class, callBackStr);

                String orderEditStr = redisService.hget(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_EDIT, supplierCode), String.valueOf(callbackInfo.getIdDesignOrder()));
                String orderImpositionStr = redisService.hget(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_IMPOSITION, supplierCode), String.valueOf(callbackInfo.getIdDesignOrder()));

                DesignOrder orderEdit = jsonConvert.convertFrom(DesignOrder.class, orderEditStr);
                DesignOrder orderImposition = jsonConvert.convertFrom(DesignOrder.class, orderImpositionStr);

                orderEdit.setPdfDownloadUrl("/output/" + callbackInfo.getPdfFileName());
                orderImposition.setPdfDownloadUrl("/output/" + callbackInfo.getPdfFileName());

                redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_EDIT, supplierCode), String.valueOf(orderEdit.getId()), orderEdit);
                redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_IMPOSITION, supplierCode), String.valueOf(orderImposition.getId()), orderImposition);

                designDao.pdfCallbackDesignOrder(orderImposition, dataSourceId, supplierCode);
            }
        }, 1, 2, TimeUnit.SECONDS);
    }

    @Override
    public void destroy(AnyValue config) {
        pdfCallbackExecutor.shutdown();
    }

    @Override
    public RetResult<List<DesignFont>> getDesignFonts(RMap params, String dataSourceId, long supplierCode) {
        List<DesignFont> fontList = getRedisDocInfos(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_FONT, supplierCode), DesignFont.class);
        if (ERPUtils.mapContainKey(params, "voidFlag")) {
            return RetResult.<List<DesignFont>>successT().result(fontList.stream().filter(x -> x.getVoidFlag() == params.getInt("voidFlag")).sorted(Comparator.comparingLong(BaseEntity::getCreateTimeLong)).toList());
        } else {
            return RetResult.<List<DesignFont>>successT().result(fontList.stream().filter(x -> x.getVoidFlag() == 0).sorted(Comparator.comparingLong(BaseEntity::getCreateTimeLong)).toList());
        }
    }

    @Override
    public RetResult<DesignFont> addDesignFont(DesignFont designFont, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        designFont.setId(tableIdService.getTableIdMulti("deDesignFont.id", 1, dataSourceId, String.valueOf(supplierCode)));

        //加载字体读取fontFamily
        String fontUrl = appHome + File.separator +
                "erpfiles" + File.separator +
                (designFont.getFontFilePath().replaceFirst("/static/", "").replace("/", File.separator));

        try {
            Font font = Font.createFont(Font.TRUETYPE_FONT, new File(fontUrl));
            designFont.setFontFamily(font.getFamily());
        } catch (FontFormatException | IOException e) {
            throw new RuntimeException(e);
        }

        //如果是windows系统,把字体拷到c:\windows\fonts目录
        //需求administrator权限
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win")) {
            try {
                Path srcPath = Paths.get(fontUrl);
                Files.copy(srcPath, Paths.get("C:\\Windows\\Fonts\\" + srcPath.getFileName()));
            } catch (IOException e) {
//                throw new RuntimeException(e);
                logger.error("安装系统字体失败: " + e.getMessage());
            }
        }

        designFont.setVoidFlag(0);
        DesignFont.create(designFont, currentUser.getId());

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_FONT, supplierCode), String.valueOf(designFont.getId()), designFont);
        designDao.addDesignFont(designFont, dataSourceId, supplierCode);

        return RetResult.<DesignFont>successT().result(designFont);
    }

    @Override
    public RetResult<DesignFont> voidDesignFont(DesignFont font, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        DesignFont redisFont = getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_FONT, supplierCode),
                String.valueOf(font.getId()), DesignFont.class);

        if (redisFont == null) return RetResult.successT();

        redisFont.setVoidFlag(font.getVoidFlag());
        DesignFont.update(redisFont, currentUser.getId());

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_FONT, supplierCode), String.valueOf(redisFont.getId()), redisFont);
        designDao.voidDesignFont(redisFont, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    public RetResult<List<DesignTemplate>> queryDesignTemplates(RMap params, PageFlipper pageFlipper, String dataSourceId, long supplierCode) {
        if (ERPUtils.mapContainKey(params, "tags")) {
            List tags = params.getList("tags");
            if (tags.size() > 0) {
                params.put("tagCount", params.getList("tags").size());
                params.put("tags", tags.stream().map(tag -> "'" + tag + "'").collect(Collectors.toList()));
            }
        }
        List<DesignTemplate> templateList = designDao.selectDesignTemplates(params, dataSourceId, supplierCode, pageFlipper);

        //获取标签
        List<TemplateTag> allTags = new ArrayList<>();
        if (templateList.size() > 0) {
            List<Long> idTemplates = templateList.stream().map(DesignTemplate::getId).toList();
            RMap rMap = new RMap();
            rMap.put("ids", idTemplates);
            allTags.addAll(designDao.getTemplateTags(rMap, dataSourceId, supplierCode));
        }

        templateList.forEach(x -> {
            x.setJsonContent("");
            x.setTagList(allTags.stream().filter(y -> y.getIdTemplate() == x.getId()).collect(Collectors.toList()));
        });
        return RetResult.<List<DesignTemplate>>successT().result(templateList).page(pageFlipper);
    }

    @Override
    public RetResult<DesignTemplate> getDesignTemplateEdit(long id, String dataSourceId, long supplierCode) {
        DesignTemplate redisTemplate = getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_EDIT, supplierCode),
                String.valueOf(id), DesignTemplate.class);

        if (redisTemplate == null) return RetResult.<DesignTemplate>errorT().retinfo("模板id不正确");
        else
            return RetResult.<DesignTemplate>successT().result(redisTemplate);
    }

    private void fillParamsToTemplate(DesignTemplate designTemplate, RMap params) {
        FabricMain fabricMain = jsonConvert.convertFrom(FabricMain.class, designTemplate.getJsonContent());

        //根据传入参数不同,查找替换
        if (ERPUtils.mapContainKey(params, "backgroundWidth") &&
                ERPUtils.mapContainKey(params, "backgroundHeight")) {
            //传进来的默认都是mm,但是fabric记录的是px,需要转一下
            double width = ERPUtils.mm2px(params.getDouble("backgroundWidth"));
            double height = ERPUtils.mm2px(params.getDouble("backgroundHeight"));

            fabricMain.setHeight(height * fabricMain.getZoom());
            fabricMain.setWidth(width * fabricMain.getZoom());

            fabricMain.getObjects().forEach(object -> {
                if (object.get("id").equals("WorkSpaceDrawType")) {
                    //背景对象
                    object.put("height", height);
                    object.put("width", width);
                }
            });
        }
        if (ERPUtils.mapContainKey(params, "backgroundColor")) {
            //格式 rgba(125,125,125,1)
            String color = params.getString("backgroundColor");
            fabricMain.getObjects().forEach(object -> {
                if (object.get("id").equals("WorkSpaceDrawType")) {
                    //背景对象
                    object.put("color", color);
                    object.put("fill", color);
                }
            });

            fabricMain.getWorkSpace().setColor(color);
            fabricMain.getWorkSpace().setFill(color);
        }

        if (ERPUtils.mapContainKey(params, "objects")) {
            List<HashMap<String, Object>> objects = jsonConvert.convertFrom(new TypeToken<List<HashMap<String, Object>>>() {
            }.getType(), params.getString("objects"));

            objects.forEach(object -> {
                fabricMain.getObjects().stream().filter(x ->
                        x.get("id").equals(object.get("id")) && x.get("name").equals("textbox")
                ).findFirst().ifPresent(x -> {
                    x.put("color", object.get("color"));
                    x.put("fill", object.get("color"));
                    x.put("text", object.get("text"));
                    x.put("fontFamily", object.get("fontFamily"));
                });
            });
        }
//            redisTemplate.setJsonContent(jsonConvert.convertTo(fabricMain))
        designTemplate.setJsonContent(JSON.toJSONString(fabricMain, SerializerFeature.WriteMapNullValue));
    }

    /**
     * 获取供编辑的设计模板,带参数
     *
     * @param id
     * @param params
     * @param dataSourceId
     * @param supplierCode
     * @return
     */
    @Override
    public RetResult<DesignTemplate> getDesignTemplateEdit(long id, RMap params, String dataSourceId, long supplierCode) {
        DesignTemplate redisTemplate = getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_EDIT, supplierCode),
                String.valueOf(id), DesignTemplate.class);

        if (redisTemplate == null) return RetResult.<DesignTemplate>errorT().retinfo("模板id不正确");
        else {
            //从文件读取设计json
            String fileName = designContentRoot + File.separator + supplierCode +
                    File.separator + redisTemplate.getId() + ".txt";
            Path path = Paths.get(fileName);
            try {
                redisTemplate.setJsonContent(Files.readString(path, StandardCharsets.UTF_8));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            //标签信息
            RMap rMap = new RMap();
            rMap.put("ids", new Long[]{id});
            List<TemplateTag> tags = designDao.getTemplateTags(rMap, dataSourceId, supplierCode);
            redisTemplate.setTagList(tags);

            fillParamsToTemplate(redisTemplate, params);
            return RetResult.<DesignTemplate>successT().result(redisTemplate);
        }

    }

    @Override
    public RetResult<DesignTemplate> getDesignTemplateEdit(long id, RMap params, String outerSessionId, String dataSourceId, long supplierCode) {
        //这里多了一个暂存设计的需求,进来之后先用outerSessionId找一下有没有暂存的设计稿,有了就直接返回暂存,没有的话正常加载模板
        String templateJson = redisService.get(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_SESSION, supplierCode, true)
                + outerSessionId);
        if (StringUtils.isNotEmpty(templateJson)) {
            DesignTemplate template = jsonConvert.convertFrom(DesignTemplate.class, templateJson);
            template.setJsonContent(preProcessTemplateContent(template.getJsonContent()));
            return RetResult.<DesignTemplate>successT().result(template);
        } else {
            RetResult<DesignTemplate> templateRetResult = this.getDesignTemplateEdit(id, params, dataSourceId, supplierCode);
            if (!templateRetResult.isSuccess()) return templateRetResult;
            DesignTemplate designTemplate = templateRetResult.getResult();

            //给前端预处理一下权限
            designTemplate.setJsonContent(preProcessTemplateContent(designTemplate.getJsonContent()));

            //将当前临时模板记录在redis中,设置个过期时间就行了
            redisService.setex(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_SESSION, supplierCode, true)
                    + outerSessionId, tempTemplateExpire, designTemplate);
            return RetResult.<DesignTemplate>successT().result(designTemplate);
        }
    }

    @Override
    public RetResult<DesignTemplate> getDesignTemplateImposition(long id, String dataSourceId, long supplierCode) {
        DesignTemplate redisTemplate = getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_IMPOSITION, supplierCode),
                String.valueOf(id), DesignTemplate.class);

        if (redisTemplate == null) return RetResult.<DesignTemplate>errorT().retinfo("模板id不正确");
        else
            return RetResult.<DesignTemplate>successT().result(redisTemplate);
    }

    //根据元素权限对元素进行一些限制
    private String preProcessTemplateContent(String templateContent) {
        RMap<String, Object> template = jsonConvert.convertFrom(RMap.class, templateContent);

        List<HashMap<String, Object>> objects = jsonConvert.convertFrom(new TypeToken<List<HashMap<String, Object>>>() {
        }.getType(), template.getString("objects"));

        objects.forEach(object -> {
            //此处要处理permissionsConfig为null的情况
            if (object.get("permissionsConfig") != null) {
                if (!object.get("id").equals("WorkSpaceDrawType") && object.get("name").equals("textbox")) {
                    //字
                    List<String> permsList = jsonConvert.convertFrom(new TypeToken<List<String>>() {
                    }.getType(), object.get("permissionsConfig").toString());
                    if (permsList.contains("0")) {
                        //文字内容
                        object.put("editable", true);
                    } else {
                        object.put("editable", false);
                    }

                    if (permsList.contains("5")) {
                        //大小
                        object.put("hasControls", true);
                    } else {
                        object.put("hasControls", false);
                    }

                    if (permsList.contains("6")) {
                        //位置
                        object.put("lockMovementX", false);
                        object.put("lockMovementY", false);
                    } else {
                        object.put("lockMovementX", true);
                        object.put("lockMovementY", true);
                    }
                } else if (!object.get("id").equals("WorkSpaceDrawType") && object.get("name").equals("image")) {
                    //图
                    List<String> permsList = jsonConvert.convertFrom(new TypeToken<List<String>>() {
                    }.getType(), object.get("permissionsConfig").toString());

                    if (permsList.contains("1")) {
                        //大小
                        object.put("hasControls", true);
                    } else {
                        object.put("hasControls", false);
                    }

                    if (permsList.contains("2")) {
                        //位置
                        object.put("lockMovementX", false);
                        object.put("lockMovementY", false);
                    } else {
                        object.put("lockMovementX", true);
                        object.put("lockMovementY", true);
                    }
                }
            }
        });

        template.set("objects", objects);
        return jsonConvert.convertTo(template);
    }

    //todo 转换fabric的元素结构
    private void convertJsonObjectsToTemplate(DesignTemplate designTemplate, String dataSourceId, long supplierCode) {
        FabricMain fabricMain = jsonConvert.convertFrom(FabricMain.class, designTemplate.getJsonContent());
        List<DesignTemplateItem> templateItems = new ArrayList<>();
        fabricMain.getObjects().forEach(object -> {
            if (object.get("id").equals("WorkSpaceDrawType")) {
                //背景对象
                designTemplate.setCanvasHeight(ERPUtils.px2mm(((BigDecimal) object.get("height")).doubleValue()));
                designTemplate.setCanvasWidth(ERPUtils.px2mm(((BigDecimal) object.get("width")).doubleValue()));
            }


        });

        designTemplate.setItemList(templateItems);
    }

    private void convertJsonObjectsToOrder(DesignOrder designOrder, String dataSourceId, long supplierCode) {
        FabricMain fabricMain = jsonConvert.convertFrom(FabricMain.class, designOrder.getJsonContent());
        List<DesignOrderItem> orderItems = new ArrayList<>();
        long idItem = tableIdService.getTableIdMulti("deDesignOrderItem.id", fabricMain.getObjects().size(), dataSourceId, String.valueOf(supplierCode));
        for (HashMap<String, Object> object : fabricMain.getObjects()) {
            if (object.get("id").equals("WorkSpaceDrawType")) {
                //背景对象
                designOrder.setCanvasHeight(ERPUtils.px2mm(new BigDecimal(object.get("height").toString()).doubleValue()));
                designOrder.setCanvasWidth(ERPUtils.px2mm(new BigDecimal(object.get("width").toString()).doubleValue()));
            }

            DesignOrderItem orderItem = new DesignOrderItem();
            orderItem.setId(idItem++);
            orderItem.setIdOrder(designOrder.getId());
            orderItem.setItemType(object.get("type").toString());
            orderItem.setLocationX(Double.parseDouble(object.get("left").toString()));
            orderItem.setLocationY(Double.parseDouble(object.get("top").toString()));
            orderItem.setSizeWidth(ERPUtils.px2mm(new BigDecimal(object.get("width").toString()).doubleValue()));
            orderItem.setSizeHeight(ERPUtils.px2mm(new BigDecimal(object.get("height").toString()).doubleValue()));
            orderItem.setRotation(Double.parseDouble(object.get("angle").toString()));

            orderItems.add(orderItem);
        }

        designOrder.setItemList(orderItems);
    }

    @Override
    public RetResult<DesignTemplate> updateDesignTemplate(DesignTemplate template, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        boolean isNew = false;
        if (template.getId() <= 0) {
            //新增
            isNew = true;
            template.setId(tableIdService.getTableIdMulti("deDesignTemplate.id", 1, dataSourceId, String.valueOf(supplierCode)));
            DesignTemplate.create(template, currentUser.getId());
        } else {
            DesignTemplate.update(template, currentUser.getId());
        }

        String fileName = designContentRoot + File.separator + supplierCode +
                File.separator + template.getId() + ".txt";
        Path path = Paths.get(fileName);

        String writeContent = "";
        if (StringUtils.isNotEmpty(template.getJsonContent())) {
            writeContent = template.getJsonContent();
        }
        try {
            if (!Files.exists(path.getParent())) {
                Files.createDirectories(path.getParent());
            }
            Files.write(path,
                    Collections.singleton(new StringBuilder(writeContent)),
                    StandardCharsets.UTF_8,
                    StandardOpenOption.CREATE,
                    StandardOpenOption.WRITE,
                    StandardOpenOption.TRUNCATE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_EDIT, supplierCode), String.valueOf(template.getId()), template);
        convertJsonObjectsToTemplate(template, dataSourceId, supplierCode);
        template.setJsonContent(fileName);
        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_IMPOSITION, supplierCode), String.valueOf(template.getId()), template);

        if (isNew)
            designDao.addDesignTemplate(template, template.getItemList(), dataSourceId, supplierCode);
        else
            designDao.updateDesignTemplate(template, template.getItemList(), dataSourceId, supplierCode);

        return RetResult.<DesignTemplate>successT().result(template);
    }

    @Override
    public RetResult<DesignTemplate> updateDesignTemplateThumb(DesignTemplate template, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        DesignTemplate redisTemplateEdit = getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_EDIT, supplierCode),
                String.valueOf(template.getId()), DesignTemplate.class);
        DesignTemplate redisTemplateImposition = getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_IMPOSITION, supplierCode),
                String.valueOf(template.getId()), DesignTemplate.class);

        if (redisTemplateEdit != null) {
            redisTemplateEdit.setViewThumbPath(template.getViewThumbPath());
            redisTemplateEdit.setTemplateName(template.getTemplateName());

            redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_EDIT, supplierCode), String.valueOf(redisTemplateEdit.getId()), redisTemplateEdit);
        }

        if (redisTemplateImposition != null) {
            redisTemplateImposition.setViewThumbPath(template.getViewThumbPath());
            redisTemplateImposition.setTemplateName(template.getTemplateName());

            redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_IMPOSITION, supplierCode), String.valueOf(redisTemplateImposition.getId()), redisTemplateImposition);
        }

        designDao.updateDesignTemplateThumb(template, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    public RetResult<DesignTemplate> voidDesignTemplate(DesignTemplate template, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        DesignTemplate redisTemplateEdit = getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_EDIT, supplierCode),
                String.valueOf(template.getId()), DesignTemplate.class);
        DesignTemplate redisTemplateImposition = getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_IMPOSITION, supplierCode),
                String.valueOf(template.getId()), DesignTemplate.class);

        if (redisTemplateEdit != null) {
            redisTemplateEdit.setVoidFlag(template.getVoidFlag());
            redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_EDIT, supplierCode), String.valueOf(redisTemplateEdit.getId()), redisTemplateEdit);
        }
        if (redisTemplateImposition != null) {
            redisTemplateImposition.setVoidFlag(template.getVoidFlag());
            redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_IMPOSITION, supplierCode), String.valueOf(redisTemplateImposition.getId()), redisTemplateImposition);
        }

        designDao.voidDesignTemplate(template, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    public RetResult<DesignTemplate> tmpSaveUserDesign(DesignTemplate tmpTemplate, String dataSourceId, long supplierCode) {
        String outerSessionId = tmpTemplate.getTemplateName();
        String jsonContent = tmpTemplate.getJsonContent();

        String templateJson = redisService.get(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_SESSION, supplierCode, true)
                + outerSessionId);
        if (StringUtils.isEmpty(templateJson))
            return RetResult.<DesignTemplate>errorT().retinfo("当前设计已超时,请刷新后操作");
        DesignTemplate template = jsonConvert.convertFrom(DesignTemplate.class, templateJson);
        template.setJsonContent(jsonContent);

        //将当前临时模板记录在redis中,设置个过期时间就行了
        redisService.setex(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_SESSION, supplierCode, true)
                + outerSessionId, tempTemplateExpire, template);
        return RetResult.<DesignTemplate>successT();
    }

    @Override
    public RetResult<ProcessIdItem> saveCurrentUserTokenInfo(String virtualCode, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        RMap currentToken = new RMap();
        currentToken.set("dataSourceId", dataSourceId);
        currentToken.set("supplierCode", String.valueOf(supplierCode));
        String accessToken = ERPUtils.parseTokenFromERPUser(currentUser, tokenKey, jsonConvert);
        currentToken.set("token", accessToken);

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_SYS_USER_TOKEN, -1000), virtualCode, jsonConvert.convertTo(currentToken));
        return RetResult.successT();
    }

    @Override
    public RetResult<ProcessStringItem> getCurrentUserTokenInfo(String virtualCode) {
        String accessToken = redisService.hget(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_SYS_USER_TOKEN, -1000), virtualCode);
        if (StringUtils.isEmpty(accessToken)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("用户信息不正确");
        }
        RMap currentToken = jsonConvert.convertFrom(RMap.class, accessToken);
        ProcessStringItem resultItem = new ProcessStringItem();
        resultItem.setItemValue(currentToken.getString("token"));
        resultItem.setSupplierCode(currentToken.getLong("supplierCode"));
        resultItem.setDataSourceId(currentToken.getString("dataSourceId"));

        redisService.hdel(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_SYS_USER_TOKEN, -1000), virtualCode);

        return RetResult.<ProcessStringItem>successT().result(resultItem);
    }

    private DesignOrder convertTemplateToOrder(DesignTemplate designTemplate) {
        DesignOrder designOrder = new DesignOrder();
        designOrder.setIdTemplate(designTemplate.getId());
        designOrder.setOrderName("[" + designTemplate.getTemplateName() + "]" + ERPUtils.parseTimeFormat(new Date(), "yyyyMMddHHmmss") + "设计订单");
        designOrder.setProductIdentity(designTemplate.getProductIdentity());
        designOrder.setJsonContent(designTemplate.getJsonContent());

        return designOrder;
    }

    //region 设计订单
    @Override
    public RetResult<DesignOrder> newDesignOrder(String outerSessionId, String svgContent, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        String templateJson = redisService.get(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_SESSION, supplierCode, true)
                + outerSessionId);
        if (StringUtils.isEmpty(templateJson))
            return RetResult.<DesignOrder>errorT().retinfo("当前设计已超时,请刷新后操作");
        DesignTemplate template = jsonConvert.convertFrom(DesignTemplate.class, templateJson);
        //将缓存中的该session临时设计删掉了
        redisService.del(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_TEMPLATE_SESSION, supplierCode, true)
                + outerSessionId);

        svgContent = StringEscapeUtils.unescapeJava(svgContent);
        if (svgContent.startsWith("\"") && svgContent.endsWith("\"")) {
            svgContent = svgContent.substring(1, svgContent.length() - 1);
        }

        String fileName = ERPUtils.generateUUID() + ".svg";
        String fileUrl = designOutputRoot + File.separator + supplierCode +
                File.separator + fileName;
        Path path = Paths.get(fileUrl);

        try {
            if (!Files.exists(path.getParent())) {
                Files.createDirectories(path.getParent());
            }
            Files.write(path,
                    Collections.singleton(new StringBuilder(svgContent)),
                    StandardCharsets.UTF_8,
                    StandardOpenOption.CREATE,
                    StandardOpenOption.WRITE,
                    StandardOpenOption.TRUNCATE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //生成redis任务
        // 使用 SAXReader 解析 SVG 内容
        SAXReader reader = new SAXReader();
        Document document = null;
        try {
            document = reader.read(new StringReader(svgContent));
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }

        //生成订单结构
        DesignOrder designOrder = convertTemplateToOrder(template);
        designOrder.setId(tableIdService.getTableIdMulti("deDesignOrder.id", 1, dataSourceId, String.valueOf(supplierCode)));
        if (currentUser != null) {
            //后台测试
            designOrder.setUserIdentity(String.valueOf(currentUser.getId()));
            DesignOrder.create(designOrder, currentUser.getId());
        } else {
            //实际使用
            designOrder.setUserIdentity(outerSessionId);
            DesignOrder.create(designOrder, 999L);
        }


        // 获取 SVG 根元素
        Element rootElement = document.getRootElement();

        SVGTaskInfo taskInfo = new SVGTaskInfo();
        taskInfo.setHeight(rootElement.attributeValue("height").replace("px", ""));
        taskInfo.setWidth(rootElement.attributeValue("width").replace("px", ""));
        taskInfo.setSvgPath(fileUrl);
        taskInfo.setSvgFileName(fileName);
        taskInfo.setIdDesignOrder(designOrder.getId());

        redisService.rpush(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_SVG_TASK_LIST, supplierCode), jsonConvert.convertTo(taskInfo));


        //保存订单的设计文件信息
        String fileNameJson = orderContentRoot + File.separator + supplierCode +
                File.separator + designOrder.getId() + ".txt";
        Path pathJson = Paths.get(fileNameJson);

        String writeContent = "";
        if (StringUtils.isNotEmpty(designOrder.getJsonContent())) {
            writeContent = designOrder.getJsonContent();
        }
        try {
            if (!Files.exists(pathJson.getParent())) {
                Files.createDirectories(pathJson.getParent());
            }
            Files.write(pathJson,
                    Collections.singleton(new StringBuilder(writeContent)),
                    StandardCharsets.UTF_8,
                    StandardOpenOption.CREATE,
                    StandardOpenOption.WRITE,
                    StandardOpenOption.TRUNCATE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_EDIT, supplierCode), String.valueOf(designOrder.getId()), designOrder);
        convertJsonObjectsToOrder(designOrder, dataSourceId, supplierCode);
        designOrder.setJsonContent(fileNameJson);
        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_IMPOSITION, supplierCode), String.valueOf(designOrder.getId()), designOrder);

        designDao.addDesignOrder(designOrder, designOrder.getItemList(), dataSourceId, supplierCode);

        return RetResult.<DesignOrder>successT().result(designOrder);
    }

    @Override
    public RetResult<DesignOrder> newDesignOrder(DesignTemplate customerDesign, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        DesignOrder designOrder = convertTemplateToOrder(customerDesign);
        designOrder.setId(tableIdService.getTableIdMulti("deDesignOrder.id", 1, dataSourceId, String.valueOf(supplierCode)));
        designOrder.setUserIdentity(String.valueOf(currentUser.getId()));
        DesignOrder.create(designOrder, currentUser.getId());

        String fileName = orderContentRoot + File.separator + supplierCode +
                File.separator + designOrder.getId() + ".txt";
        Path path = Paths.get(fileName);

        String writeContent = "";
        if (StringUtils.isNotEmpty(designOrder.getJsonContent())) {
            writeContent = designOrder.getJsonContent();
        }
        try {
            if (!Files.exists(path.getParent())) {
                Files.createDirectories(path.getParent());
            }
            Files.write(path,
                    Collections.singleton(new StringBuilder(writeContent)),
                    StandardCharsets.UTF_8,
                    StandardOpenOption.CREATE,
                    StandardOpenOption.WRITE,
                    StandardOpenOption.TRUNCATE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_EDIT, supplierCode), String.valueOf(designOrder.getId()), designOrder);
        convertJsonObjectsToOrder(designOrder, dataSourceId, supplierCode);
        designOrder.setJsonContent(fileName);
        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_IMPOSITION, supplierCode), String.valueOf(designOrder.getId()), designOrder);

        designDao.addDesignOrder(designOrder, designOrder.getItemList(), dataSourceId, supplierCode);

        return RetResult.<DesignOrder>successT().result(designOrder);
    }

    @Override
    public RetResult<DesignOrder> updateDesignOrder(DesignOrder designOrder, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        RetResult<DesignOrder> redisOrderResult = getDesignOrderEdit(designOrder.getId(), dataSourceId, supplierCode);
        if (!redisOrderResult.isSuccess()) return redisOrderResult;
        DesignOrder redisOrder = redisOrderResult.getResult();

        designOrder.setIdTemplate(redisOrder.getIdTemplate());
        designOrder.setUserIdentity(redisOrder.getUserIdentity());
        designOrder.setOrderName(redisOrder.getOrderName());
        designOrder.setProductIdentity(redisOrder.getProductIdentity());

        DesignOrder.update(designOrder, currentUser.getId());

        String fileName = orderContentRoot + File.separator + supplierCode +
                File.separator + designOrder.getId() + ".txt";
        Path path = Paths.get(fileName);

        String writeContent = "";
        if (StringUtils.isNotEmpty(designOrder.getJsonContent())) {
            writeContent = designOrder.getJsonContent();
        }
        try {
            if (!Files.exists(path.getParent())) {
                Files.createDirectories(path.getParent());
            }
            Files.write(path,
                    Collections.singleton(new StringBuilder(writeContent)),
                    StandardCharsets.UTF_8,
                    StandardOpenOption.CREATE,
                    StandardOpenOption.WRITE,
                    StandardOpenOption.TRUNCATE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_EDIT, supplierCode), String.valueOf(designOrder.getId()), designOrder);
        convertJsonObjectsToOrder(designOrder, dataSourceId, supplierCode);
        designOrder.setJsonContent(fileName);
        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_IMPOSITION, supplierCode), String.valueOf(designOrder.getId()), designOrder);

        designDao.updateDesignOrder(designOrder, designOrder.getItemList(), dataSourceId, supplierCode);

        return RetResult.<DesignOrder>successT().result(designOrder);
    }

    @Override
    public RetResult<DesignOrder> downloadDesignPDF(String outerSessionId, String dataSourceId, long supplierCode) {
        RMap params = new RMap();
        params.put("userIdentity", outerSessionId);

        List<DesignOrder> orderList = designDao.selectDesignOrders(params, dataSourceId, supplierCode, null);
        if (orderList.isEmpty()) return RetResult.<DesignOrder>errorT().retinfo("未找到当前用户的设计订单");

        //假如多个,取最后一个
        DesignOrder designOrder = orderList.stream().sorted(Comparator.comparingLong(DesignOrder::getId).reversed()).toList().get(0);

        if (StringUtils.isBlank(designOrder.getPdfDownloadUrl()))
            return RetResult.<DesignOrder>successT().retcode(201).retinfo("当前设计订单生成中");
        else return RetResult.<DesignOrder>successT().result(designOrder).retinfo("success");
    }

    @Override
    public RetResult<List<DesignOrder>> queryDesignOrders(RMap params, PageFlipper pageFlipper, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        //默认来说这里查的都是自己的设计单
        int perm = permissionService.ifPermission(currentUser, "designOrder:view:all", null, dataSourceId, supplierCode);
        if (perm != 1)
            params.set("userIdentity", currentUser.getId());

        List<DesignOrder> orderList = designDao.selectDesignOrders(params, dataSourceId, supplierCode, pageFlipper);

        orderList.forEach(x -> x.setJsonContent(""));
        return RetResult.<List<DesignOrder>>successT().result(orderList);
    }

    @Override
    public RetResult<DesignOrder> getDesignOrderEdit(long id, String dataSourceId, long supplierCode) {
        DesignOrder redisOrder = getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_EDIT, supplierCode),
                String.valueOf(id), DesignOrder.class);

        if (redisOrder == null) return RetResult.<DesignOrder>errorT().retinfo("设计订单id不正确");
        else
            return RetResult.<DesignOrder>successT().result(redisOrder);
    }

    @Override
    public RetResult<DesignOrder> getDesignOrderImposition(long id, String dataSourceId, long supplierCode) {
        DesignOrder redisOrder = getRedisDocInfo(keysService.getRedisKey(RedisKeys.KEY_DESIGNER_DESIGN_ORDER_IMPOSITION, supplierCode),
                String.valueOf(id), DesignOrder.class);

        if (redisOrder == null) return RetResult.<DesignOrder>errorT().retinfo("设计订单id不正确");
        else
            return RetResult.<DesignOrder>successT().result(redisOrder);
    }

    //endregion


    //region 模板标签档案


    @Override
    public RetResult<List<DesignTagType>> queryDesignTagTypeFlatten(RMap params, String dataSourceId, long supplierCode, PageFlipper pageFlipper) {
        List<DesignTagType> typeList = designDao.queryDesignTagType(params, dataSourceId, supplierCode, pageFlipper);
        return RetResult.<List<DesignTagType>>successT().result(typeList).page(pageFlipper);
    }


    private void buildTypeTree(List<DesignTagType> designTagTypes, DesignTagType parentType) {
        List<DesignTagType> childrenTypes = designTagTypes.stream().filter(x -> x.getIdParentType() == parentType.getId()).findAny().stream().toList();
        parentType.setSubTypes(childrenTypes);

        childrenTypes.forEach(designTagType -> {
            buildTypeTree(designTagTypes, designTagType);
        });
    }

    @Override
    public RetResult<List<DesignTagType>> queryDesignTagType(String dataSourceId, long supplierCode) {
        List<DesignTagType> typeList = designDao.queryDesignTagType(new RMap(), dataSourceId, supplierCode);
        //手动创建一个未分组
        DesignTagType unGroupedType = new DesignTagType();
        unGroupedType.setIdParentType(0);
        unGroupedType.setId(0);
        unGroupedType.setName("未分组");
        typeList.add(unGroupedType);


        execPageFlipper(1000, (pageFlipper) -> {
            List<DesignTag> tagList = designDao.queryDesignTags(new RMap(), dataSourceId, supplierCode, pageFlipper);
            Map<Long, List<DesignTag>> groupTags = tagList.stream().collect(Collectors.groupingBy(DesignTag::getIdType));

            groupTags.forEach((k, v) -> {
                typeList.stream().filter(x -> x.getId() == k).findFirst().ifPresent(x -> x.getTags().addAll(v));
            });
        });

        //先自行找到root
        List<DesignTagType> roots = typeList.stream().filter(x -> x.getIdParentType() == 0).findAny().stream().toList();
        roots.forEach(designTagType -> {
            buildTypeTree(typeList, designTagType);
        });

        return RetResult.<List<DesignTagType>>successT().result(roots);
    }

    @Override
    public RetResult<DesignTagType> getDesignTagType(long idTagType, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        RMap params = new RMap();
        params.put("id", idTagType);

        DesignTagType designTagType = designDao.getDesignTagType(params, dataSourceId, supplierCode);
        if (designTagType == null) return RetResult.<DesignTagType>errorT().retinfo("查找的信息不存在");

        return RetResult.<DesignTagType>successT().result(designTagType);
    }

    @Override
    public RetResult<DesignTagType> newDesignTagType(DesignTagType tagType, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        tagType.setId(tableIdService.getTableIdMulti("deDesignTagType.id", 1, dataSourceId, String.valueOf(supplierCode)));
        DesignTagType.create(tagType, currentUser.getId());

        designDao.newDesignTagType(tagType, dataSourceId, supplierCode);

        return RetResult.<DesignTagType>successT().result(tagType);
    }

    private List<DesignTag> collectDesignTags(DesignTagType type) {
        List<DesignTag> tagList = type.getTags();
        type.getSubTypes().forEach(x -> {
            tagList.addAll(collectDesignTags(x));
        });

        return tagList;
    }

    private List<DesignTagType> collectDesignTypes(DesignTagType type) {
        List<DesignTagType> typeList = type.getSubTypes();
        typeList.forEach(x -> {
            typeList.addAll(collectDesignTypes(x));
        });

        return typeList;
    }


    //删除类别,则该类别下所有的tag置为未分组
    @Override
    public RetResult<DesignTagType> deleteDesignTagType(long id, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        List<DesignTagType> typeList = designDao.queryDesignTagType(new RMap(), dataSourceId, supplierCode);

        execPageFlipper(1000, (pageFlipper) -> {
            List<DesignTag> tagList = designDao.queryDesignTags(new RMap(), dataSourceId, supplierCode, pageFlipper);
            Map<Long, List<DesignTag>> groupTags = tagList.stream().collect(Collectors.groupingBy(DesignTag::getIdType));

            groupTags.forEach((k, v) -> {
                typeList.stream().filter(x -> x.getId() == k).findFirst().ifPresent(x -> x.getTags().addAll(v));
            });
        });

        DesignTagType toDeleteType = typeList.stream().filter(x -> x.getId() == id).findFirst().orElse(null);

        if (toDeleteType != null) {
            List<DesignTag> changeTagList = collectDesignTags(toDeleteType);
            changeTagList.forEach(x -> {
                x.setIdType(0);
            });

            List<DesignTagType> toDeleteTypeList = collectDesignTypes(toDeleteType);
            toDeleteTypeList.add(toDeleteType);

            designDao.deleteDesignTagType(toDeleteTypeList, changeTagList, dataSourceId, supplierCode);
        }
        return RetResult.successT();
    }

    @Override
    public RetResult<DesignTagType> deleteDesignTagTypeFlatten(long id, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        RMap params = new RMap();
        params.put("idType", id);


        List<DesignTag> tagList = designDao.queryDesignTags(params, dataSourceId, supplierCode);
        tagList.forEach(x -> {
            x.setIdType(0);
        });

        List<DesignTagType> toDeleteList = new ArrayList<>();
        DesignTagType toDeleteType = new DesignTagType();
        toDeleteType.setId(id);
        toDeleteList.add(toDeleteType);

        designDao.deleteDesignTagType(toDeleteList, tagList, dataSourceId, supplierCode);
        return RetResult.successT();
    }

    @Override
    public RetResult<DesignTagType> updateDesignTagType(DesignTagType tagType, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        DesignTagType.update(tagType, currentUser.getId());
        designDao.updateDesignTagType(tagType, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    public RetResult<List<DesignTag>> queryDesignTags(RMap params, String dataSourceId, long supplierCode, PageFlipper pageFlipper) {
        List<DesignTag> designTags = designDao.queryDesignTags(params, dataSourceId, supplierCode, pageFlipper);
        return RetResult.<List<DesignTag>>successT().result(designTags).page(pageFlipper);
    }

    @Override
    public RetResult<DesignTag> newDesignTag(DesignTag designTag, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        designTag.setId(tableIdService.getTableIdMulti("deDesignTag.id", 1, dataSourceId, String.valueOf(supplierCode)));
        DesignTag.create(designTag, currentUser.getId());

        designDao.newDesignTag(designTag, dataSourceId, supplierCode);
        return RetResult.<DesignTag>successT().result(designTag);
    }

    @Override
    public RetResult<List<DesignTag>> changeTagType(List<DesignTag> tagList, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        tagList.forEach(x -> {
            DesignTag.update(x, currentUser.getId());
        });

        designDao.changeTagType(tagList, dataSourceId, supplierCode);
        return RetResult.successT();
    }

    @Override
    public RetResult<DesignTag> deleteDesignTag(long id, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        DesignTag designTag = new DesignTag();
        designTag.setId(id);

        designDao.deleteDesignTag(designTag, dataSourceId, supplierCode);
        return RetResult.successT();
    }
    //endregion

    //region 模板标签
    @Override
    public RetResult<List<TemplateTag>> getTemplateTags(long idTemplate, String dataSourceId, long supplierCode) {
        RMap params = new RMap();
        params.put("ids", new Long[]{idTemplate});
        List<TemplateTag> tags = designDao.getTemplateTags(params, dataSourceId, supplierCode);
        return RetResult.<List<TemplateTag>>successT().result(tags);
    }

    @Override
    public RetResult<List<TemplateTag>> modifyTemplateTags(long idTemplate, List<DesignTag> tags, String dataSourceId, long supplierCode, ERPTokenUser currentUser) {
        RMap params = new RMap();
        params.put("idTemplate", idTemplate);

        List<Long> ids = tags.stream().map(DesignTag::getIdType).filter(idType -> idType > 0).toList();
        RMap searchParams = new RMap();
        searchParams.put("ids", ids);
        List<DesignTagType> typeList = designDao.queryDesignTagType(searchParams, dataSourceId, supplierCode);

        long idTemplateTag = tableIdService.getTableIdMulti("deTemplateTag.id", tags.size(), dataSourceId, String.valueOf(supplierCode));
        List<TemplateTag> templateTags = new ArrayList<>();
        for (DesignTag x : tags) {
            DesignTagType type = typeList.stream().filter(y -> y.getId() == x.getIdType()).findFirst().orElse(null);
            TemplateTag templateTag = new TemplateTag();
            templateTag.setId(idTemplateTag++);
            templateTag.setIdTemplate(idTemplate);
            templateTag.setTagName(x.getTagName());
            if (type != null)
                templateTag.setTagTypeName(type.getName());
            else {
                if (StringUtils.isBlank(x.getTagTypeName()))
                    templateTag.setTagTypeName("未分组");
                else templateTag.setTagTypeName(x.getTagTypeName());
            }
            TemplateTag.create(templateTag, currentUser.getId());
            templateTags.add(templateTag);
        }

        designDao.modifyTemplateTags(params, templateTags, dataSourceId, supplierCode);
        return RetResult.successT();
    }
    //endregion
}
