@xinlian-frontend/lui
v0.0.1-beta.17
Published
组件库
Readme
L-UI 组件库文档
基于 Ant Design Vue 封装的业务组件库,提供表单、表格、抽屉、弹窗等常用业务组件。
组件总览
| 组件 | 名称 | 说明 | | ------------------------------------- | ------------ | ---------------------------------------------- | | LButton | 按钮 | 基于 AButton 的简单封装 | | LPageTable | 分页表格 | 集成筛选、分页、列设置、全屏等功能的高级表格 | | LModal | 弹窗 | 支持拖拽的模态框 | | LDrawer | 抽屉 | 可全屏、刷新的抽屉组件 | | LFilterPanel | 筛选面板 | 表单筛选组件,支持多种筛选项类型 | | LFormFooter | 表单底部栏 | 固定底部的操作按钮栏 | | LFormSubmitPage | 表单提交页 | 表单提交页通用外壳,支持卡片/分区两种布局 | | LFormSectionPage | 分区表单页 | 固定为分区样式的表单提交页 | | LSectionBlock | 区块容器 | 区块标题+内容的通用容器 | | LDetailLayout | 详情布局 | 详情页布局,含描述信息和 Tab 切换 | | LInfoLayout | 信息布局 | 滚动同步 Tab 锚点的信息展示布局 | | LFixedFooter | 固定底部 | 固定在页面底部的插槽容器 | | LSecondBar | 二级标签栏 | 顶部二级 Tab 切换栏 | | LPageNotFound | 404 页面 | 404 错误页面 | | LApprovalSteps | 审批流程 | 审批流程时间线展示组件 | | LRoleTree | 角色菜单树 | 带复选框的菜单树形结构 | | LSignStatusFlow | 签署状态流程 | 签署流程状态展示 | | LUploadFile | 文件上传 | 文件上传组件,支持附件上传和预览 | | LUploadImage | 图片上传 | 图片/视频上传组件,支持预览 | | LFilePreview | 文件预览 | 支持图片、PDF、Word、Excel、视频等多种文件预览 |
LButton
介绍
基于 Ant Design Vue AButton 的简单封装。
基本用法
<LButton type="primary">主要按钮</LButton>Props
| 参数 | 说明 | 类型 | 默认值 |
| ---- | -------- | ------------ | ----------- |
| type | 按钮类型 | ButtonType | 'default' |
ButtonType 类型
type ButtonType =
| 'primary' // 主要按钮
| 'secondary' // 次要按钮
| 'tertiary' // 幽灵按钮
| 'ghost' // 幽灵按钮
| 'link' // 链接按钮
| 'text' // 文本按钮
| 'icon' // 图标按钮
| 'default' // 默认按钮其他属性继承自 Ant Design Vue
AButton。
LPageTable
介绍
基于 Ant Design Vue Table 封装的高级表格组件,集成了筛选、分页、列设置、全屏等功能,适用于数据展示和管理场景。
基础用法
<script setup lang="ts">
import { ref } from 'vue'
import {
type LFilterPanelItem,
LPageTable,
type LPageTableColumn,
type LPageTableRefresh,
type LPageType,
} from '@xinlian-frontend/lui'
const tableRef = ref<LPageTableRef>()
const data = ref<any[]>([])
const pageInfo = ref<LPageType>({ total: 0, pageNum: 1, pageSize: 10 })
const condition = ref<Record<string,any>>({})
const columns = ref<<LPageTableColumn[]>>([
{ title: '姓名', dataIndex: 'name', width: 120 },
{ title: '年龄', dataIndex: 'age', width: 80 },
{ title: '创建时间', dataIndex: 'createTime', formatType: 'DateTime', width: 180 },
{ title: '操作', dataIndex: 'options', fixed: 'right' },
])
const filterItems = ref<LFilterPanelItem[]>([
{ key: 'name', label: '姓名', type: 'input' },
{
key: 'status',
label: '状态',
type: 'select',
options: [
{ label: '全部', value: '' },
{ label: '启用', value: '1' },
],
},
])
const refresh: LPageTableRefresh = async done => {
try {
await mockApi({ ...condition.value, ...pageInfo.value })
} finally {
done()
}
}
</script>
<template>
<LPageTable
ref="tableRef"
v-model:page="pageInfo"
v-model:condition="condition"
v-model:columns="columns"
:data="data"
:filter-items="filterItems"
@refresh="refresh"
>
<template #action>
<a-button type="primary" @click="addRef?.open">添加</a-button>
</template>
<template #name="{ record }">
<a-button type="link" @click="detailRef?.open()">{{ record.name }}</a-button>
</template>
<template #options>
<a-button type="link">删除</a-button>
</template>
<template #name-header>
{{ '姓名(自定义表头)' }}
</template>
<template #filter-age>
{{ '自定义组件' }}
</template>
</LPageTable>
</template>Props
| 参数 | 说明 | 类型 | 默认值 |
| ----------------- | ------------------ | ----------------------- | ------- |
| data | 表格数据 | Record<string, any>[] | [] |
| columns | 列配置 | LPageTableColumn[] | [] |
| filterItems | 筛选项配置 | LFilterPanelItem[] | [] |
| autoSearch | 是否自动发起搜索 | boolean | true |
| showFilter | 是否显示顶部筛选 | boolean | true |
| showRefresh | 是否显示刷新按钮 | boolean | true |
| showAction | 是否显示顶部操作列 | boolean | true |
| showRadio | 是否显示单选 | boolean | false |
| showSelection | 是否显示多选 | boolean | false |
| showPage | 是否显示分页 | boolean | true |
| showSetting | 是否显示列设置 | boolean | true |
| radioSelected | 单选选中项 | number \| string | - |
| selectionSelected | 多选选中项 | (number \| string)[] | [] |
| condition | 筛选条件 | Record<string, any> | {} |
| page | 分页信息 | LPageType | 见下文 |
| refreshLoading | 刷新加载状态 | boolean | false |
| card | 是否卡片布局 | boolean | true |
| bordered | 是否显示边框 | boolean | true |
| rowKey | 行标识字段 | string | 'id' |
LPageType 默认值
{
total: 0,
pageSize: 10,
pageNum: 1,
}Events
| 事件名 | 说明 | 参数 |
| ---------------- | ---------------------------------------------- | ------------------------------------------ |
| refresh | 刷新数据事件,参数 done 需在数据加载完成后调用 | (done: Done) => void |
| update:page | 分页变化事件 | (page: LPageType) => void |
| update:condition | 筛选条件变化事件 | (condition: Record<string, any>) => void |
| update:sortInfo | 排序信息变化事件 | (sortInfo: LTableSortInfo) => void |
| update:columns | 列配置变化事件 | (columns: LPageTableColumn[]) => void |
Slots
| 插槽名 | 说明 | | ------------------ | ----------------------------------------- | | action | 顶部操作区域 | | filter-{key} | 自定义筛选项,key 为 filterItems 中的 key | | {dataIndex} | 自定义列内容 | | {dataIndex}-header | 自定义列头 | | expandedRowRender | 展开行内容 | | expandColumnTitle | 展开列标题 | | summary | 表格底部汇总 |
方法(通过 ref 调用)
| 方法名 | 说明 | | ----------------- | ---------------- | | refresh() | 刷新表格数据 | | getRootTableRef() | 获取原生表格实例 |
类型定义
LPageTableColumn
interface LPageTableColumn<T> extends TableColumnProps {
dataIndex: T extends object ? keyof T : string
visible?: boolean // 是否显示列
promission?: boolean // 权限控制
formatType?: 'Date' | 'DateTime' | 'Money' // 格式化类型
require?: boolean // 是否必填(显示红色 *)
}LFilterPanelItem
interface LFilterPanelItem {
key: string
label: string
type?: 'input' | 'select' | 'daterange' | 'datetimerange'
options?: { label: string; value: any; disabled?: boolean }[]
placeholder?: string
startPlaceholder?: string
endPlaceholder?: string
multiple?: boolean
hide?: boolean
change?: (...args: any[]) => void
}自定义列渲染示例
<LPageTable :data="data" :columns="columns">
<!-- 自定义状态列 -->
<template #status="{ record }">
<a-tag :color="record.status === 1 ? 'green' : 'red'">
{{ record.status === 1 ? '启用' : '禁用' }}
</a-tag>
</template>
<!-- 自定义操作列 -->
<template #operation="{ record }">
<a-space>
<a-button type="link" size="small" @click="handleEdit(record)">编辑</a-button>
<a-button type="link" size="small" danger @click="handleDelete(record)">删除</a-button>
</a-space>
</template>
</LPageTable>LModal
介绍
基于 Ant Design Vue Modal 封装,支持拖拽移动的模态框组件。
基础用法
<template>
<LModal v-model:open="visible" title="弹窗标题">
<p>弹窗内容</p>
<template #footer>
<a-button @click="visible = false">取消</a-button>
<a-button type="primary" @click="handleOk">确定</a-button>
</template>
</LModal>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const visible = ref(false)
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| -------------------- | -------- | --------- | ------- |
| modelValue (v-model) | 是否显示 | boolean | false |
| title | 弹窗标题 | string | - |
Slots
| 插槽名 | 说明 | | ------- | -------------- | | default | 弹窗内容 | | title | 自定义标题区域 | | footer | 自定义底部 |
其他属性继承自 Ant Design Vue
AModal。
LDrawer
介绍
基于 Ant Design Vue Drawer 封装的抽屉组件,支持全屏切换、刷新、遮罩控制等功能。
基础用法
<template>
<LDrawer
v-model:open="visible"
title="抽屉标题"
:width="600"
placement="right"
@close="handleClose"
>
<p>抽屉内容</p>
<template #footer>
<a-space>
<a-button @click="visible = false">取消</a-button>
<a-button type="primary" @click="handleConfirm">确定</a-button>
</a-space>
</template>
</LDrawer>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const visible = ref(false)
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| ----------- | ---------------------------- | ---------------------------------------- | --------- |
| mask | 是否显示遮罩 | boolean | true |
| placement | 抽屉方向 | 'top' \| 'right' \| 'bottom' \| 'left' | 'right' |
| width | 抽屉宽度 | string \| number | '75%' |
| title | 抽屉标题 | string | - |
| loading | 加载状态,显示 Spin | boolean | false |
| showRefresh | 是否显示刷新按钮 | boolean | false |
| page | 是否启用分页模式(预留功能) | boolean | false |
Events
| 事件名 | 说明 | | ------- | ------------------- | | prev | 上一步(page 模式) | | next | 下一步(page 模式) | | refresh | 点击刷新按钮 | | close | 关闭抽屉 |
Slots
| 插槽名 | 说明 | | ----------- | ------------------ | | default | 抽屉内容 | | footer | 自定义底部 | | extra | 标题栏右侧扩展区域 | | title | 自定义标题 | | title-extra | 标题后方扩展 |
方法(通过 ref 调用)
| 方法名 | 说明 | | ------- | ------------------------ | | open() | 打开抽屉 | | close() | 关闭抽屉 | | visable | 抽屉可见性状态(响应式) |
LFilterPanel
介绍
表单筛选面板组件,支持 input、select、日期范围等多种筛选项类型,自动处理查询/重置逻辑。
基础用法
<template>
<LFilterPanel
v-model="condition"
:filter-items="filterItems"
label-width="80px"
@search="handleSearch"
@reset="handleReset"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const condition = ref({})
const filterItems = [
{ key: 'name', label: '姓名', type: 'input', placeholder: '请输入姓名' },
{
key: 'status',
label: '状态',
type: 'select',
options: [
{ label: '全部', value: '' },
{ label: '启用', value: '1' },
],
},
{
key: 'date',
label: '日期',
type: 'daterange',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
},
]
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| -------------------- | ---------------- | --------------------- | -------- |
| modelValue (v-model) | 筛选条件双向绑定 | Record<string, any> | {} |
| filterItems | 筛选项配置数组 | LFilterPanelItem[] | [] |
| labelWidth | 表单标签宽度 | number \| string | '80px' |
| collapsible | 是否可折叠 | boolean | false |
| collapsedRows | 折叠时显示的行数 | number | 1 |
| searchText | 查询按钮文本 | string | '查询' |
| resetText | 重置按钮文本 | string | '重置' |
| expandText | 展开文本 | string | '展开' |
| collapseText | 收起文本 | string | '收起' |
| card | 是否显示卡片背景 | boolean | true |
LFilterPanelItem
| 字段 | 说明 | 类型 |
| ---------------- | -------------------- | ------------------------------------------------------- |
| key | 字段标识 | string |
| label | 字段标签 | string |
| type | 筛选项类型 | 'input' \| 'select' \| 'daterange' \| 'datetimerange' |
| options | select 选项列表 | { label: string; value: any; disabled?: boolean }[] |
| placeholder | 输入框占位文本 | string |
| startPlaceholder | 日期范围开始占位文本 | string |
| endPlaceholder | 日期范围结束占位文本 | string |
| multiple | select 是否多选 | boolean |
| hide | 是否隐藏该筛选项 | boolean |
| change | 值变化时的回调 | (...args: any[]) => void |
Events
| 事件名 | 说明 | | ----------------- | ----------------------------- | | update:modelValue | 筛选条件变化 | | search | 点击查询按钮 | | reset | 点击重置按钮 | | toggle | 折叠/展开变化,参数为展开状态 |
LFormFooter
介绍
固定在页面底部的操作按钮栏组件,支持自定义按钮配置。
基础用法
<template>
<LFormFooter
:loading="submitLoading"
@close="handleClose"
@save="handleSave"
@submit="handleSubmit"
/>
</template>
<script setup lang="ts">
const submitLoading = ref(false)
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| ---------- | ------------------ | -------------------- | -------- |
| buttons | 自定义按钮配置列表 | FormFooterButton[] | [] |
| showClose | 是否显示关闭按钮 | boolean | true |
| showSave | 是否显示保存按钮 | boolean | true |
| showSubmit | 是否显示提交按钮 | boolean | true |
| loading | 全局 loading 状态 | boolean | false |
| closeText | 关闭按钮文本 | string | '关闭' |
| saveText | 保存按钮文本 | string | '保存' |
| submitText | 提交按钮文本 | string | '提交' |
FormFooterButton
interface FormFooterButton {
text: string // 按钮文本
type?: 'default' | 'primary' | 'dashed' | 'link' | 'text' // 按钮类型
loading?: boolean // loading 状态
disabled?: boolean // 是否禁用
onClick?: () => void | Promise<void> // 点击事件
}Events
| 事件名 | 说明 | | -------- | ------------ | | onClose | 点击关闭按钮 | | onSave | 点击保存按钮 | | onSubmit | 点击提交按钮 |
LFormSubmitPage
介绍
表单提交页通用外壳组件,统一页面容器、表单布局与底部操作栏。支持 卡片 (card) 和 分区 (section) 两种布局形态,可通过 props 切换或用户手动切换(自动同步到 localStorage)。
基础用法
<template>
<LFormSubmitPage
ref="pageRef"
:model="formData"
:rules="rules"
:show-save="true"
@cancel="handleCancel"
@save="handleSave"
@submit="handleSubmit"
>
<a-card title="基础信息">
<a-form-item label="名称" name="name">
<a-input v-model:value="formData.name" />
</a-form-item>
</a-card>
</LFormSubmitPage>
</template>
<script setup lang="ts">
import { message } from 'ant-design-vue'
import { reactive, ref } from 'vue'
const pageRef = ref()
const formData = reactive({ name: '' })
const rules = { name: [{ required: true, message: '请输入名称', trigger: 'blur' }] }
async function handleSubmit() {
await pageRef.value?.formRef?.validate()
message.success('提交成功')
}
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| ---------------- | -------------------- | ---------------------------------------- | -------------- |
| model | 表单绑定数据 | Record<string, unknown> | - |
| rules | 校验规则 | Record<string, unknown> | - |
| layout | 表单布局 | 'horizontal' \| 'vertical' \| 'inline' | 'horizontal' |
| variant | 展示形态 | 'card' \| 'section' | 'section' |
| showLayoutSwitch | 是否显示布局切换图标 | boolean | true |
| sections | 卡片区块配置 | FormSubmitPageSection[] | - |
| showSave | 是否显示保存按钮 | boolean | true |
| showSubmit | 是否显示提交按钮 | boolean | true |
| submitLoading | 提交按钮 loading | boolean | false |
| saveLoading | 保存按钮 loading | boolean | false |
| cancelText | 取消按钮文案 | string | '取消' |
| saveText | 保存按钮文案 | string | '保存' |
| submitText | 提交按钮文案 | string | '提交' |
FormSubmitPageSection
interface FormSubmitPageSection {
key: string // 区块唯一标识
title: string // 区块标题
desc?: string // 区块描述
}Events
| 事件名 | 说明 | | -------------- | ------------ | | cancel | 点击取消按钮 | | save | 点击保存按钮 | | submit | 点击提交按钮 | | update:variant | 布局形态变化 |
Slots
| 插槽名 | 说明 | | ------------ | ------------------------------- | | default | 表单内容区 | | card-{key} | 按 section 配置渲染卡片区块内容 | | footer | 整块自定义底部栏 | | footer-left | 底部左侧扩展 | | footer-right | 底部右侧扩展 |
Expose
| 名称 | 类型 | 说明 | | ------- | --------- | -------------------------------------------------------- | | formRef | Form 实例 | ant-design-vue Form 实例,可调用 validate/resetFields 等 |
多区块使用示例
<template>
<LFormSubmitPage
ref="pageRef"
:model="formData"
:sections="[
{ key: 'basic', title: '基础信息' },
{ key: 'detail', title: '详细信息' },
]"
>
<template #card-basic>
<a-form-item label="名称" name="name">
<a-input v-model:value="formData.name" />
</a-form-item>
</template>
<template #card-detail>
<a-form-item label="描述" name="desc">
<a-textarea v-model:value="formData.desc" />
</a-form-item>
</template>
</LFormSubmitPage>
</template>布局切换说明
开启 showLayoutSwitch 后,页面右上角会显示卡片/分区切换图标。切换结果会自动写入 localStorage(key: l-form-submit-page-layout-variant),所有开启此功能的页面会共用该状态,实现跨页面无缝同步。
LFormSectionPage
介绍
固定为 分区 (section) 形态的表单提交页,用法与 LFormSubmitPage 完全一致,仅固定为分区布局。
<LFormSectionPage :model="formData" :rules="rules">
<a-form-item label="名称" name="name">
<a-input v-model:value="formData.name" />
</a-form-item>
</LFormSectionPage>所有 Props、Slots、Events、Expose 与 LFormSubmitPage 保持一致。
LSectionBlock
介绍
区块标题+内容的通用容器组件,仅负责结构复用,样式由使用方工程提供。
基础用法
<template>
<LSectionBlock title="基本信息">
<template #header-extra>
<a-button type="link">编辑</a-button>
</template>
<p>区块内容</p>
</LSectionBlock>
</template>Props
| 参数 | 说明 | 类型 | 默认值 |
| ---------- | ---------------- | ----------- | ----------- |
| title | 标题文案 | string | '' |
| blockClass | 最外层额外 class | ClassType | undefined |
| showHeader | 是否显示头部 | boolean | true |
| loading | 加载状态 | boolean | false |
Slots
| 插槽名 | 说明 | | ------------ | ---------------- | | default | 区块内容 | | title | 自定义标题 | | header-extra | 标题右侧扩展区域 |
LDetailLayout
介绍
详情页布局组件,包含顶部描述信息区域和下方 Tab 切换区域,内置 FixedFooter 固定底部栏。
基础用法
<template>
<LDetailLayout
title="详情"
:descriptions="descriptions"
:tabs="tabs"
@tab-change="handleTabChange"
>
<template #extra>
<a-space>
<a-button>编辑</a-button>
</a-space>
</template>
<template #tab-basic>
<p>基本信息内容</p>
</template>
<template #tab-record>
<p>记录信息内容</p>
</template>
<template #footer>
<a-button @click="goBack">返回</a-button>
<a-button type="primary">提交</a-button>
</template>
</LDetailLayout>
</template>
<script setup lang="ts">
const descriptions = [
{ label: '姓名', value: '张三' },
{ label: '状态', value: '启用' },
]
const tabs = [
{ key: 'basic', label: '基本信息' },
{ key: 'record', label: '记录信息' },
]
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| ---------------- | -------------- | -------------------------- | ------------- |
| title | 页面标题 | string | - |
| descriptions | 顶部描述项配置 | LDetailDescriptionItem[] | [] |
| headerColumn | 描述信息列数 | number | 3 |
| tabs | Tab 配置列表 | LDetailTabItem[] | [] |
| defaultActiveKey | 默认激活的 Tab | string | '' |
| tabSize | Tab 尺寸 | 'small' \| 'default' | 'small' |
| loading | 加载状态 | boolean | false |
| loadingTip | 加载提示文本 | string | '加载中...' |
LDetailDescriptionItem
interface LDetailDescriptionItem {
label: string // 标签
value: string | number | undefined | null // 值
span?: number // 跨列数
}LDetailTabItem
interface LDetailTabItem {
key: string // Tab 唯一标识
label: string // Tab 显示文本
}Events
| 事件名 | 说明 | 参数 |
| --------- | ------------ | ------------- |
| tabChange | Tab 切换事件 | key: string |
Slots
| 插槽名 | 说明 | | ------------------- | ----------------------------- | | extra | 右上角扩展区域 | | description-{label} | 自定义描述项渲染,参数为 item | | tab-{key} | Tab 内容区 | | footer | 固定底部栏内容 |
LInfoLayout
介绍
信息展示布局组件,左侧为可滚动的内容区,右侧为固定 Tab 导航,支持滚动时自动高亮对应 Tab。
基础用法
<template>
<LInfoLayout :items="items" :show-menu="true">
<template #base>
<p>基础信息内容...</p>
</template>
<template #detail>
<p>详细信息内容...</p>
</template>
</LInfoLayout>
</template>
<script setup lang="ts">
const items = [
{ label: '基础信息', value: 'base', show: true },
{ label: '详细信息', value: 'detail', show: true },
]
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| -------- | ---------------------- | -------------------- | ------ |
| items | 导航项配置(双向绑定) | LInfoLayoutItems[] | [] |
| showMenu | 是否显示右侧 Tab 导航 | boolean | true |
LInfoLayoutItems
interface LInfoLayoutItems {
label: string // 导航标签
value: string // 导航值(对应插槽名)
show: boolean // 是否显示该项
hide?: boolean // 是否隐藏
}Events
| 事件名 | 说明 | | ------------ | -------------- | | update:items | items 变化事件 |
Slots
| 插槽名 | 说明 | | ------------- | ------------------ | | {value} | 各导航项对应内容 | | title-{value} | 各导航项自定义标题 | | footer | 底部内容 |
LFixedFooter
介绍
固定在页面底部的插槽容器,通过 teleport 挂载到指定容器中,适用于详情页底部操作栏。
基础用法
<template>
<LFixedFooter>
<template #footer>
<a-button @click="goBack">返回</a-button>
<a-button type="primary">提交</a-button>
</template>
</LFixedFooter>
</template>组件通过
teleport将内容挂载到#smartAdminMain容器中,配合LDetailLayout等布局组件使用效果更佳。
LSecondBar
介绍
顶部二级 Tab 切换栏组件,适用于页面顶部的分类导航。
基础用法
<template>
<LSecondBar v-model="activeTab" :tabs="tabs" @change="handleChange" />
</template>
<script setup lang="ts">
const activeTab = ref('tab1')
const tabs = [
{ label: 'Tab 1', value: 'tab1' },
{ label: 'Tab 2', value: 'tab2' },
]
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| -------------------- | ------------ | ------------------------------------ | ------ |
| modelValue (v-model) | 当前选中值 | string | - |
| tabs | Tab 配置列表 | { label: string; value: string }[] | [] |
Events
| 事件名 | 说明 | 参数 |
| ----------------- | ---------- | --------------- |
| update:modelValue | 值变化事件 | value: string |
| change | 切换事件 | value: string |
LPageNotFound
介绍
404 错误页面组件,点击按钮返回首页。
基础用法
<LPageNotFound />LApprovalSteps
介绍
审批流程时间线展示组件,以树形结构展示父流程节点和子节点审批记录,支持文件附件预览。
基础用法
<template>
<LApprovalSteps :nodes="flowData" />
</template>
<script setup lang="ts">
import type { LFlowData } from '@xinlian-frontend/lui'
const flowData: LFlowData[] = [
{
nodeName: '审批1',
enterpriseName: '企业A',
nodeStatus: 'PASS',
subInstRecordList: [
{
actualUsers: [
{
assignee: { name: '张三' },
result: 1, // 1=同意
createTime: '2024-01-01 10:00:00',
},
],
},
],
},
]
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| ----- | -------------- | ------------- | ------ |
| nodes | 父流程节点列表 | LFlowData[] | [] |
LFlowData
interface LFlowData {
approvalRole?: number // 审批身份
approvalRoleName?: string // 审批身份名称
createTime?: string // 创建时间
enterpriseId?: number // 企业id
enterpriseName?: string // 企业名称
id?: number // 主键id
nodeName?: string // 节点名
nodeStatus?: string // 节点状态
nodeStatusDesc?: string // 节点状态描述
remark?: string // 备注
subInstId?: string // 子流程实例id
subInstRecordList?: FlowInstRecordVo[] // 子流程实例审批记录
updateTime?: string // 更新时间
}节点状态说明
| 状态值 | 说明 |
| --------- | ------ |
| PASS | 已通过 |
| RUNNING | 进行中 |
| PENDING | 待审批 |
| REFUSE | 驳回 |
| REVOKED | 已撤回 |
| DELETED | 已删除 |
LRoleTree
介绍
带复选框的角色菜单树形结构组件,支持多级菜单的勾选联动(向上向下级联),自动过滤按钮类型节点。
基础用法
<template>
<LRoleTree v-model="selectedMenus" :menu="menuTree" @update:model-value="handleChange" />
</template>
<script setup lang="ts">
import type { LMenuTreeOption } from '@xinlian-frontend/lui'
const selectedMenus = ref<Array<string | number>>([])
const menuTree: LMenuTreeOption[] = [
{
id: 1,
label: '系统管理',
menuName: '系统管理',
parentId: 0,
weight: 1,
menuType: 'M',
children: [
{ id: 2, label: '用户管理', menuName: '用户管理', parentId: 1, weight: 1, menuType: 'C' },
{ id: 3, label: '角色管理', menuName: '角色管理', parentId: 1, weight: 2, menuType: 'C' },
],
},
]
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| -------------------- | -------------- | ------------------------- | ------ |
| menu | 菜单树形数据 | LMenuTreeOption[] | [] |
| modelValue (v-model) | 选中值 | Array<string \| number> | [] |
| showCheckbox | 是否显示复选框 | boolean | true |
LMenuTreeOption
interface LMenuTreeOption {
id: string | number // 唯一标识
label: string // 显示文本
menuName: string // 菜单名称
parentId: string | number // 父节点id
weight: number // 权重
menuType: 'M' | 'C' | 'F' // M=目录 C=菜单 F=按钮
children?: LMenuTreeOption[] // 子节点
}Events
| 事件名 | 说明 | 参数 |
| ----------------- | --------------------------------------------- | ------------------------- |
| update:modelValue | 选中值变化,包含全选节点和半选父节点的 id | Array<string \| number> |
方法(通过 ref 调用)
| 方法名 | 说明 | | ------------- | ------------ | | expandAll() | 展开全部节点 | | collapseAll() | 收起全部节点 |
节点联动规则
- 勾选非按钮类型节点:自动勾选其所有后代非按钮类型节点
- 取消勾选非按钮类型节点:自动取消勾选其所有后代非按钮类型节点
- 按钮类型节点 (
menuType: 'F'):不参与级联计算
LSignStatusFlow
介绍
签署状态流程展示组件,以列表形式展示签署人及其签署状态。
基础用法
<template>
<LSignStatusFlow :items="signList" />
</template>
<script setup lang="ts">
const signList = [
{ id: 1, psnName: '张三', orgName: '公司A', signResult: 2, operateTime: '2024-01-01 10:00' },
{ id: 2, psnName: '李四', orgName: '公司B', signResult: 1, operateTime: '' },
]
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| ----- | ------------ | ----------------------- | ------ |
| items | 签署记录列表 | LSignStatusFlowItem[] | [] |
LSignStatusFlowItem
interface LSignStatusFlowItem {
id?: string | number // 唯一标识
psnName?: string // 签署人姓名
orgName?: string // 组织名称
signResult?: string | number // 签署结果:2=已签署,4=已拒绝,其他=待签署
operateTime?: string // 操作时间
}签署状态说明
| signResult | 状态 | 标签颜色 |
| ---------- | ------ | --------- |
| 2 | 已签署 | success |
| 4 | 已拒绝 | error |
| 其他 | 待签署 | warning |
LUploadFile
介绍
文件上传组件,基于 Ant Design Vue Upload 封装,支持附件上传、文件预览、只读模式。
基础用法
<template>
<LUploadFile
v-model="fileList"
:action="uploadUrl"
:max-count="6"
accept=".jpg,.png,.pdf,.docx"
/>
</template>
<script setup lang="ts">
import type { LUploadFileList } from '@xinlian-frontend/lui'
const fileList = ref<LUploadFileList>([])
const uploadUrl = '/api/upload'
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| -------------------- | ------------------------ | ---------------------- | --------------------------------------- |
| modelValue (v-model) | 已上传文件列表 | LUploadFileList | [] |
| type | 展示类型 | 'normal' \| 'inline' | 'normal' |
| readonly | 只读模式(隐藏上传按钮) | boolean | false |
| accept | 允许的文件类型 | string | .jpg,.png,.jpeg,.docx,.pdf,.xls,.xlsx |
| hint | 提示文本 | string | - |
| action | 上传地址 | string | - |
| uploadText | 上传按钮文本 | string | '上传附件' |
| headers | 请求头 | any | - |
| maxCount | 最大上传数量 | number | 6 |
| maxSizeMb | 单个文件大小限制(MB) | number | - |
LUploadFileList
interface LUploadFileItem {
fileId: string // 文件id
url?: string // 文件地址
fileUrl?: string // 文件地址(别名)
originalFileName?: string // 原文件名
}
type LUploadFileList = LUploadFileItem[]Events
| 事件名 | 说明 | 参数 |
| ----------------- | ------------ | ----------------- |
| update:modelValue | 文件列表变化 | LUploadFileList |
组件内部集成了
LFilePreview,上传后可直接点击文件进行预览。
完整使用示例
<template>
<LUploadFile
v-model="fileList"
action="/api/file/upload"
:max-count="6"
:max-size-mb="10"
hint="支持 jpg、png、pdf、docx 格式,单个文件不超过 10MB"
@change="handleFileChange"
/>
</template>
<script setup lang="ts">
import type { LUploadFileList } from '@xinlian-frontend/lui'
const fileList = ref<LUploadFileList>([])
function handleFileChange(files: LUploadFileList) {
console.log('当前文件列表:', files)
}
</script>LUploadImage
介绍
图片/视频上传组件,基于 Ant Design Vue Upload 封装,使用卡片样式展示,支持预览。
基础用法
<template>
<LUploadImage v-model="imageList" :action="uploadUrl" :max-count="6" accept="image/*" />
</template>
<script setup lang="ts">
import type { LUploadFileList } from '@xinlian-frontend/lui'
const imageList = ref<LUploadFileList>([])
const uploadUrl = '/api/upload'
</script>Props
| 参数 | 说明 | 类型 | 默认值 |
| -------------------- | -------------- | ---------------------- | ----------------- |
| modelValue (v-model) | 已上传文件列表 | LUploadFileList | [] |
| type | 展示类型 | 'normal' \| 'inline' | 'normal' |
| readonly | 只读模式 | boolean | false |
| accept | 允许的文件类型 | string | image/*,video/* |
| hint | 提示文本 | string | - |
| action | 上传地址 | string | - |
| uploadText | 上传按钮文本 | string | '上传图片' |
| headers | 请求头 | any | - |
| maxCount | 最大上传数量 | number | 6 |
类型定义与事件同
LUploadFile。
LFilePreview
介绍
通用文件预览组件,支持图片、PDF、Word、Excel、视频等多种文件格式的在线预览。
基础用法
<template>
<LFilePreview ref="previewRef" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
const previewRef = ref()
// 预览图片
previewRef.value?.showDialog('https://example.com/image.jpg')
// 预览 PDF
previewRef.value?.showDialog('https://example.com/document.pdf')
// 预览 Word
previewRef.value?.showDialog('https://example.com/document.docx')
// 预览 Excel
previewRef.value?.showDialog('https://example.com/spreadsheet.xlsx')
// 预览视频
previewRef.value?.showDialog('https://example.com/video.mp4')
</script>方法
| 方法名 | 说明 | 参数 |
| ---------------------- | ------------ | ---------------------------------------------------------------------------- |
| showDialog(url, type?) | 打开预览弹窗 | url: string 文件地址;type?: string 可选文件类型,不传则根据后缀自动识别 |
支持的文件类型
| 类型 | 扩展名 | 预览方式 | | ----- | --------------------------------------- | --------------------------------- | | 图片 | png、jpg、jpeg、gif、bmp、webp | Ant Design Vue Image 组件全屏预览 | | PDF | pdf | VueOfficePdf 组件 | | Word | doc、docx | VueOfficeDocx 组件 | | Excel | xls、xlsx | VueOfficeExcel 组件 | | 视频 | mp4、webm、ogg、avi、mov、wmv、flv、mkv | HTML5 video 标签 | | 其他 | - | 显示"暂不支持预览"提示 |
注意事项
- 图片预览不通过弹窗,直接以全屏方式展示
- 文件地址需可直接访问(含权限、跨域配置等)
- 组件内部通过
showDialog方法暴露给外部调用
全局引入
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import Lui from '@xinlian-frontend/lui'
const app = createApp(App)
app.use(L Lui)
app.mount('#app')按需引入
// 按需引入单个组件
import LPageTable from '@xinlian-frontend/lui/es/page-table'
import LDrawer from '@xinlian-frontend/lui/es/drawer'注意事项
- 组件库基于 Ant Design Vue 封装,使用前请确保已正确安装 ant-design-vue
- 组件样式使用 SCSS 预处理器,支持主题变量覆盖
- 组件内部已处理大部分常见场景,如需深度定制可查看源码
- 所有涉及
id的字段统一按string类型传递,避免长整型精度丢失 - 接口请求方法
request的泛型无需嵌套ResponseData
