Oinone实战:深度剖析Oinone低代码平台的统计功能实现与竞品优势

136 阅读5分钟

业务场景:让数据价值触手可及

在现代企业数字化转型进程中,数据不仅是资产,更是决策的核心驱动力。以“经费申请”系统为例,用户不仅需要查看列表数据,更希望在操作界面中实时掌握关键业务指标——如“年度申请总额”、“当前选中记录的金额汇总”等。 传统开发模式下,这类统计功能需前后端协同开发,涉及接口设计、数据聚合、UI 布局调整等多个环节,开发周期长、维护成本高。而在 Oinone 低代码平台 中,我们通过高度可扩展的组件化架构与灵活的布局引擎,仅需数个文件即可实现完整的统计功能集成,真正做到了“零侵入、高复用、快交付”。


实现步骤:优雅实现表格统计功能

Oinone 平台凭借其模块化设计哲学与声明式布局能力,允许开发者以极简方式扩展系统功能。以下以“经费申请”模块为例,展示如何在表格工具栏中动态集成统计数据组件。

1. 创建模块目录结构

layout 目录下新建 TrainingFee 模块文件夹,用于组织相关组件。

2. 构建四大核心文件

  • TrainingFeeStatistics.vue:UI 层组件,负责呈现统计信息
  • TrainingFeeStatisticsWidget.ts:逻辑层组件,封装数据获取与状态管理
  • index.ts:模块导出入口
  • Register.ts:布局注册器,实现组件动态注入

TrainingFeeStatistics.vue —— 精致 UI,极致体验

<template>
  <div class="action-bar-container">
    <slot name="tableAction"></slot>
    <div class="statistic">
      申请总额:{{ yearTotalAmount }}元
      <span style="margin-left: 5px" v-if="activeRecords.length !== 0">
        已选择申请总额:{{ totalAmount }}元
      </span>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { computed, defineProps } from 'vue';

const props = defineProps({
  activeRecords: {
    type: Object,
    default: () => []
  },
  yearTotalAmount: {
    type: Number,
    default: 0.0
  }
});

const totalAmount = computed(() => {
  let sum = 0.0;
  for (let i = 0; i < props.activeRecords.length; i++) {
    sum += parseFloat(props.activeRecords[i].approvalAmount);
  }
  return sum.toFixed(2);
});
</script>

<style scoped>
.action-bar-container {
  display: flex;
}
.statistic {
  display: inline;
  margin-left: 10px;
  vertical-align: middle;
  line-height: var(--oio-height);
}
:deep(.action-bar) {
  width: auto;
}
</style>

亮点说明
通过 slot 机制实现与原生操作栏无缝融合,利用 computed 实现响应式数据计算,结合 CSS 变量确保 UI 高度适配平台主题,体现 Oinone 对用户体验一致性的极致追求。


TrainingFeeStatisticsWidget.ts —— 智能逻辑,高效聚合

import { BaseElementWidget, BaseElementWidgetProps, SPI, Widget, http } from '@kunlun/dependencies';
import TrainingFeeStatistics from './TrainingFeeStatistics.vue';

@SPI.ClassFactory(BaseElementWidget.Token({ widget: 'TrainingFeeStatisticsWidget' }))
export class TrainingFeeStatisticsWidget extends BaseElementWidget {
  public initialize(props: BaseElementWidgetProps) {
    if (!props.slotNames) {
      props.slotNames = ['tableAction'];
    }
    super.initialize(props);
    this.setComponent(TrainingFeeStatistics);
    return this;
  }

  @Widget.Reactive()
  private yearTotalAmount: number = 0.0;

  public async $$mounted() {
    super.$$mounted();
    await this.statisticsCurrent();
  }

  private async statisticsCurrent() {
    const result = await http.query(
      'Expense',
      `{
        trainingFeeQuery {
          statisticTotalAmount(data: {}) {
            approvalAmount                   
          }
        }
      }`
    );
    const res = result.data.trainingFeeQuery.statisticYearTotalAmount as any;
    this.yearTotalAmount = res.approvalAmount;
  }
}

架构优势
采用 SPI(Service Provider Interface)机制实现组件热插拔,通过 @Widget.Reactive() 实现响应式状态管理,结合 GraphQL 高效查询,充分体现了 Oinone 前后端一体化、响应式编程、微内核架构的设计理念。


index.ts —— 模块化入口,清晰易维护

import './Register';
export * from './TrainingFeeStatisticsWidget';

简洁的模块导出机制,支持按需加载与依赖注入,便于团队协作与版本管理。


Register.ts —— 声明式布局,动态注入

import { ViewType, LayoutManager } from '@kunlun/dependencies';

LayoutManager.register(
  {
    viewType: ViewType.Table,
    moduleName: 'ZsIcBiz',
    model: 'app.expense.TrainingFee'
  },
  `<view type="TABLE">
    <pack widget="group">
        <view type="SEARCH">
            <element widget="search" slot="search" slotSupport="field" />
        </view>
    </pack>
    <pack widget="group" slot="tableGroup">
        <element widget="TrainingFeeStatisticsWidget">
          <template slot="tableAction">
            <element widget="actionBar" slot="actionBar" slotSupport="action">
              <xslot name="actions" slotSupport="action" />
            </element>
          </template>
        </element>
        <element widget="table" slot="table" slotSupport="field">
            <element widget="expandColumn" slot="expandRow" />
            <xslot name="fields" slotSupport="field" />
            <element widget="rowActions" slot="rowActions" slotSupport="action" />
        </element>
    </pack>
  </view>`
);

革命性优势
通过 LayoutManager.register 实现运行时布局动态注册,无需修改原始代码即可扩展功能,真正实现“配置即代码,扩展无侵入”。


对比主流平台:Oinone 的技术领先性

为了更清晰地展现 Oinone 的优势,我们将其与当前主流低代码平台在实现相同“表格统计”功能时的表现进行横向对比:

功能能力Oinone若依(RuoYi)JeecgBoot宜搭(YiDa)
是否支持自定义组件注入✅ 完全支持,通过 SPI 机制动态注册❌ 仅支持前端代码扩展,需手动修改页面⚠️ 支持部分自定义组件,但需遵循固定模板✅ 支持,但局限于可视化拖拽,无法深度编程
是否支持运行时布局修改✅ 支持 LayoutManager 动态注册,无需重启❌ 需修改前端 Vue 文件,重新构建部署⚠️ 需通过代码生成器重新生成代码✅ 支持,但仅限于基础控件,不支持逻辑层扩展
是否支持响应式状态管理✅ 原生支持 @Widget.Reactive() 响应式编程❌ 依赖 Vue 原生响应式,需手动维护⚠️ 支持 Vue/React 状态管理,但需开发者自行实现⚠️ 支持简单数据绑定,复杂逻辑需 JS 脚本
是否支持 GraphQL 数据查询✅ 原生集成,高效精准获取数据❌ 仅支持 REST API,需多次请求⚠️ 支持 REST,GraphQL 需额外集成✅ 支持,但语法受限,调试困难
扩展开发效率⭐⭐⭐⭐⭐(4 文件,<100 行代码)⭐⭐(需修改源码,易出错)⭐⭐⭐(需生成代码,灵活性差)⭐⭐⭐⭐(可视化操作快,但逻辑受限)
维护成本极低(无侵入,独立模块)高(代码耦合,升级易冲突)中(依赖代码生成器)中(依赖平台规则)

结论
Oinone 凭借其微内核 + 插件化 + 声明式布局的先进架构,在实现复杂业务扩展时展现出无与伦比的灵活性与可维护性,远超传统低代码平台。


为什么选择 Oinone?

  1. 极致可扩展性:基于 SPI 与组件化架构,支持任意层级的功能扩展。
  2. 零侵入式开发:无需修改原始代码,通过注册机制动态注入,保障系统稳定性。
  3. 高可定制性:从 UI 到逻辑层全面开放,满足企业级复杂业务需求。
  4. 开发效率倍增:标准化开发模式,新人也能快速上手,交付周期缩短 60%+。
  5. 面向未来架构:支持 GraphQL、响应式编程、微前端等现代技术栈。

结语

在数字化浪潮中,低代码平台不再是“表单工具”,而是企业业务创新的加速器。Oinone 以工程化思维重构低代码开发范式,让开发者既能享受“低代码”的高效,又能保有“高代码”的自由与掌控力。

Oinone —— 不止于低代码,更懂企业级扩展。

添加微信(微信号:coder1908),立即体验 Oinone,开启您的智能开发之旅!

ee091dbda973a4a014f50c314ece8b95_151150-20250814232537100-1986876602.jpg


Gitee开源地址

后端:gitee.com/gq2010/oino…

前端:gitee.com/gq2010/oino…