3.5.7.8 自定义菜单栏

在业务中,可能会遇到需要对菜单栏的交互或UI做全新设计的需求,这个时候可以自定义菜单栏组件支持。

首先继承平台的CustomMenuWidget 组件,将自己vue文件设置到component处

import { NavMenu, SPI, ViewWidget } from '@kunlun/dependencies';
import Component from './CustomMenu.vue';

@SPI.ClassFactory(
  ViewWidget.Token({
    // 这里的widget跟平台的组件一样,这样才能覆盖平台的组件
    widget: 'nav-menu'
  })
)
export class CustomMenuWidget extends NavMenu {

  public initialize(props) {
    super.initialize(props);
    this.setComponent(Component);
    return this;
  }
}

vue文件中继承平台的props,编写自定义页面代码

export const NavMenuProps = {
  /**
   * 当前模块
   */
  module: {
    type: Object as PropType<IModule | null>
  },
  /**
   * 树结构的菜单
   */
  menus: {
    type: Array as PropType<IResolvedMenu[]>,
    default: () => []
  },
  /**
   * 菜单类型,现在支持垂直、水平、和内嵌模式三种
   */
  mode: {
    type: String as PropType<'vertical' | 'horizontal' | 'inline'>,
    default: 'inline'
  },
  /**
   * 菜单栏是否折叠收起
   */
  collapsed: {
    type: Boolean,
    default: false
  },
  /**
   * 当前展开的 SubMenu 菜单项 key 数组
   */
  openKeys: {
    type: Array as PropType<string[]>,
    default: () => []
  },
  /**
   * 当前选中的菜单项 key 数组
   */
  selectKeys: {
    type: Array as PropType<string[]>,
    default: () => []
  },
  /**
   * 菜单搜索下拉选中菜单项
   */
  selectMenuBySearch: {
    type: Function as PropType<(menuName: String) => void>
  },
  /**
   * 选中菜单项
   */
  selectMenu: {
    type: Function as PropType<(menuName: String) => Promise<void>>
  },
  /**
   * SubMenu 展开/关闭的回调
   */
  openChange: {
    type: Function as PropType<(openKeys: string[]) => void>
  },
  /**
   * 菜单栏折叠的回调
   */
  onChangeCollapsed: {
    type: Function as PropType<(collapsed: boolean) => Promise<void>>
  }
};
<template>
  <div class="k-oinone-menu-wrapper custom-menu">
    <div class="menu-search" v-if="module && mode === 'inline' && !collapsed">
      <a-select
        ref="menuSelectSearch"
        dropdown-class-name="ui-designer-select-global"
        option-filter-prop="label"
        placeholder="搜索菜单"
        :show-search="true"
        @change="innerSearchSelect"
      >
        <a-select-option
          v-for="opt in module.allMenus.filter((_f) => _f.viewAction)"
          :key="opt.name"
          :value="opt.name"
          :label="opt.displayName"
        >
          {{ opt.displayName }}
        </a-select-option>
        <template #suffixIcon>
          <oio-icon icon="oinone-sousuo" size="14px" color="var(--oio-menu-default-icon-color)" />
        </template>
      </a-select>
    </div>
    <div class="menu-area oio-scrollbar">
      <div class="menu-content" :class="collapsed && 'collapsed'">
        <template v-for="item in menus" :key="item.key">
          <template v-if="!item.children || !item.children.length">
            <div :key="item.key" :title="item.title" class="root-menu" @click="selectMenu(item.key)">
              {{ item.title }}
            </div>
          </template>
          <template v-else>
            <div class="menu-group">
              <div class="root-menu" :title="item.title">{{ item.title }}</div>
              <div class="sub-menus">
                <template v-for="subItem in item.children" :key="subItem.key">
                  <div class="sub-menu" :title="subItem.title" @click="selectMenu(subItem.key)">
                    {{ subItem.title }}
                  </div>
                </template>
              </div>
            </div>
          </template>
        </template>
      </div>
    </div>

    <div class="menu-footer" :class="collapsed && 'collapsed'">
      <div class="menu-toggle-collapsed" @click="onChangeCollapsed(!collapsed)">
        <span class="collapsed-icon">
          <oio-icon
            :icon="collapsed ? 'oinone-menu-caidanzhankai' : 'oinone-menu-caidanshouqi'"
            size="16px"
            color="var(--oio-menu-default-icon-color)"
          />
        </span>
        <span v-show="!collapsed" class="collapsed-text">点击收起菜单</span>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted, nextTick } from 'vue';
import { OioIcon, NavMenuProps } from '@kunlun/dependencies';

export default defineComponent({
  props: {
    ...NavMenuProps
  },
  components: {
    OioIcon
  },
  setup(props) {
    const DEFAULT_MENU_ICON = 'oinone-menu-caidanmoren';

    onMounted(async () => {
      await nextTick();
      props.onChangeCollapsed?.(false);
    });

    const menuSelectSearch = ref();
    const innerSearchSelect = (menuName) => {
      props.selectMenuBySearch?.(menuName);
      menuSelectSearch.value?.blur?.();
    };
    return {
      DEFAULT_MENU_ICON,
      menuSelectSearch,
      innerSearchSelect
    };
  }
});
</script>
<style lang="scss">
.custom-menu {
  .root-menu,
  .sub-menu {
    text-indent: 12px;
    cursor: pointer;
    &:hover {
      background: rgba(var(--oio-primary-color-rgb), 0.1);
    }
  }
  .sub-menus {
    padding-left: 20px;
  }
}
</style>

文件目录结构如下图

image.png

最后再到运行路径中导入该组件

这里以启动工程的 main.ts 举例,如果运行时未看到该组件的效果,请检查是否正确导入到运行时的路径中

image.png

以上自定义菜单栏的页面效果如下(该组件仅供演示,所以未实现3级菜单,可自行用子组件实现)

image.png

Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9271.html

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

Like (0)
史, 昂's avatar史, 昂数式管理员
Previous 2024年5月23日 am9:07
Next 2024年5月23日 am9:09

相关推荐

  • 3.5.5 设计器的结合(改)

    在页面开发的时候,直接通过前端组件和视图xml进行开发虽然开放性是很大的、但我们经常会忘记视图的配置属性,同时用xml配置的页面因为缺少设计数据,导致无法直接在设计器中复制,自定义页面得从头设计。今天就带大家一起来学习如何结合无代码设计器来完成页面开发,并把设计后的页面元数据装载为标准产品的一部分。 1 安装Docker 如果没有Docker的话,请自行到官网下载:https://www.docker.com/get-started/ 2 下载Docker 镜像,并导入镜像 Step2.1 镜像下载 v.4.6.28.3-allinone-full 版本说明 前后端以及中间件一体 镜像地址 docker pull harbor.oinone.top/oinone/designer:4.6.28.3-allinone-full 下载结构包 oinone-op-ds-all-full.zip(17 KB) v.4.6.28.3-allinone-mini 版本说明 前后端一体支持外部中间件 镜像地址 docker pull harbor.oinone.top/oinone/designer:4.6.28.3-allinone-mini 下载结构包 oinone-op-ds-all-mini.zip(14 KB) v.4.7.9-allinone-full 版本说明 前后端以及中间件一体 镜像地址 docker pull harbor.oinone.top/oinone/designer:4.7.9-allinone-full 下载结构包 oinone-op-ds-all-full.zip(17 KB) v.4.7.9-allinone-mini 版本说明 前后端一体支持外部中间件 镜像地址 docker pull harbor.oinone.top/oinone/designer:4.7.9-allinone-mini 下载结构包 oinone-op-ds-all-mini.zip(14 KB) Step2.1.2 镜像下载用户与密码 需要商业版镜像需要加入Oinone商业版本伙伴专属群,向Oinone技术支持获取用户名与密码,镜像会定时更新并通知大家。 #注意:docker镜像拉取的账号密码请联系数式技术 docker login –username=用户名 harbor.oinone.top docker pull docker pull harbor.oinone.top/oinone/designer:4.6.28.3-allinone-full Step2.1.3 镜像和版本选择 目前有2个版本可供选择,包含中间件以及不包含中间件2个版本,下载结构包以后注意修改startup.sh和startup.cmd中对应镜像地址的版本号。 Step2.1.4 本地结构说明 下载结构包并解压 config是放application.yml的目录,可以在application.yml配置需要启动的自有模块同时修改对应其他中间件配置项 lib是放自有模块的jar包以及其对应的依赖包比如:pamirs-demo-api-1.0.0-SNAPSHOT.jar和pamirs-demo-core-1.0.0-SNAPSHOT.jar nginx:前端运行的nginx站点配置文件 mq:消息配置,再使用低无一体时需要指定mq的broker的IP run:容器运行中间件的脚本,可以对个别中间件是否启动进行设置,(注释掉运行脚本,容器启动时就不会启动该中间件) logs是运行时系统日志目录 Step2.2 修改startup.sh中的路径 Step2.2.1 linux环境修改参数 在文件中找到如下 configDir=/opt/docker/oinone-op-ds-all-full version=4.6.28.3 IP=192.168.0.121 修改configDir的路径(下载oinone-op-ds-xx.zip解压后的路径) 修改对应的镜像版本号 修改对应的IP为docker宿主机IP #!/bin/bash configDir=/opt/docker/oinone-op-ds-all-full version=4.6.28.3 IP=192.168.0.121 docker run -d –name designer-allinone \ -e DUBBO_IP_TO_REGISTRY=$IP \ -e DUBBO_PORT_TO_REGISTRY=20880 \ -p 8099:8091 \ -p 3307:3306 \ -p 2182:2181 \ -p 6378:6379 \ -p 19876:9876 \ -p 10991:10991 \ -p 15555:15555 \ -p 20880:20880 \ -p 88:80 \ -v $configDir/config/:/opt/pamirs/ext \ -v $configDir/nginx:/opt/pamirs/nginx/vhost \ -v $configDir/logs:/opt/pamirs/logs \ -v $configDir/mq/broker.conf:/opt/mq/conf/broker.conf \ -v $configDir/run/run.sh:/opt/pamirs/run/run.sh \ -v $configDir/lib:/opt/pamirs/outlib harbor.oinone.top/oinone/designer:$version-allinone-full Step2.2.3 window环境修改参数 在文件中找到如下 set configDir=/d/shushi/docker/oinone-op-ds-all-full set version=4.6.28.3 set IP=192.168.0.121 修改configDir的路径((下载oinone-op-ds-xx.zip解压后的路径) 修改对应的镜像版本号 修改对应的IP为docker宿主机IP @echo off set configDir=/d/shushi/docker/oinone-op-ds-all-full set version=4.6.28.3 set IP=192.168.0.121 docker run -d –name designer-allinone ^ -e DUBBO_IP_TO_REGISTRY=%IP% ^ -e DUBBO_PORT_TO_REGISTRY=20880 ^ -p 8099:8091…

    2024年5月23日
    1.6K00
  • 4.1.11 函数之异步执行

    异步任务是非常常见的一种开发模式,它在分布式的开发模式中有很多应用场景如: 高并发场景中,我们一般采用把长流程切短,用异步方式去掉可以异步的非关键功能,缩小主流程响应时间,提升用户体验 异构系统的集成调用,通过异步任务完成解耦与自动重试 分布式系统最终一致性的可选方案 今天我们了解oinone是如何结合Spring+TbSchedule来完成异步任务 一、TbSchedule介绍 它是一个支持分布式的调度框架,让批量任务或者不断变化的任务能够被动态的分配到多个主机的JVM中,在不同的线程组中并行执行,所有的任务能够被不重复,不遗漏的快速处理。基于ZooKeeper的纯Java实现,由Alibaba开源。在互联网和电商领域TBSchedule的使用非常广泛,目前被应用于阿里巴巴、淘宝、支付宝、京东、聚美、汽车之家、国美等很多互联网企业的流程调度系统。也是笔者早期在阿里参与设计的一款产品。 oinone的异步任务执行原理(如下图4-1-11-1所示),先做一个大致了解: 图4-1-11-1 Oinone的异步任务执行原理图 基础管理工具 下载tbSchedule的控制台jar包去除文件后缀.txt(详见本书籍【附件一】)pamirs-middleware-schedule-console-3.0.1.jar.txt(31.2 MB) 启动控制台 java -jar pamirs-middleware-schedule-console-3.0.1.jar 图4-1-11-2 控制台启动方式 访问地址 http://127.0.0.1:10014/schedule/index.jsp?manager=true 图4-1-11-3 访问地址 配置zk连接参数 图4-1-11-4 配置zk连接参数 oinone默认实现任务类型 图4-1-11-5 Oinone默认实现任务类型 baseScheduleNoTransactionTask baseScheduleTask remoteScheduleTask — 适用于pamirs-middleware-schedule独立部署场景 serialBaseScheduleNoTransactionTask serialBaseScheduleTask serialRemoteScheduleTask — 适用于pamirs-middleware-schedule独立部署场景 cycleScheduleNoTransactionTask delayMsgTransferScheduleTask deleteTransferScheduleTask 注: a. 默认情况下:所有任务的任务项都只配置了一个任务项0,只有一台机器能分配任务。 1. 如果要修改配置可以在启动项目中放置schedule.json,来修改配置 2. 人工进入控制修改任务对应任务项的配置 b. 如果想为某一个核心任务配置的独立调度器,不受其他任务执行影响。那么见独立调度的异步任务 任务表相关说明 图4-1-11-6 任务表相关说明 二、构建第一个异步任务(举例) Step1 新建PetShopService和PetShopServiceImpl 1 新建PetShopService定义updatePetShops方法 package pro.shushi.pamirs.demo.api.service; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import java.util.List; @Fun(PetShopService.FUN_NAMESPACE) public interface PetShopService { String FUN_NAMESPACE = "demo.PetShop.PetShopService"; @Function void updatePetShops(List<PetShop> petShops); } 图4-1-11-7 新建PetShopService定义updatePetShops方法 PetShopServiceImpl实现PetShopService接口并在updatePetShops增加@XAsync注解 displayName = "异步批量更新宠物商店",定义异步任务展示名称 limitRetryNumber = 3,定义任务失败重试次数,,默认:-1不断重试 nextRetryTimeValue = 60,定义任务失败重试的时间数,默认:3 nextRetryTimeUnit,定义任务失败重试的时间单位,默认:TimeUnitEnum.SECOND delayTime,定义任务延迟执行的时间数,默认:0 delayTimeUnit,定义任务延迟执行的时间单位,默认:TimeUnitEnum.SECOND package pro.shushi.pamirs.demo.core.service; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.demo.api.service.PetShopService; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.trigger.annotation.XAsync; import java.util.List; @Fun(PetShopService.FUN_NAMESPACE) @Component public class PetShopServiceImpl implements PetShopService { @Override @Function @XAsync(displayName = "异步批量更新宠物商店",limitRetryNumber = 3,nextRetryTimeValue = 60) public void updatePetShops(List<PetShop> petShops) { new PetShop().updateBatch(petShops); } } 图4-1-11-8 实现PetShopService接口并在updatePetShops增加@XAsync注解 Step2 修改PetShopBatchUpdateAction的conform方法 引入PetShopService 修改conform方法 利用ArgUtils进行参数转化,ArgUtils会经常用到。 调用petShopService.updatePetShops方法 package pro.shushi.pamirs.demo.core.action; …… 引依赖类 @Model.model(PetShopBatchUpdate.MODEL_MODEL) @Component public class PetShopBatchUpdateAction { @Autowired private PetShopService petShopService; ……其他代码 @Action(displayName = "确定",bindingType = ViewTypeEnum.FORM,contextType = ActionContextTypeEnum.SINGLE) public PetShopBatchUpdate conform(PetShopBatchUpdate data){ if(data.getPetShopList() == null || data.getPetShopList().size()==0){ throw…

    2024年5月23日
    1.5K00
  • 3.5.7.3 自定义布局

    布局是什么 在系统中,布局决定了母版内的页面元素,一个页面可以由多个组件进行组装,布局可以根据视图类型来替换。 默认布局范围: 图3-5-7-36 默认布局范围 作用场景 系统内置了多个布局组件,这些组件适用于全局、某个应用或某个页面,提供了灵活的布局定制选项。这些组件根据不同类型的视图进行了默认的组装,这也是选择了视图类型后,页面能够呈现的原因。当然,这些默认的组装是可以被覆盖、新增和添加新组件的。 使用registerLayout进行自定义布局 开发者在使用这些布局组件时,应该遵循公司的规范进行统一的调整。自定义布局组件的使用可通过 registerLayout 实现。registerLayout 的第一个参数是代表布局的 XML,第二个参数是不同的选项维度,默认包含以下维度: viewType: 视图类型 module: 视图模型所在模块 moduleName: 视图模型所在模块名称 model: 视图模型编码 modelName: 视图模型名称 viewName: 视图名称 actionName: 动作名称 inline: 是否内嵌视图(子视图特有) ttype: 模型字段类型(子视图特有) relatedTtype: 关联模型字段类型(子视图特有) field: 字段(子视图特有) 需要注意的是,动作可以是A模块下的a模型,这个动作可以打开B模块下的b模型的视图,module、moduleName、model、modelName应该填b模型对应的值,只不过大部分场景我们都是本模型的动作打开本模型的视图,所以这些场景拿动作所在模型填这些值也可以这些纬度也可以通过查看TS的定义查看 全局 在系统中,我们可以通过指定视图类型来决定某一类视图的全局布局。以表格为例,当第二个入参为 { viewType: ViewType.Table } 时,代表了替换了系统内所有表格的布局样式。 示例工程目录 以下是需关注的工程目录示例,main.ts更新导入./layout,layout/index.ts更新导出./tableLayout: 图3-5-7-37 全局纬度注册布局工程目录示例 示例代码 import {registerLayout, ViewType} from '@kunlun/dependencies' /** * 把系统内所有表格类型视图的全局动作放入搜索区域 * * 移动actionBar布局至外层 * <element widget="actionBar" slot="actionBar" slotSupport="action"> * <xslot name="actions" slotSupport="action" /> * </element> * */ const registerGlobalTableLayout = () => { return registerLayout(`<view type="TABLE"> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <pack widget="group"> <view type="SEARCH"> <element widget="search" slot="search" slotSupport="field" /> </view> </pack> <pack widget="group" slot="tableGroup"> <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>`, { viewType: ViewType.Table }) } registerGlobalTableLayout() 图3-5-7-38 全局纬度注册布局代码示例 效果 图3-5-7-39 全局纬度注册布局效果示例 应用 在系统中,我们可以通过指定视图类型和模块名称来替换某一类视图在特定模块下的全局布局。以表格为例,当第二个入参为 { viewType: ViewType.Table, moduleName: ‘resource’ } 时,代表了替换了资源应用下所有表格的布局样式,而其他应用仍使用默认布局 import {registerLayout, ViewType} from '@kunlun/dependencies' const registerModuleTableLayout = () => { return registerLayout(`<view type="TABLE"> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <pack widget="group"> <view type="SEARCH"> <element widget="search" slot="search" slotSupport="field" /> </view> </pack> <pack…

    2024年5月23日
    1.6K00
  • 3.5.6.1 字段的配置

    字段组件类型 ttype可以配置哪些widget?本文这里把oinone平台默认支持的所有widget都进行了罗列,方便大家查阅。 字段组件匹配规则 字段组件没有严格的按组件名(widget)、字段类型(ttype)、视图组件类型(viewType)限定,而是一个匹配规则 按widget 最优先匹配 按最大匹配原则 ttype、viewType。每个属性权重一分 按后注册优先原则 通用属性 属性 属性描述 属性name 默认值 类型 标题 字段的标题名称 label – string 占位提示 一个字段的描述信息,常用于说明当前字典的范围、注意事项等 placeholder – string 描述说明 组件描述信息 hint – string 数据校验 与表单其他数据联动校验 validator – 表达式 数据校验不通过提示 数据校验不通过提示 validatorMessage 校验失败 string 只读 字段的状态,可见,不可编辑 readonly false boolean或者表达式 隐藏 字段的状态,不,不可编辑 invisible false boolean或者表达式 必填 字段是否必填 required false boolean或者表达式 禁用 字段是否禁用 disabled false boolean或者表达式 宽度 属性在页面中的宽度 colSpan 01/02 标题排列方式 标题排列方式: 水平 , 横向 layout vertical vertical | horizontal 默认值 默认值,多值逗号分割 defaultValue – 根据不同ttype有不同的默认值类型 表3-5-6-1 字段通用属性 字段组件大全 widget为"-"表明不需要指定,是该ttype默认widget 组件名称 widget 对应ttype 属性 属性描述 属性name 默认值 类型 单行文本 – STRING 通用属性 文本类型 密码:password; 文本: text type text string 最小长度 输入框填写数据时最少输入的长度值 minLength – number 最大长度 输入框填写数据时最多输入的长度值 maxLength – number 输入格式 单行文本组件特有的属性,通过规则校验内容,提供一些常用的,也支持自定义校验正则 pattern – 正则表达式 输入格式不通过 输入格式不通过提示语 tips 校验失败 string 显示计数器 设置输入框是否显示字数计数器 showCount FALSE boolean 显示清除按钮 设置输入框是否有一键清除的按钮及功能 allowClear TRUE TRUE 支持前缀 开启前缀 showPrefix FALSE boolean 支持后缀 开启后缀 showSuffix FALSE boolean 前缀类型 ICON: 图标; TEXT:文本 prefixType – string 后缀类型 ICON: 图标; TEXT:文本 suffixType – string 前缀内容 文本内容或者图标引用名 prefix – string 后缀内容 文本内容或者图标引用名 suffix – string 前缀存储 前缀存储, 仅前缀类型为文本可用 prefixStore – boolean 后缀存储 后缀存储, 仅后缀类型为文本可用 suffixStore – boolean 多行文本 -…

    2024年5月23日
    1.6K00
  • 工作台

    有工作台权限的用户,默认登录页为工作台,也可以通过APP Finder进入工作台。 1. 快捷处理 右上角消息中会气泡展示未处理或未读的操作,点击展开后可以点过去进行快捷处理。 2. 查看、处理流程 2.1 流程查看 流程管理页面共同点: 1包含选项分类筛选 2包含标签筛选 3包含应用下拉选筛选 4包含根据流程名称搜素 流程管理页面名词解释: 待办:当前登录用户未处理的流程节点 我发起的:当前登录用户人为触发的流程(模型触发) 抄送:抄送给当前登录用户的节点(审批/填写) 我已办结:由当前登录用户完成人工/自动同意、人工拒绝或人工填写的节点 无需办理:当前登录用户转交的任务/被退回、被撤销、被或签、被其他分支任务拒绝的还未办理的任务 站内信:当前登录用户收到的站内信 2.2 流程处理 每条流程数据下方有动作,点击进入流程处理页面,大致分为详情页和操作页。 待办中点击“审批/填写”会进入流程操作页。审批操作页可能包含“同意、拒绝、退回、加签、转交、返回”,填写操作页可能包含“提交、暂存”,审批操作页包含哪些动作由流程设计决定。 我发起的、抄送、我已办结、无需处理点击“查看”会进入流程详情页。 3. 应用快捷入口 应用中心中星标的收藏应用会展示在此处,点击可快捷进入应用。 应用中心中已安装的应用点击星标即可收藏。

    2024年6月20日
    2.1K00

Leave a Reply

Please Login to Comment