0.2.9 • Published 10 months ago

@axm-pack/manage-render v0.2.9

Weekly downloads
-
License
MIT
Repository
github
Last release
10 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

10 months ago

0.2.8

10 months ago

0.2.7

11 months ago

0.1.0

1 year ago

0.2.1

1 year ago

0.1.2

1 year ago

0.2.0

1 year ago

0.1.1

1 year ago

0.1.8

1 year ago

0.0.9

1 year ago

0.2.6

11 months ago

0.1.7

1 year ago

0.0.8

1 year ago

0.1.9

1 year ago

0.2.3

1 year ago

0.1.4

1 year ago

0.2.2

1 year ago

0.1.3

1 year ago

0.2.5

11 months ago

0.1.6

1 year ago

0.2.4

11 months ago

0.0.7

1 year ago

0.0.5

2 years ago

0.0.4

2 years ago

0.0.6

2 years ago

0.0.3

2 years ago

0.0.2

2 years ago

0.0.1

2 years ago