0.2.9 • Published 8 months ago

@axm-pack/manage-render v0.2.9

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

manage-render

npm GitHub GitHub GitHub

English | 简体中文

基于 ElementPlus 的 CRUD 构造器。

Demo

🔗 点击查看

npm.io

使用 JSX 的前提是需要安装 @vitejs/plugin-vue-jsx 插件。

安装

pnpm i @axm-pack/manage-render

在 main.ts 中引入

...

import { Context } from '@axm-pack/manage-render'
import '@axm-pack/manage-render/dist/style.css'

const app = createApp(App)
app.use(Context)

...

使用

Dialog

一个十分方便的 Dialog 组件

  • 函数式调用
  • 顺序关闭 & Esc 关闭
  • 自定义内容
  • 支持 h() & JSX
import { defineComponent } from 'vue'
import { Dialog } from '@axm-pack/manage-render'

const DialogContent = defineComponent({
  render() {
    return  (
      <div>
        <p>Dialog Content.</p>
      </div>
    )
  }
})

// JSX
const show = () => {
  const instance = Dialog.init({
    title: '🎄 Title'
    width: 500,
    content: () => <DialogContent />,
  })
}

// h()
const show = () => {
  const instance = Dialog.init({
    title: '🎄 Title'
    width: 500,
    content: (h) => h(DialogContent),
  })
}

对于 Vue 的单文件组件,可以这样写

import { Dialog } from '@axm-pack/manage-render'
import DialogContent from './DialogContent.vue'

// JSX
const show = () => {
  const instance = Dialog.init({
    title: '🎄 Title'
    width: 500,
    content: () => <DialogContent />,
  })
}

// h()
const show = () => {
  const instance = Dialog.init({
    title: '🎄 Title'
    width: 500,
    content: (h) => h(DialogContent),
  })
}

这里的 instance 是一个 Dialog 实例,可以通过 instance.close() 来关闭 Dialog。

QueryForm

如其名,用于构建查询表单

  • 支持自定义渲染, JSX & h()
  • 包含内置实现,如 InputSelectDatePicker
  • TS 类型支持
import { QueryForm } from '@axm-pack/manage-render'
import { ref } from 'vue'

type QueryFormType = {
  name: string
  age: number
}

const queryForm = ref<QueryFormType>({})
const QueryFormNode = QueryForm<QueryFormType>({
  modelValue: queryForm,
  formItems: [
    {
      label: 'Name',
      key: 'name',
    },
    {
      label: 'Age',
      key: 'age',
      type: () => <Component />,
    },
  ],
  actions: [
     {
      text: '查询',
      type: 'primary',
      handler: () => {
        // TODO
      },
    },
  ]
})
<template>
  <div>
    <QueryFormNode />
  </div>
</template>

type 默认为文本框,支持自定义,已实现的类型:

  • useTextField 文本框
  • useSelectorField 下拉框
  • useDatePickerField 日期选择器
  • useDateRangePickerField 日期范围选择器
  • useCascaderField 级联选择器

均为 ElementPlus 的组件,具体的 Props, Events 可以参考 ElementPlus 的文档。

🔗 Source Code

类型参照

/**
 * Defines the properties of a form.
 */
export type FormDefine<T> = {
  /** The initial value of the form. */
  modelValue?: any
  /** The validation rules for the form. */
  rules?: any
  /** Whether the form is disabled or not. */
  disabled?: boolean
  /** The width of the form label. */
  labelWidth?: number | string
  /** The form items to be displayed. */
  formItems?: FormItem<T>[]
  /** The class name of the form. */
  className?: string
  /** The actions to be displayed in the form. */
  actions?: Actions[]
}

/**
 * Defines the properties of a form item.
 */
export type FormItem<T, K = keyof T> = {
  /** The type of the form item. */
  type?: VNode | (() => VNode)
  /** The key of the form item. */
  key?: K
  /** The label of the form item. */
  label?: string
}

/**
 * Defines the properties of an action.
 */
export type Actions = {
  /** The type of the action. */
  type: 'default' | 'primary' | 'success' | 'warning' | 'info' | 'danger'
  /** The text to be displayed for the action. */
  text: string
  /** The icon of the form item. */
  icon?: string
  /** The function to be called when the action is triggered. */
  handler: () => void
}

DataTable

用于构建数据表格,基于 ElementPlus 的 Table 组件

  • 支持自定义渲染, JSX & h()
  • TS 类型支持
import { DataTable } from '@axm-pack/manage-render'
import { ref } from 'vue'

type TableDataType = {
  name: string
  age: number
}

type PageDataType = {
  pageNum: number
  pageSize: number
}

const queryForm = ref<PageDataType>({
  pageNum: 1,
  pageSize: 10,
})
const tableData = ref<TableDataType[]>([])
const loading = ref<boolean>(false)
const total = ref<number>(0)

const DataTableNode = DataTable<TableDataType, PageDataType>({
  modelValue: tableData,
  loading,
  total,
  pagination: {
    pageSize: () => queryForm.value.pageSize,
    pageNum: () => queryForm.value.pageNum,
  },
  dataFetch: (pageNum, pageSize) => {
    // TODO
  },
  columns: [
    {
      label: 'Name',
      prop: 'name',
    },
    {
      label: 'Age',
      prop: 'age',
      render: item => {
        return <span>{item.age}</span>
      },
    },
  ],
  action: {
    width: 200,
    items: [
      {
        text: 'View',
        type: 'primary',
        onClick: item => {
          // TODO
        },
      },
    ],
  },
})
<template>
  <div>
    <DataTableNode />
  </div>
</template>

✅ 关于勾选行

import { useSelection } from '@/core/DataTable/fields'
import { DataTable } from '@axm-pack/manage-render'

const selection = ref<string[]>([])
const DataTableNode = DataTable<TableDataType, PageDataType>({
  ...
  columns: [
    {
      label: '',
      width: 50,
      ...useSelection({
        selection,
        tableData,
        field: 'id',
        single: true,
      }),
    },
  ],
  ...
})

selection 的值为选中行的 id 数组

selection 类型参照

type IProps<T> = {
  selection: Ref<string[]>
  tableData: Ref<T[]>
  field: Extract<keyof T, string>
  single?: boolean // 是否单选
}

类型参照

/**
 * Defines the structure of a table in the DataTable component.
 * @template T The type of data displayed in the table.
 */
export type TableDefine<T> = {
  /** Whether the table is currently loading data. */
  loading?: Ref<boolean>
  /** The total number of items in the data set. */
  total?: Ref<number>
  /** The data items to display in the table. */
  items?: Ref<T[]>
  /** The height of the table. */
  height?: string | number
  /** The columns to display in the table. */
  columns?: ColumnItem<T>[]
  /** A function to handle the click event for a row in the table. */
  rowClick?: (row: T) => void
  /** The action to display for each row in the table. */
  action?: {
    /** The label to display for the action. */
    label?: string
    /** The width of the action. */
    width?: string | number
    /** The actions to display for the action. */
    items?: {
      /** The text to display for the action. */
      text?: string | ((item: T) => string)
      /** The type of button to display for the action. */
      type?: 'default' | 'primary' | 'success' | 'warning' | 'info' | 'danger'
      /** The icon to display for the action. */
      icon?: string
      /** Whether the action is disabled. */
      show?: (item: T) => boolean
      /** A function to handle the click event for the action. */
      onClick?: (item: T) => void
      /** A function to render custom content for the action. */
      render?: (item: T, h: any) => VNode
    }[]
  }
  /** The pagination settings for the table. */
  pagination?: {
    /** Whether to display the pagination controls. */
    show?: boolean
    /** The current page number. */
    pageNum?: () => number
    /** The number of items to display per page. */
    pageSize?: () => number
    /** The available page sizes to choose from. */
    pageSizes?: number[]
  }
  /** A function to fetch data for the table. */
  dataFetch?: (pageNum: number, pageSize: number) => void
}

/**
 * Represents a column item in a data table.
 * @template T The type of the data item.
 * @template K The type of the key of the data item property.
 */
export type ColumnItem<T, K = keyof T> = {
  /** The label to display for the column. */
  label?: string
  /** The key of the data item property to display in the column. */
  key?: K
  /** The width of the column. */
  width?: string | number
  /** A function to render custom content in the column. */
  render?: (item: T, h: any) => VNode
  /** A function to render custom content in the column header. */
  header?: (h: any) => VNode
}

DataForm

用于构建数据表单,基于 ElementPlus 的 Form 组件

  • 支持自定义渲染, JSX & h()
  • TS 类型支持

本质上和 QueryForm 差不多,和 QueryForm 共用已实现的组件,但是增加了一些参数,更加适用于构建数据表单

import { DataForm, useTextField } from '@axm-pack/manage-render'
import { ref } from 'vue'

type FormDataType = {
  name: string
  age: number
}

const formData = ref<FormDataType>({})
const DataFormNode = DataForm<FormDataType>({
  modelValue: formData,
  labelWidth: 100,
  formItems: [
    {
      label: 'Name',
      key: 'name',
      type: useTextField(),
    },
    {
      label: 'Age',
      key: 'age',
      type: () => <Component />,
    },
  ],
  actions: [
     {
      text: '提交',
      type: 'primary',
      handler: () => {
        // TODO
      },
    },
  ]
})
<template>
  <div>
    <DataFormNode />
  </div>
</template>

类型参照

/**
 * Represents the form definition for creating a form component.
 * @template T - The type of the form model.
 */
export type FormDefine<T> = {
  class?: string
  modelValue?: any
  readonly?: boolean
  disabled?: boolean
  labelWidth?: string | number
  rowGap?: number
  formItems?: FormItem<T>[]
  actions?: ActionItem<T>[]
}

/**
 * Represents a form item in the form definition.
 * @template T - The type of the form model.
 * @template K - The key of the form item.
 */
export type FormItem<T, K = keyof T> = {
  label?: string
  key?: K
  type?: VNode | (() => VNode)
  readonly?: boolean
  rules?: any
  col?: number
  rowEnd?: boolean
  remark?: string
  show?: (item: T) => boolean
}

/**
 * Represents an action item in the form definition.
 * @template T - The type of the form model.
 */
type ActionItem<T> = {
  type: 'default' | 'primary' | 'success' | 'warning' | 'info' | 'danger'
  text: string
  icon?: string
  verify?: boolean
  show?: (item: T) => boolean
  handler: () => void
}

配合 Dialog 使用

import { defineComponent, ref, PropType } from 'vue'
import { Dialog, DataForm } from '@axm-pack/manage-render'

type FormDataType = {
  name: string
  age: number
}

const DialogContent = defineComponent({
  props: {
    item: {
      type: Object as PropType<TableDataType>,
      default: () => ({}),
      required: false,
    },
    close: {
      type: Function as PropType<() => void>,
      required: false,
    }
  }
  setup(props) {
    const formData = ref<FormDataType>(props.item)
    const DataFormNode = DataForm<FormDataType>({
      modelValue: formData,
      labelWidth: 100,
      formItems: [
        {
          label: 'Name',
          key: 'name',
          type: useTextField(),
        },
        {
          label: 'Age',
          key: 'age',
          type: useTextField(),
        },
      ],
      actions: [
        {
          text: '提交',
          type: 'primary',
          handler: () => {
            // TODO
          },
        },
      ]
    })

    return {
      DataFormNode,
    }
  },
  render() {
    return  (
      <div>
        {this.DataFormNode}
      </div>
    )
  }
})

const show = ({item} : {item: FormDataType}) => {
  const instance = Dialog.init({
    title: '🎄 Title'
    width: 500,
    content: () => <DialogContent item={item} close={instance?.close} />,
  })
}

export { show }

这种组件我一般会命名为 EditDialog, 使用的话则直接调用 EditDialog.show({ item }) 即可。 eg.

...
<button @click="EditDialog.show({ item })">Edit</button>
...

<script setup>
  import EditDialog from './EditDialog.tsx'
</script>
0.2.9

8 months ago

0.2.8

8 months ago

0.2.7

9 months ago

0.1.0

11 months ago

0.2.1

10 months ago

0.1.2

10 months ago

0.2.0

10 months ago

0.1.1

10 months ago

0.1.8

10 months ago

0.0.9

11 months ago

0.2.6

9 months ago

0.1.7

10 months ago

0.0.8

11 months ago

0.1.9

10 months ago

0.2.3

10 months ago

0.1.4

10 months ago

0.2.2

10 months ago

0.1.3

10 months ago

0.2.5

9 months ago

0.1.6

10 months ago

0.2.4

9 months ago

0.0.7

1 year ago

0.0.5

1 year ago

0.0.4

1 year ago

0.0.6

1 year ago

0.0.3

1 year ago

0.0.2

1 year ago

0.0.1

1 year ago