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低代码应用平台体验

(0)
yexiu的头像yexiu数式员工
上一篇 2025年8月14日 pm5:55
下一篇 2025年8月22日 am10:51

相关推荐

  • 数式Oinone培训前注意事项

    一、快速上手 (建议至少预习 6 小时) 在正式培训之前,建议需要完成以下任务,以便对培训内容有基本了解: 点击阅读:快速启动入门 该文档为学员提供了从入门到实现 demo 的全过程说明,涵盖了开发工具、框架搭建、常见问题解答等内容 开始培训前,请参与人员确保完成以下任务 阅读并理解文档中的每个步骤。 配置好前后端开发环境。 完成 demo 的基础框架搭建,验证是否能够成功运行。 二、预期成果 通过上述预习,大家完成以下事项:• 成功搭建本地开发环境,并能运行前后端的基本 demo。• 对前后端技术栈有初步了解,为正式培训中的深度学习打下基础,并且提出对应的疑问点 三、其他准备工作 1.技术工具检查:请确在本地已安装并配置好必要的开发工具和环境(如 IDE、Node.js、数据库等);2.参与者反馈:在预习过程中,学员如遇到困难或无法解决的问题(前后端疑问),请提前记录并提交,以便培训期间重点解答;3.版本是否是最新的版本,且建议研发人员版本一致,且类型是 mini; ps:部署包相关信息,联系数式相关人员获取

    未分类 2024年8月2日
    2.7K00
  • 自定义字段样式

    在日常开发中,我们经常会遇到需要根据业务规则动态展示字段样式的场景,比如表格、表单或详情中的某些字段需要改变文字颜色。本文将通过一个具体的案例,带大家实现这一功能。 以下以 自定义表格字段文字颜色 为例。 实现步骤 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日
    5.7K00
  • 外部系统接入SSO-OAuth2(6.3.x 之后版本支持)

    一、概述 统一身份认证系统提供了单点登录功能。本文档详述了统一身份认证系统单点登录接口,介绍了应用系统对接统一身份认证系统的过程和方法,用以帮助开发人员将应用系统接入统一身份认证系统。 本文档支持的协议:OAuth2 二、统一认证集成规范 2.1 SSO登录场景 序号 场景 预期结果 确认 1 登录跳转,在未登录的条件下,直接访问业务系统 跳转到单点登录界面 是 2 登录跳转,在已登录的条件下,直接访问业务系统 直接进入业务系统 是 3 正常登录,先登录认证,然后访问业务系统 直接进入业务系统 是 4 正常登出,在单点登录系统登出 访问业务系统要重新登录 是 5 正常登出,在业务系统登出 单点登录系统同步登出 是 2.2 认证流程 OAuth2 登录和认证流程 后端验证 token 后,创建本地会话(如 JSESSIONID 或自定义 Cookie); 后续应用请求靠本地会话维持登录状态,不再依赖原始 token; 本地会话有过期时间(如 30 分钟无操作过期); 三、认证服务接口 3.1 SSO服务端认证 浏览器登录 分类 说明 请求地址(开发环境) http://${host}:${port}/pamirs/sso/auth?client_id={client_id}&redirect_uri={redirect_uri}&state={state} 请求地址(测试环境) http://${host}:${port}/pamirs/sso/auth?client_id={client_id}&redirect_uri={redirect_uri}&state={state} 请求方式 GET 请求参数 redirect_uri:应用系统回调地址client_id:SSO 服务端颁发的应用 IDstate:可选但推荐,用于防止 CSRF 的随机字符串(UUID 随机码) 请求示例 http://${host}:${port}/pamirs/sso/auth?client_id=client123456&redirect_rui=http://app.example.com&state=abc123 响应说明 1. 已登录:重定向到 redirect 地址并携带授权码 code,如 http://app.example.com&state=abc123&code=xxx2. 未登录:重定向到服务器 SSO 登录地址 备注 SSO 登录成功后,会携带授权码并重定向到 redirect 地址 3.2 验证授权码 分类 说明 请求地址(开发环境) http://${host}:${port}/pamirs/sso/oauth2/authorize 请求地址(测试环境) http://${host}:${port}/pamirs/sso/oauth2/authorize 请求方式 POST 请求 Body {"grant_type":"authorization_code","client_id":"xxxx","client_secret":"xxxxx","code":"xxxx"} 请求示例 http://${host}:${port}/pamirs/sso/oauth2/authorize 响应说明 {"code":"0","msg":"成功","data":{"access_token":"xxxxx","expires_in":7200,"refresh_token":"xxxxxx","refresh_token_expiresIn":604800}} 备注 — 3.2 根据token获取用户信息 分类 说明 请求地址(开发环境) http://${host}:${port}/pamirs/sso/oauth2/getUserInfo 请求地址(测试环境) http://${host}:${port}/pamirs/sso/oauth2/getUserInfo 请求方式 POST 请求头 Authorization: Bearer xxxxxxxx 请求 Body {"client_id":"xxxx"} 请求示例 http://${host}:${port}/pamirs/sso/oauth2/getUserInfo 响应 {"code":"0","msg":"成功","data":{"name":"xxxxx","email":"xxxxx","login":"xxxxxx","id":"xxxxxxx"}} 备注 成功返回用户信息;失败返回错误码:1 根据实际情况其他协议的验证接口 3.3 单点登出接口 分类 说明 请求地址(开发环境) http://${host}:${port}/pamirs/sso/oauth2/logout 请求地址(测试环境) http://${host}:${port}/pamirs/sso/oauth2/logout 请求方式 POST 请求头 Authorization: Bearer xxxxxxxx 请求 Body {"client_id":"xxxx"} 请求示例 http://${host}:${port}/pamirs/sso/oauth2/logout 响应头 HTTP/1.1 200;Content-Type: application/html;charset=UTF-8 响应体 登出成功页面 备注 应用系统向 SSO 系统发起登出请求,SSO 收到后会通知所有其它系统登出该用户 四、服务注册 添加以下依赖 <!– sso相关 –> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-sso-api</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-sso-common</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-sso-server</artifactId> </dependency> 配置文件 pamirs sso: enabled: true server: loginUrl: http://127.0.0.1:8091/login authType:…

    2026年1月7日
    20200
  • 流程和任务状态说明文档

    一、工作流实例状态说明 INIT:新的流程创建时,执行工作流实例前的状态。 PROCESSING:发起的新的流程之后,结束之前的状态。 FINISHED:整个流程结束后的状态。 ERROR:流程异常时的状态。 RECALL: 撤销流程实例时的状态 CLOSE:关闭流程实例时(流程撤销)的状态。 一、工作流实例通过状态说明 FILLED:流程走到填写节点,填写人填写过后的状态。 PASS:审批同意操作后的状态。 REJECT:审批结果被拒绝(审批节点结束后)的状态。 ING:新的流程创建时,执行工作流实例前的状态。 ERROR:流程异常时的状态。 RECALL:撤销流程实例时的状态。 RECALL_PASS:无 RECALL_REJECT:无 RECALL_FILLED:无 FALLBACK:已退回时标识抄送/工作流实例为已退回时的状态。 FALLBACK_PASS:无 FALLBACK_REJECT:无 FALLBACK_FILLED:无 TRANSFER:无 CLOSE:关闭流程实例时((流程撤销))的状态。

    2025年6月24日
    39800

Leave a Reply

登录后才能评论