Excel导出模块翻译值

由于目前翻译资源导出只可以导出应用资源,无法导出模块资源,所以暂时提供以下方法导出模块资源。
6.2.11、5.7.4.20 之前版本验证

方案一:

导出环境覆盖以下类

package pro.shushi.pamirs.translate.template.imports;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.file.api.context.ExcelDefinitionContext;
import pro.shushi.pamirs.file.api.entity.ExcelExportFetchDataContext;
import pro.shushi.pamirs.file.api.extpoint.impl.DefaultExcelExportFetchDataExtPoint;
import pro.shushi.pamirs.file.api.model.ExcelExportTask;
import pro.shushi.pamirs.framework.connectors.data.sql.Pops;
import pro.shushi.pamirs.framework.connectors.data.sql.query.LambdaQueryWrapper;
import pro.shushi.pamirs.framework.connectors.data.sql.query.QueryWrapper;
import pro.shushi.pamirs.meta.annotation.Ext;
import pro.shushi.pamirs.meta.annotation.ExtPoint;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;
import pro.shushi.pamirs.meta.api.Models;
import pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper;
import pro.shushi.pamirs.meta.common.lambda.LambdaUtil;
import pro.shushi.pamirs.meta.common.util.PStringUtils;
import pro.shushi.pamirs.meta.constant.SqlConstants;
import pro.shushi.pamirs.meta.domain.module.ModuleDefinition;
import pro.shushi.pamirs.resource.api.enmu.TranslationApplicationScopeEnum;
import pro.shushi.pamirs.resource.api.model.ResourceTranslation;
import pro.shushi.pamirs.resource.api.model.ResourceTranslationItem;
import pro.shushi.pamirs.translate.constant.TranslateConstants;
import pro.shushi.pamirs.translate.proxy.TranslationItemExportProxy;
import pro.shushi.pamirs.translate.service.TranslationDslNodeVisitor;
import pro.shushi.pamirs.translate.template.TranslateTemplate;
import pro.shushi.pamirs.translate.utils.UniversalParser;

import java.util.*;
import java.util.stream.Collectors;

import static pro.shushi.pamirs.translate.constant.TranslateConstants.FIELD_TO_EXCLUDE;

/**
 * @author Adamancy Zhang
 * @date 2020-11-04 18:09
 */
@Slf4j
@Component
@Ext(ExcelExportTask.class)
@SuppressWarnings({"unchecked"})
public class ResourceTranslationExportExtPoint extends DefaultExcelExportFetchDataExtPoint {

    private String resLangCodeColumn = PStringUtils.fieldName2Column(LambdaUtil.fetchFieldName(ResourceTranslationItem::getResLangCode));
    private String langCodeColumn = PStringUtils.fieldName2Column(LambdaUtil.fetchFieldName(ResourceTranslationItem::getLangCode));
    private String moduleColumn = PStringUtils.fieldName2Column(LambdaUtil.fetchFieldName(ResourceTranslationItem::getModule));

    @Override
    @ExtPoint.Implement(expression = "context.name=="" + TranslateTemplate.TEMPLATE_NAME + "" && context.model=="" + ResourceTranslation.MODEL_MODEL + """)
    public List<Object> fetchExportData(ExcelExportTask exportTask, ExcelDefinitionContext context) {
        ArrayList<Object> objects = new ArrayList<>();
        Map<String, Object> queryData = exportTask.getConditionWrapper().getQueryData();

        TranslationItemExportProxy data = JSON.parseObject(JSON.toJSONString(queryData), TranslationItemExportProxy.class);
        LambdaQueryWrapper<TranslationItemExportProxy> queryWrapper = Pops.<TranslationItemExportProxy>lambdaQuery()
                .from(TranslationItemExportProxy.MODEL_MODEL)
                .eq(StringUtils.isNotBlank(data.getModule()), ResourceTranslationItem::getModule, data.getModule())
                .eq(ResourceTranslationItem::getResLangCode, TranslateConstants.RES_LANG_CODE)
                .eq(StringUtils.isNotBlank(data.getLangCode()), ResourceTranslationItem::getLangCode, data.getLangCode())
                .eq(data.getState() != null, ResourceTranslationItem::getState, data.getState())
                .like(StringUtils.isNotBlank(data.getResLangInclude()), ResourceTranslationItem::getOrigin, data.getResLangInclude())
                .like(StringUtils.isNotBlank(data.getTargetInclude()), ResourceTranslationItem::getTarget, data.getResLangInclude());

        Map<String, String> moduleNameMap = Models.origin().queryListByWrapper(Pops.<ModuleDefinition>lambdaQuery()
                        .from(ModuleDefinition.MODEL_MODEL)
                        .eq(StringUtils.isNotBlank(data.getModule()), ModuleDefinition::getModule, data.getModule()))
                .stream()
                .collect(Collectors.toMap(ModuleDefinition::getModule, ModuleDefinition::getDisplayName, (_a, _b) -> _a));
        ModuleDefinition moduleDefinition = new ModuleDefinition();
        moduleDefinition.setModule(TranslateConstants.PUBLIC_RESOURCE);
        moduleDefinition = moduleDefinition.queryOne();
        moduleNameMap.put(moduleDefinition.getModule(), moduleDefinition.getDisplayName());

        List<TranslationItemExportProxy> translationItemExportProxies = new ArrayList<>();
        //TODO 源语言无法识别请在YAML 中直接配置
        switch (data.getIsTranslate()) {
            case TRANSLATED:
                queryWrapper.eq(data.getScope() != null, ResourceTranslationItem::getScope, data.getScope()).isNotNull(ResourceTranslationItem::getTarget);
                translationItemExportProxies = new TranslationItemExportProxy().queryList(queryWrapper);
                Models.origin().listFieldQuery(translationItemExportProxies, TranslationItemExportProxy::getTranslation);
                if (CollectionUtils.isNotEmpty(translationItemExportProxies)) {
                    for (TranslationItemExportProxy item : translationItemExportProxies) {
                        item.setModule(Optional.ofNullable(item.getModule()).map(moduleNameMap::get).orElse(item.getModule()));
                        item.setComments(Optional.ofNullable(item.getTranslation().getComments()).orElse(""));
                    }
                }
                if (CollectionUtils.isNotEmpty(translationItemExportProxies)) {
                    objects.add(translationItemExportProxies);
                }
                break;
            case NOT_TRANSLATED:
                translationItemExportProxies = new TranslationItemExportProxy().queryList(queryWrapper);
                if (CollectionUtils.isNotEmpty(translationItemExportProxies)) {
                    translationItemExportProxies = new TranslationItemExportProxy().listFieldQuery(translationItemExportProxies, TranslationItemExportProxy::getTranslation);
                }
                if (TranslationApplicationScopeEnum.GLOBAL.equals(data.getScope()) || Boolean.TRUE.equals(data.getState())
                        || StringUtils.isNotBlank(data.getTargetInclude()) || StringUtils.isNotBlank(data.getResLangInclude())) {
                    break;
                }
                //解析XML
                Map<String, Set<String>> translationContext = parseXmlAndModelAndEnumAndErrorInfo(data, moduleNameMap);

                // 初始化结果容器
                List<TranslationItemExportProxy> noTranslateItems = new ArrayList<>();
                Map<Boolean, Map<String, List<String>>> origins = new HashMap<>();
                origins.put(true, new HashMap<>());
                origins.put(false, new HashMap<>());

                // 单次遍历处理两个操作
                translationItemExportProxies.forEach(item -> {
                    // 处理第一个过滤和收集操作
                    if (StringUtils.isEmpty(item.getTarget()) && Boolean.TRUE.equals(Optional.ofNullable(item.getSystem()).orElse(Boolean.FALSE))) {
                        item.setModule(Optional.ofNullable(item.getModule()).map(moduleNameMap::get).orElse(item.getModule()));
                        item.setState(false);
                        item.setComments("");
                        item.setLangCode(Optional.ofNullable(data.getLangCode()).orElse(""));
                        item.setResLangCode(TranslateConstants.RES_LANG_CODE);
                        noTranslateItems.add(item);
                    }

                    // 处理分类和收集操作
                    if (TranslationApplicationScopeEnum.GLOBAL.equals(item.getScope()) || TranslationApplicationScopeEnum.MODULE.equals(item.getScope())) {
                        boolean isGlobal = TranslationApplicationScopeEnum.GLOBAL.equals(item.getScope());
                        String module = isGlobal ? "" : item.getModule();

                        origins.computeIfAbsent(isGlobal, k -> new HashMap<>())
                                .computeIfAbsent(module, k -> new ArrayList<>())
                                .add(item.getOrigin());
                    }
                });

                List<String> overallOrigins = origins.get(true).get("");
                Map<String, List<String>> applicationOrigins = origins.get(false);

                for (Map.Entry<String, Set<String>> entry : translationContext.entrySet()) {
                    if (applicationOrigins.containsKey(entry.getKey())) {
                        List<String> list = applicationOrigins.get(entry.getKey());
                        entry.getValue().removeAll(list);
                        entry.getValue().removeAll(overallOrigins);
                    }
                }

                //生成系统中未翻译的字段
                translationItemExportProxies = getTranslationItemExportProxies(moduleNameMap, translationContext, data);
                translationItemExportProxies.addAll(noTranslateItems);
                if (CollectionUtils.isNotEmpty(translationItemExportProxies)) {
                    objects.add(translationItemExportProxies);
                }
                break;
            default:
                List<TranslationItemExportProxy> result = new ArrayList<>();
                queryWrapper.eq(data.getScope() != null, ResourceTranslationItem::getScope, data.getScope());
                translationItemExportProxies = new TranslationItemExportProxy().queryList(queryWrapper);
                if (CollectionUtils.isNotEmpty(translationItemExportProxies)) {
                    translationItemExportProxies = new TranslationItemExportProxy().listFieldQuery(translationItemExportProxies, TranslationItemExportProxy::getTranslation);
                }

                if (TranslationApplicationScopeEnum.GLOBAL.equals(data.getScope()) || Boolean.TRUE.equals(data.getState()) || StringUtils.isNotBlank(data.getTargetInclude())) {
                    if (CollectionUtils.isNotEmpty(translationItemExportProxies)) {
                        for (TranslationItemExportProxy item : translationItemExportProxies) {
                            item.setModule(Optional.ofNullable(item.getModule()).map(moduleNameMap::get).orElse(item.getModule()));
                            item.setComments(Optional.ofNullable(item.getTranslation()).map(ResourceTranslation::getComments).orElse(null));
                        }
                        result.addAll(translationItemExportProxies);
                        objects.add(result);
                    }
                    break;
                }
                Map<String, Set<String>> tContext = parseXmlAndModelAndEnumAndErrorInfo(data, moduleNameMap);

                Map<Boolean, Map<String, List<String>>> origins0 = translationItemExportProxies.stream()
                        .filter(item -> TranslationApplicationScopeEnum.GLOBAL.equals(item.getScope()) || TranslationApplicationScopeEnum.MODULE.equals(item.getScope()))
                        .collect(Collectors.partitioningBy(
                                item -> TranslationApplicationScopeEnum.GLOBAL.equals(item.getScope()),
                                Collectors.groupingBy(
                                        item -> TranslationApplicationScopeEnum.MODULE.equals(item.getScope()) ? item.getModule() : "",
                                        Collectors.mapping(TranslationItemExportProxy::getOrigin, Collectors.toList())
                                )
                        ));

                List<String> overOrigins = origins0.get(true).getOrDefault("", Collections.emptyList());
                Map<String, List<String>> applicationsOrigins = origins0.get(false);

                for (Map.Entry<String, Set<String>> entry : tContext.entrySet()) {
                    if (applicationsOrigins.containsKey(entry.getKey())) {
                        List<String> list = applicationsOrigins.get(entry.getKey());
                        entry.getValue().removeAll(list);
                        entry.getValue().removeAll(overOrigins);
                    }
                }

                //生成系统中未翻译的字段
                List<TranslationItemExportProxy> noTranslation = getTranslationItemExportProxies(moduleNameMap, tContext, data);
                if (CollectionUtils.isNotEmpty(translationItemExportProxies)) {
                    for (TranslationItemExportProxy item : translationItemExportProxies) {
                        item.setModule(Optional.ofNullable(item.getModule()).map(moduleNameMap::get).orElse(item.getModule()));
                        item.setComments(Optional.ofNullable(item.getTranslation()).map(ResourceTranslation::getComments).orElse(null));
                    }
                    result.addAll(translationItemExportProxies);
                }
                if (CollectionUtils.isNotEmpty(noTranslation)) {
                    result.addAll(noTranslation);
                }
                objects.add(result);
                break;
        }
        return objects;
    }

    private Map<String, Set<String>> parseXmlAndModelAndEnumAndErrorInfo(TranslationItemExportProxy data, Map<String, String> moduleNameMap) {
        //解析XML
        TranslationDslNodeVisitor translationVisitor = UniversalParser.getTranslationDslNodeVisitor(data);
        Map<String, Set<String>> tContext = translationVisitor.context;
        //解析模型
        UniversalParser.parseModel(moduleNameMap, tContext, data.getModule());
        //解析枚举
        UniversalParser.parseModelEnum(moduleNameMap, tContext, data.getModule());
        //解析错误信息
        UniversalParser.parseErrorInfo(moduleNameMap, tContext, data.getModule());
        return tContext;
    }

    /**
     * 生成系统中未翻译的字段
     *
     * @param moduleNameMap      模块编码与名称的映射
     * @param translationContext 需要翻译的字段
     * @param data
     * @return
     */
    private static List<TranslationItemExportProxy> getTranslationItemExportProxies(Map<String, String> moduleNameMap, Map<String, Set<String>> translationContext, TranslationItemExportProxy data) {
        List<TranslationItemExportProxy> translationItemExportProxies = new ArrayList<>();

        for (Map.Entry<String, Set<String>> entry : translationContext.entrySet()) {
            for (String origin : entry.getValue()) {
                if (FIELD_TO_EXCLUDE.contains(origin.toLowerCase())) {
                    continue;
                }
                if (StringUtils.isNotBlank(data.getResLangInclude())) {
                    if (origin.contains(data.getResLangInclude())) {
                        TranslationItemExportProxy item = new TranslationItemExportProxy();
                        item.setModule(Optional.ofNullable(entry.getKey()).map(moduleNameMap::get).orElse(entry.getKey()));
                        item.setResLangCode(TranslateConstants.RES_LANG_CODE);
                        item.setLangCode(Optional.ofNullable(data.getLangCode()).orElse(""));
                        item.setOrigin(origin);
                        item.setState(false);
                        item.setScope(TranslationApplicationScopeEnum.MODULE);
                        item.setComments("");
                        translationItemExportProxies.add(item);
                    }
                } else {
                    TranslationItemExportProxy item = new TranslationItemExportProxy();
                    item.setModule(Optional.ofNullable(entry.getKey()).map(moduleNameMap::get).orElse(entry.getKey()));
                    item.setResLangCode(TranslateConstants.RES_LANG_CODE);
                    item.setLangCode(Optional.ofNullable(data.getLangCode()).orElse(""));
                    item.setOrigin(origin);
                    item.setState(false);
                    item.setScope(TranslationApplicationScopeEnum.MODULE);
                    item.setComments("");
                    translationItemExportProxies.add(item);

                }
            }
        }
        return translationItemExportProxies;
    }

    @Override
    protected IWrapper<?> queryBefore(ExcelExportFetchDataContext context, IWrapper<?> wrapper) {
        wrapper.setModel(ResourceTranslation.MODEL_MODEL);
        List<?> translations = Models.data().queryListByWrapper(wrapper);

        QueryWrapper<ResourceTranslationItem> itemWrapper = Pops.query();
        itemWrapper.setModel(ResourceTranslationItem.MODEL_MODEL);

        if (CollectionUtils.isEmpty(translations)) {
            itemWrapper.lt(SqlConstants.ID, 0);
        } else {
            itemWrapper.in(
                    Lists.newArrayList(resLangCodeColumn, langCodeColumn, moduleColumn),
                    translations.stream()
                            .map(i -> ((ResourceTranslation) i).getResLangCode())
                            .collect(Collectors.toList()),
                    translations.stream()
                            .map(i -> ((ResourceTranslation) i).getLangCode())
                            .collect(Collectors.toList()),
                    translations.stream()
                            .map(i -> ((ResourceTranslation) i).getModule())
                            .collect(Collectors.toList())
            );
        }
        return itemWrapper;
    }
}
package pro.shushi.pamirs.translate.action;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.core.common.WrapperHelper;
import pro.shushi.pamirs.framework.connectors.cdn.factory.FileClientFactory;
import pro.shushi.pamirs.framework.connectors.data.sql.query.LambdaQueryWrapper;
import pro.shushi.pamirs.framework.gateways.rsql.RSQLHelper;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.api.dto.condition.Pagination;
import pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper;
import pro.shushi.pamirs.meta.constant.FunctionConstants;
import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum;
import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum;
import pro.shushi.pamirs.translate.constant.TranslateConstants;
import pro.shushi.pamirs.translate.proxy.TranslationModuleProxy;

import java.util.List;

@Component
@Model.model(TranslationModuleProxy.MODEL_MODEL)
public class TranslationModuleProxyAction {

    @Function.Advanced(type = FunctionTypeEnum.QUERY)
    @Function.fun(FunctionConstants.queryPage)
    @Function(openLevel = {FunctionOpenEnum.LOCAL, FunctionOpenEnum.REMOTE, FunctionOpenEnum.API})
    public Pagination<TranslationModuleProxy> queryPage(Pagination<TranslationModuleProxy> page, IWrapper<TranslationModuleProxy> queryWrapper) {
        String displayName = RSQLHelper.getFieldValue(TranslationModuleProxy.MODEL_MODEL, queryWrapper.getOriginRsql(), TranslationModuleProxy::getDisplayName).orElse("");
        LambdaQueryWrapper<TranslationModuleProxy> qw = WrapperHelper.lambda(queryWrapper);

        if (StringUtils.isEmpty(displayName) || TranslateConstants.PUBLIC_RESOURCE_NAME.contains(displayName.replace("%", ""))) {
            qw.or(item -> item.eq(TranslationModuleProxy::getModule, TranslateConstants.PUBLIC_RESOURCE));
        }

        Pagination<TranslationModuleProxy> translationModuleProxyPagination = new TranslationModuleProxy().queryPage(page, qw);
        TranslationModuleProxy translationModuleProxy = null;
        List<TranslationModuleProxy> content = translationModuleProxyPagination.getContent();
        if (CollectionUtils.isNotEmpty(content)) {
            for (TranslationModuleProxy moduleProxy : content) {
                if (TranslateConstants.PUBLIC_RESOURCE.equals(moduleProxy.getModule())) {
                    translationModuleProxy = moduleProxy;
                }
                String logo = moduleProxy.getLogo();
                if (StringUtils.isBlank(logo)) {
                    logo = FileClientFactory.getClient().getStaticUrl() + "/oinone/static/images/default.png";
                }
                moduleProxy.setLogo(logo);
            }
        }
        if (translationModuleProxy != null) {
            content.remove(translationModuleProxy);
            content.add(0, translationModuleProxy);
        }
        return translationModuleProxyPagination;
    }
}

替换完毕之后即可在 翻译 - 导出 页面导出模块资源。

方案二:如无法替换文件,可使用以下方案

与翻译的导出全部翻译项类似,需要通过工具发起后端服务请求,拿到导入导出翻译Excel模版,添加模版翻译项。(查看路径:文件--导出任务)

{
  translationItemExportProxyQuery {
    export(
      data: {isTranslate: ALL, module: "top_demo", state: true, langCode: null}
    ) {
      isTranslate
      moduleDefinition {
        displayName
        module
        id
      }
      module
      state
      lang {
        code
        name
        id
      }
      langCode
      scope
      resLangInclude
      targetInclude
      id
    }
  }
}

参数说明:isTranslate 是否全部翻译项;module 模块编码;state 是否激活

修改翻译文件

拿到导出的翻译文件之后,将模版里的应用名字由 模块编码 替换为 模块展示名字,全部替换之后方可成功导入
Excel导出模块翻译值

导入翻译项

进入 翻译 — 导入翻译文件 导入修改后的翻译文件。

Oinone社区 作者:yexiu原创文章,如若转载,请注明出处:https://doc.oinone.top/other/21558.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

Like (0)
yexiu's avataryexiu数式员工
Previous 2025年8月14日 pm5:55
Next 2025年8月22日 am10:51

相关推荐

  • 自定义字段样式

    在日常开发中,我们经常会遇到需要根据业务规则动态展示字段样式的场景,比如表格、表单或详情中的某些字段需要改变文字颜色。本文将通过一个具体的案例,带大家实现这一功能。 以下以 自定义表格字段文字颜色 为例。 实现步骤 1. 在界面设计器中添加组件 通过界面设计器,添加一个组件 2. 创建元件 以表格的「金额字段」为例,创建对应的元件(可根据自己的业务场景调整)。 3. 配置元件属性 进入元件设计页面,从组件库中拖入「单行文本」到设计区域。在右侧属性面板中填写相关配置并保存 4. 保存元件 完成配置后,保存元件。 5. 发布元件 将元件发布,供页面设计使用。 6. 切换表格字段 进入页面设计器,将表格中的字段切换为刚刚创建的元件。 7. 配置字段颜色 在右侧属性面板中,配置字段的文字颜色: 固定颜色:直接输入颜色值(如 red)。 动态颜色:输入表达式,根据业务逻辑动态展示颜色。例如:当前行的名称等于 1 时显示红色,否则为蓝色。 示例表达式: activeRecord.name === '1' ? 'red' : 'blue' 8: 在代码中,自定义对应的表格字段 import { SPI, BaseFieldWidget, ModelFieldType, ViewType, TableCurrencyFieldWidget, Widget, RowContext, numberZeroFill, numberAddThousandth, Expression, ExpressionRunParam } from '@kunlun/dependencies'; import { toString } from 'lodash-es'; import { createVNode, VNode } from 'vue'; @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: [ViewType.Table], ttype: [ModelFieldType.Currency], widget: 'TableCurrencyColor' }) ) export class TableCustomCurrencyFieldWidget extends TableCurrencyFieldWidget { computedFieldColor(context: RowContext) { const { fieldColor = ' ' } = this.getDsl(); if (!fieldColor) { return null; } // 如果当前颜色是表达式,则需要计算 if (Expression.hasKeywords(fieldColor)) { const params: ExpressionRunParam = { activeRecords: [context.data], rootRecord: {}, openerRecord: {}, scene: '' }; return Expression.run(params, fieldColor, fieldColor)!; } return fieldColor; } @Widget.Method() public renderDefaultSlot(context: RowContext): VNode[] | string { let value = numberZeroFill(toString(super.compute(context)), this.getPrecision(context)); if (this.getShowThousandth(context)) { value = numberAddThousandth(value); } return [ createVNode( 'div', { style: { color: this.computedFieldColor(context) } }, value ) ]; } } 9: 页面效果图

    2025年1月9日
    6.5K00
  • 后端脚手架生成工程

    后端脚手架生成工程 脚手架版本 6.2.x(6.3.x/6.4.x)版本的脚手架,修改脚本(参考下节内容)中脚手架版本: # 新项目的pamirs platform version pamirsVersion=6.2.8 …… # mvn archetype:generate执行片段中 -DarchetypeVersion=6.2.8 7.0.x版本的脚手架,修改脚本(参考下节内容)中脚手架版本: # 新项目的pamirs platform version pamirsVersion=7.0.5 …… # mvn archetype:generate执行片段中 -DarchetypeVersion=7.0.5 后端脚手架生成工程 后端单工程脚手架 1、使用如下命令来用项目脚手架生成工程:新建archetype-project-generate.sh(bat) 脚本 archetype-project-generate.sh #!/bin/bash # 项目生成脚手架 # 用于新项目的构建 # 脚手架使用目录 # 本地 local # 本地脚手架信息存储路径 ~/.m2/repository/archetype-catalog.xml archetypeCatalog=local # 以下参数以pamirs-demo为例 # 新项目的groupId groupId=pro.shushi.pamirs.demo # 新项目的artifactId artifactId=pamirs-demo # 新项目的version version=1.0.0-SNAPSHOT # Java包名前缀 packagePrefix=pro.shushi # Java包名后缀 packageSuffix=pamirs.demo # 新项目的pamirs platform version;根据上个章节中的版本介绍进行修改 pamirsVersion=6.2.8 # Java类名称前缀 javaClassNamePrefix=Demo # 项目名称 module.displayName projectName=OinoneDemo # 模块 MODULE_MODULE 常量 moduleModule=demo_core # 模块 MODULE_NAME 常量 moduleName=DemoCore # spring.application.name applicationName=pamirs-demo # tomcat server address serverAddress=0.0.0.0 # tomcat server port serverPort=8090 # redis host redisHost=127.0.0.1 # redis port redisPort=6379 # 数据库名 db=demo # zookeeper connect string zkConnectString=127.0.0.1:2181 # zookeeper rootPath zkRootPath=/demo mvn archetype:generate \ -DinteractiveMode=false \ -DarchetypeCatalog=${archetypeCatalog} \ -DarchetypeGroupId=pro.shushi.pamirs.archetype \ -DarchetypeArtifactId=pamirs-project-archetype \ -DarchetypeVersion=6.2.8 \ #根据上个章节中的版本介绍进行修改 -DgroupId=${groupId} \ -DartifactId=${artifactId} \ -Dversion=${version} \ -DpamirsVersion=${pamirsVersion} \ -Dpackage=${packagePrefix}.${packageSuffix} \ -DpackagePrefix=${packagePrefix} \ -DpackageSuffix=${packageSuffix} \ -DjavaClassNamePrefix=${javaClassNamePrefix} \ -DprojectName="${projectName}" \ -DmoduleModule=${moduleModule} \ -DmoduleName=${moduleName} \ -DapplicationName=${applicationName} \ -DserverAddress=${serverAddress} \ -DserverPort=${serverPort} \ -DredisHost=${redisHost} \ -DredisPort=${redisPort} \ -Ddb=${db} \ -DzkConnectString=${zkConnectString} \ -DzkRootPath=${zkRootPath} archetype-project-generate.bat @echo off :: 项目生成脚手架 set archetypeCatalog=local set groupId=pro.shushi.pamirs.demo set artifactId=pamirs-demo set version=1.0.0-SNAPSHOT set…

    2025年8月22日
    99600
  • 前端学习路径

    准备工作 环境准备-1h安装基础环境,需要Node和PNPM如果已经安装检查对应版本,体验阶段建议版本保持一致 克隆一个空工程-0.5h全新工程 注意事项-0.5h静态资源解压,如果还没有对应的后端服务。可以使用:https://demo.oinone.top(Oinone演示环境),账号密码:admin/admin 前端基础 1.1.1了解组件-3h– 组件如何开发– 组件如何复用– 组件如何嵌套 1.1.2 更近一步-5h– 构建更复杂的工作台– 如何发起后端请求– 构建一个通用的图表组件 1.1.3 深入了解概念-5h– 通用概念、名词解释– 页面渲染原理– 组件执行原理 1.1.4业务实战-实现通用的甘特图组件-8h– 怎么与第三方结合– 如何在开源组件上接入Oinone, 并复用 1.1.5 业务实战-实现通用的画廊组件-6h–如何更近一步复用–基础学习结束 前端进阶 2.1.1代码和无代码如何结合-4h– 了解无代码如何使用和基础概念 2.1.2使用无代码搭建增删改查-8h– 了解无代码如何使用和基础概念 最后一步 当您实现玩基础和进阶的所有的效果,Oinone的整体使用您已经大致掌握了,接下来您可以找一个当前业务的场景来实现它把!

    2025年9月1日
    1.2K00
  • IP黑白名单实现拦截三方用户

    已知厂商IP为10.139.0.1,经系统检测122.233.24.28、138.122.12.9为风险IP,需要禁止访问。 白名单配置:10.139.0.1 黑名单配置:122.233.24.28、138.122.12.9 厂商请求到Oinone开放平台请求头需携带X-Forwarded-For和X-Real-IP,例如: X-Forwarded-For 122.233.24.28 X-Real-IP 122.233.24.28 经Nginx代理后,oinone获取的请求头内容: X-Forwarded-For 122.233.24.28, 10.139.0.1 # 代理追加厂商IP到末尾 X-Real-IP 122.233.24.28 # 保持客户端原始值,Nginx不处理 效果:厂商10.139.0.1发送的请求且用户X-Real-IP不在黑名单内才放行。 注意事项 Nginx如果配置X-Real-IP需关闭,否则拿到的永远是厂商IP。 proxy_set_header X-Real-IP $remote_addr; 相关文章 开放应用中的ip黑白名单

    2025年5月15日
    66100
  • 如何设计公用跳转动作(类似导入导出动作)

    背景 设计一个公共动作,在界面设计器可以拖到页面里,点击之后跳转指定页面。就像导入导出一样。 实现思路 元数据计算时,初始化跳转动作,为本模块以及依赖于本模块的所有模块生成该跳转动作。实现所有模型都有该跳转动作的元数据。 代码示例: package pro.shushi.pamirs.top.core.init; import com.google.common.collect.Lists; import org.apache.commons.collections4.MapUtils; import org.springframework.stereotype.Component; import pro.shushi.pamirs.boot.base.enmu.ActionTargetEnum; import pro.shushi.pamirs.boot.base.enmu.ActionTypeEnum; import pro.shushi.pamirs.boot.base.model.ViewAction; import pro.shushi.pamirs.boot.common.api.command.AppLifecycleCommand; import pro.shushi.pamirs.boot.common.extend.MetaDataEditor; import pro.shushi.pamirs.core.common.InitializationUtil; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.meta.Meta; import pro.shushi.pamirs.meta.api.dto.meta.MetaData; import pro.shushi.pamirs.meta.domain.model.ModelDefinition; import pro.shushi.pamirs.meta.enmu.ActionContextTypeEnum; import pro.shushi.pamirs.meta.enmu.SystemSourceEnum; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; import pro.shushi.pamirs.top.api.TopModule; import pro.shushi.pamirs.top.api.model.Teacher; import java.util.*; import java.util.stream.Collectors; @Slf4j @Component public class DemoModuleAppInstall implements MetaDataEditor { @Override public void edit(AppLifecycleCommand command, Map<String, Meta> metaMap) { InitializationUtil util = InitializationUtil.get(metaMap, TopModule.MODULE_MODULE, TopModule.MODULE_NAME); if (util == null) { return; } if (MapUtils.isEmpty(metaMap)) { return; } Set<String> dependencyFileModels = metaMap.values().stream() .filter(v -> v.getData().containsKey(TopModule.MODULE_MODULE)) .map(Meta::getModule) .collect(Collectors.toSet()); for (String module : metaMap.keySet()) { if (!dependencyFileModels.contains(module)) { // 不依赖本模块,不生成跳转动作 continue; } Meta meta = metaMap.get(module); MetaData metaData = meta.getCurrentModuleData(); List<ModelDefinition> modelList = metaData.getDataList(ModelDefinition.MODEL_MODEL); for (ModelDefinition data : modelList) { makeDefaultModelViewAction(meta, data, dependencyFileModels); } } } // 跳转的xml模版 name public static final String DEFAULT_VIEW_NAME = "fixed_teacher_table"; private void makeDefaultModelViewAction(Meta meta, ModelDefinition data, Set<String> dependencyFileModels) { if (!dependencyFileModels.contains(data.getModule())) { // 当前模块使用了其他模块的模型,对方模块未依赖本模块,不生成跳转动作 return; } Map<String, Object> context = new HashMap<>(); context.put("model", "'" + data.getModel() + "'"); // 创建 跳转表格页面 viewAction,根据实际需求更改 makeDefaultViewAction(meta, data, "teacherListDialog", "教师表格", null, ActionContextTypeEnum.CONTEXT_FREE, ViewTypeEnum.TABLE, 99, Teacher.MODEL_MODEL, DEFAULT_VIEW_NAME,…

    2025年10月22日
    71200

Leave a Reply

Please Login to Comment