Appearance
BizAuditLog 操作记录
审计日志时间轴:内置筛选条(关键字 / 模块 / 类型 / 日期区间)+ 按天分组(今天 / 昨天 / 具体日期)的记录列表——操作人、动作、类型标签、操作对象、成功 / 失败标记、meta 行(模块 · IP · 地点)、可展开明细(插槽可接管)。列表本地过滤,服务端分页由业务层监听 filter-change 回填。合规审计、操作留痕、变更历史页标配。
基础用法
今天3 条
张伟导出订单报表导出2026-10 订单明细成功16:20:12
订单中心·IP 10.8.12.36·上海 · 静安
筛选条件:近 30 天 · 已支付订单,共 8,642 行,导出耗时 12.3s
李娜修改商品价格修改SKU-10023872成功14:05:12
商品中心·IP 10.8.9.101·上海 · 浦东
零售价 199.00 → 179.00(限时活动)
王强删除临时营销页删除页面「双十一种草」 失败 10:42:12
营销中心·IP 223.104.5.18
失败原因:页面仍被 3 个进行中活动引用,需先解除引用
昨天2 条
陈静新增会员标签新增标签「高净值」成功18:30:12
会员中心·IP 10.8.12.55·杭州 · 西湖
赵磊调整库存预警阈值修改库存预警规则成功09:15:12
商品中心·IP 10.8.9.77·杭州 · 滨江
默认阈值 50 → 80,自 2026-10-25 生效
2026-10-231 条
张伟批量导入用户导入user-2026-10.xlsx成功11:02:12
系统设置·IP 10.8.12.36
共 1,204 行:成功 1,198,失败 6(手机号格式错误)
按天分组 + 成功 / 失败标记 + 详情展开。
<script setup lang="ts">
/** 场景:基础——按天分组(今天/昨天/更早)、成功/失败标记、详情展开 */
import { BizAuditLog } from 'vue3-ep-biz-lib'
import type { BizAuditLogItem } from 'vue3-ep-biz-lib'
const dayOf = (offset: number, h: number, m: number): string => {
const d = new Date()
d.setDate(d.getDate() - offset)
d.setHours(h, m, 12, 0)
return d.toISOString()
}
const logs: BizAuditLogItem[] = [
{
id: '1',
action: '导出订单报表',
operator: '张伟',
time: dayOf(0, 16, 20),
module: '订单中心',
type: '导出',
target: '2026-10 订单明细',
ip: '10.8.12.36',
location: '上海 · 静安',
detail: '筛选条件:近 30 天 · 已支付订单,共 8,642 行,导出耗时 12.3s',
},
{
id: '2',
action: '修改商品价格',
operator: '李娜',
time: dayOf(0, 14, 5),
module: '商品中心',
type: '修改',
target: 'SKU-10023872',
ip: '10.8.9.101',
location: '上海 · 浦东',
detail: '零售价 199.00 → 179.00(限时活动)',
},
{
id: '3',
action: '删除临时营销页',
operator: '王强',
time: dayOf(0, 10, 42),
module: '营销中心',
type: '删除',
target: '页面「双十一种草」',
ip: '223.104.5.18',
result: 'fail',
detail: '失败原因:页面仍被 3 个进行中活动引用,需先解除引用',
},
{
id: '4',
action: '新增会员标签',
operator: '陈静',
time: dayOf(1, 18, 30),
module: '会员中心',
type: '新增',
target: '标签「高净值」',
ip: '10.8.12.55',
location: '杭州 · 西湖',
},
{
id: '5',
action: '调整库存预警阈值',
operator: '赵磊',
time: dayOf(1, 9, 15),
module: '商品中心',
type: '修改',
target: '库存预警规则',
ip: '10.8.9.77',
location: '杭州 · 滨江',
detail: '默认阈值 50 → 80,自 2026-10-25 生效',
},
{
id: '6',
action: '批量导入用户',
operator: '张伟',
time: dayOf(3, 11, 2),
module: '系统设置',
type: '导入',
target: 'user-2026-10.xlsx',
ip: '10.8.12.36',
detail: '共 1,204 行:成功 1,198,失败 6(手机号格式错误)',
},
]
</script>
<template>
<BizAuditLog :logs="logs" :show-filter="false" />
</template>
显示代码
内置筛选
全部模块
全部类型
至
今天2 条
张伟导出订单报表导出2026-10 订单明细成功16:20:03
订单中心
李娜修改商品价格修改SKU-10023872成功14:05:03
商品中心
昨天2 条
陈静新增会员标签新增标签「高净值」成功18:30:03
会员中心
王强删除营销页删除页面「双十一种草」成功10:42:03
营销中心
2026-10-241 条
李娜导出会员名单导出10 月新增会员成功15:08:03
会员中心
2026-10-221 条
赵磊修改库存预警阈值修改库存预警规则成功09:15:03
商品中心
最近一次筛选:(未筛选)(服务端分页场景在 filter-change 里拉取当页数据回填)
关键字 / 模块 / 类型 / 日期区间本地过滤,
filter-change 同步外抛。<script setup lang="ts">
/** 场景:内置筛选——关键字/模块/类型/日期区间本地过滤,filter-change 外抛 */
import { ref } from 'vue'
import { BizAuditLog } from 'vue3-ep-biz-lib'
import type { BizAuditLogFilter, BizAuditLogItem } from 'vue3-ep-biz-lib'
const dayOf = (offset: number, h: number, m: number): string => {
const d = new Date()
d.setDate(d.getDate() - offset)
d.setHours(h, m, 3, 0)
return d.toISOString()
}
const logs: BizAuditLogItem[] = [
{ id: '1', action: '导出订单报表', operator: '张伟', time: dayOf(0, 16, 20), module: '订单中心', type: '导出', target: '2026-10 订单明细' },
{ id: '2', action: '修改商品价格', operator: '李娜', time: dayOf(0, 14, 5), module: '商品中心', type: '修改', target: 'SKU-10023872' },
{ id: '3', action: '新增会员标签', operator: '陈静', time: dayOf(1, 18, 30), module: '会员中心', type: '新增', target: '标签「高净值」' },
{ id: '4', action: '删除营销页', operator: '王强', time: dayOf(1, 10, 42), module: '营销中心', type: '删除', target: '页面「双十一种草」' },
{ id: '5', action: '导出会员名单', operator: '李娜', time: dayOf(2, 15, 8), module: '会员中心', type: '导出', target: '10 月新增会员' },
{ id: '6', action: '修改库存预警阈值', operator: '赵磊', time: dayOf(4, 9, 15), module: '商品中心', type: '修改', target: '库存预警规则' },
]
const lastFilter = ref<string>('(未筛选)')
const onFilterChange = (filter: BizAuditLogFilter): void => {
lastFilter.value = `关键字「${filter.keyword || '无'}」 · 模块「${filter.module || '全部'}」 · 类型「${filter.type || '全部'}」`
}
</script>
<template>
<div>
<BizAuditLog
:logs="logs"
:module-options="[
{ label: '订单中心', value: '订单中心' },
{ label: '商品中心', value: '商品中心' },
{ label: '会员中心', value: '会员中心' },
{ label: '营销中心', value: '营销中心' },
]"
:type-options="[
{ label: '新增', value: '新增' },
{ label: '修改', value: '修改' },
{ label: '删除', value: '删除' },
{ label: '导出', value: '导出' },
]"
@filter-change="onFilterChange"
/>
<p style="margin: 10px 0 0; font-size: 12px; color: var(--el-text-color-secondary)">
最近一次筛选:{{ lastFilter }}(服务端分页场景在 filter-change 里拉取当页数据回填)
</p>
</div>
</template>
显示代码
失败记录
今天4 条
张伟批量导入用户导入user-2026-10.xlsx 失败 11:02:45
系统设置
失败原因:第 208 / 666 行手机号格式错误,整批已回滚
李娜调价审批提交修改 失败 10:18:45
商品中心
失败原因:超过单次调价幅度上限(30%),需拆分审批单
王强删除会员标签删除标签「流失预警」 失败 09:30:45
会员中心
失败原因:标签被 2 个自动化策略引用,需先解除引用
陈静新增会员标签新增标签「高净值」成功09:02:45
会员中心
失败记录红点 + 危险标签 + 失败原因明细。
<script setup lang="ts">
/** 场景:失败记录——红点 / 危险标签 / 失败原因明细 */
import { BizAuditLog } from 'vue3-ep-biz-lib'
import type { BizAuditLogItem } from 'vue3-ep-biz-lib'
const dayOf = (offset: number, h: number, m: number): string => {
const d = new Date()
d.setDate(d.getDate() - offset)
d.setHours(h, m, 45, 0)
return d.toISOString()
}
const logs: BizAuditLogItem[] = [
{
id: '1',
action: '批量导入用户',
operator: '张伟',
time: dayOf(0, 11, 2),
module: '系统设置',
type: '导入',
target: 'user-2026-10.xlsx',
result: 'fail',
detail: '失败原因:第 208 / 666 行手机号格式错误,整批已回滚',
},
{
id: '2',
action: '调价审批提交',
operator: '李娜',
time: dayOf(0, 10, 18),
module: '商品中心',
type: '修改',
result: 'fail',
detail: '失败原因:超过单次调价幅度上限(30%),需拆分审批单',
},
{
id: '3',
action: '删除会员标签',
operator: '王强',
time: dayOf(0, 9, 30),
module: '会员中心',
type: '删除',
target: '标签「流失预警」',
result: 'fail',
detail: '失败原因:标签被 2 个自动化策略引用,需先解除引用',
},
{ id: '4', action: '新增会员标签', operator: '陈静', time: dayOf(0, 9, 2), module: '会员中心', type: '新增', target: '标签「高净值」' },
]
</script>
<template>
<BizAuditLog :logs="logs" :show-filter="false" />
</template>
显示代码
自定义明细
今天1 条
李娜修改商品信息修改SKU-10023872成功14:05:30
商品中心
零售价199.00→179.00
库存500→800
上架状态草稿→在售
昨天1 条
王强修改配送模板修改模板「江浙沪包邮」成功16:40:30
商品中心
包邮门槛满 99 元→满 79 元
detail 插槽接管展开区(变更字段前后对照等富展示)。<script setup lang="ts">
/** 场景:detail 插槽——变更字段前后对照等富展示 */
import { BizAuditLog } from 'vue3-ep-biz-lib'
import type { BizAuditLogItem } from 'vue3-ep-biz-lib'
interface SkuChange {
field: string
before: string
after: string
}
const dayOf = (offset: number, h: number, m: number): string => {
const d = new Date()
d.setDate(d.getDate() - offset)
d.setHours(h, m, 30, 0)
return d.toISOString()
}
const logs: BizAuditLogItem[] = [
{
id: '1',
action: '修改商品信息',
operator: '李娜',
time: dayOf(0, 14, 5),
module: '商品中心',
type: '修改',
target: 'SKU-10023872',
extra: {
changes: [
{ field: '零售价', before: '199.00', after: '179.00' },
{ field: '库存', before: '500', after: '800' },
{ field: '上架状态', before: '草稿', after: '在售' },
] as SkuChange[],
},
},
{
id: '2',
action: '修改配送模板',
operator: '王强',
time: dayOf(1, 16, 40),
module: '商品中心',
type: '修改',
target: '模板「江浙沪包邮」',
extra: {
changes: [
{ field: '包邮门槛', before: '满 99 元', after: '满 79 元' },
] as SkuChange[],
},
},
]
</script>
<template>
<BizAuditLog :logs="logs" :show-filter="false">
<template #detail="{ log }">
<div class="demo-audit-changes">
<div v-for="(change, i) in (log.extra?.changes as SkuChange[])" :key="i" class="demo-audit-change">
<span class="demo-audit-field">{{ change.field }}</span>
<span class="demo-audit-before">{{ change.before }}</span>
<span class="demo-audit-arrow">→</span>
<span class="demo-audit-after">{{ change.after }}</span>
</div>
</div>
</template>
</BizAuditLog>
</template>
<style scoped>
.demo-audit-changes {
display: flex;
flex-direction: column;
gap: 4px;
}
.demo-audit-change {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
}
.demo-audit-field {
min-width: 72px;
color: var(--el-text-color-secondary);
}
.demo-audit-before {
color: var(--el-color-danger);
text-decoration: line-through;
}
.demo-audit-arrow {
color: var(--el-text-color-placeholder);
}
.demo-audit-after {
color: var(--el-color-success);
font-weight: 500;
}
</style>
显示代码
变更前后对照(changes)
操作记录3 条
张采购修改供应商档案修改SUP-0086 华东包装成功2026-10-23 10:24:00
供应商
变更前 +0~5-0
联系人
刘经理
→
陈经理
修改联系电话
13900000086
→
13900000099
修改结算周期(天)
30
→
45
修改统一社会信用代码
91350100M000100Y43
→
—
修改备注
—
→
战略供应商(年度框架)
修改李仓管修改入库单修改IN-20261023-004成功2026-10-23 09:10:00
仓储
变更前 +0~2-0
入库数量
120
→
100
修改批次号
B-1023
→
B-1023A
修改王财务导出库存月报导出成功2026-10-23 08:30:00
报表
2026-09 库存月报.xlsx(24 个仓库,3.2 万行)
带 changes 的日志点「详情」展开字段级对照:修改高亮、删除划线、新增绿色、未变灰底;纯文本 detail 日志行为不变。
日志项带
changes: [{ field, label?, oldValue, newValue }] 时展开区自动渲染字段级 diff(内部复用 BizDiffViewer table 模式):修改高亮、删除划线、新增绿色;纯文本 detail 日志行为不变。<script setup lang="ts">
/** 场景:变更前后对照——日志项 changes 明细在展开区渲染字段级 diff(复用 BizDiffViewer table 模式) */
import { BizAuditLog } from 'vue3-ep-biz-lib'
import type { BizAuditLogItem } from 'vue3-ep-biz-lib'
const logs: BizAuditLogItem[] = [
{
id: '1',
action: '修改供应商档案',
operator: '张采购',
time: '2026-10-23 10:24:00',
module: '供应商',
type: '修改',
target: 'SUP-0086 华东包装',
result: 'success',
changes: [
{ field: 'contact', label: '联系人', oldValue: '刘经理', newValue: '陈经理' },
{ field: 'phone', label: '联系电话', oldValue: '13900000086', newValue: '13900000099' },
{ field: 'settleDays', label: '结算周期(天)', oldValue: 30, newValue: 45 },
{ field: 'creditCode', label: '统一社会信用代码', oldValue: '91350100M000100Y43' },
{ field: 'remark', label: '备注', newValue: '战略供应商(年度框架)' },
],
},
{
id: '2',
action: '修改入库单',
operator: '李仓管',
time: '2026-10-23 09:10:00',
module: '仓储',
type: '修改',
target: 'IN-20261023-004',
result: 'success',
changes: [
{ field: 'qty', label: '入库数量', oldValue: 120, newValue: 100 },
{ field: 'batchNo', label: '批次号', oldValue: 'B-1023', newValue: 'B-1023A' },
],
},
{
id: '3',
action: '导出库存月报',
operator: '王财务',
time: '2026-10-23 08:30:00',
module: '报表',
type: '导出',
result: 'success',
detail: '2026-09 库存月报.xlsx(24 个仓库,3.2 万行)',
},
]
</script>
<template>
<div style="max-width: 760px">
<BizAuditLog :logs="logs" :show-filter="false" :group-by-day="false" />
<p style="margin-top: 10px; font-size: 13px; color: var(--el-text-color-secondary)">
带 changes 的日志点「详情」展开字段级对照:修改高亮、删除划线、新增绿色、未变灰底;纯文本 detail 日志行为不变。
</p>
</div>
</template>
显示代码
自定义 meta
meta 插槽接管第二行(extra 单号链接、耗时等业务字段)。<script setup lang="ts">
/** 场景:meta 插槽 + 平铺模式——extra 业务字段(单号链接、耗时),groupByDay=false 完整时间 */
import { BizAuditLog } from 'vue3-ep-biz-lib'
import type { BizAuditLogItem } from 'vue3-ep-biz-lib'
const dayOf = (offset: number, h: number, m: number): string => {
const d = new Date()
d.setDate(d.getDate() - offset)
d.setHours(h, m, 18, 0)
return d.toISOString()
}
const logs: BizAuditLogItem[] = [
{ id: '1', action: '审批通过', operator: '周主管', time: dayOf(0, 15, 10), module: '订单中心', type: '审核', target: '退款单 REF-20261020-001', ip: '10.8.3.21', extra: { orderNo: 'SO-58231', cost: '3.2s' } },
{ id: '2', action: '审批驳回', operator: '周主管', time: dayOf(0, 11, 44), module: '订单中心', type: '审核', target: '退款单 REF-20261020-002', ip: '10.8.3.21', extra: { orderNo: 'SO-58417', cost: '1.8s' } },
{ id: '3', action: '订单发货', operator: '系统', time: dayOf(1, 9, 5), module: '订单中心', type: '修改', target: 'SO-58002', ip: '—', extra: { orderNo: 'SO-58002', cost: '0.4s' } },
]
</script>
<template>
<BizAuditLog :logs="logs" :show-filter="false" :group-by-day="false">
<template #meta="{ log }">
<span>关联订单
<a class="demo-audit-link" href="javascript:void(0)">{{ log.extra?.orderNo }}</a>
</span>
<span>·</span>
<span>耗时 {{ log.extra?.cost }}</span>
<span>·</span>
<span>IP {{ log.ip }}</span>
</template>
</BizAuditLog>
</template>
<style scoped>
.demo-audit-link {
color: var(--el-color-primary);
}
</style>
显示代码
加载与空态
当日暂无操作记录
loading 过渡态与空列表占位切换。<script setup lang="ts">
/** 场景:loading 加载态与空列表占位切换 */
import { ref } from 'vue'
import { ElButton } from 'element-plus'
import { BizAuditLog } from 'vue3-ep-biz-lib'
import type { BizAuditLogItem } from 'vue3-ep-biz-lib'
const loading = ref(false)
const logs = ref<BizAuditLogItem[]>([])
const dayOf = (h: number, m: number): string => {
const d = new Date()
d.setHours(h, m, 0, 0)
return d.toISOString()
}
const load = (): void => {
loading.value = true
logs.value = []
setTimeout(() => {
logs.value = [
{ id: '1', action: '导出订单报表', operator: '张伟', time: dayOf(16, 20), module: '订单中心', type: '导出' },
{ id: '2', action: '新增会员标签', operator: '陈静', time: dayOf(11, 8), module: '会员中心', type: '新增' },
]
loading.value = false
}, 1200)
}
</script>
<template>
<div>
<div style="margin-bottom: 10px; display: flex; gap: 8px">
<ElButton size="small" type="primary" plain :loading="loading" @click="load">加载当日记录</ElButton>
<ElButton size="small" @click="logs = []">清空</ElButton>
</div>
<BizAuditLog :logs="logs" :loading="loading" :show-filter="false" empty-text="当日暂无操作记录" />
</div>
</template>
显示代码
程序化筛选
全部模块
全部类型
至
今天1 条
张伟导出订单报表导出成功16:20:00
订单中心
昨天1 条
李娜修改商品价格修改成功11:20:00
商品中心
2026-10-241 条
王强删除临时页面删除成功09:20:00
营销中心
expose
setFilter / clearFilter:URL 参数回填、外部条件联动场景。<script setup lang="ts">
/** 场景:setFilter / clearFilter 程序化筛选——外部条件(如 URL 参数)回填 */
import { ref } from 'vue'
import { ElButton } from 'element-plus'
import { BizAuditLog } from 'vue3-ep-biz-lib'
import type { BizAuditLogInstance } from 'vue3-ep-biz-lib'
const dayOf = (offset: number, h: number): string => {
const d = new Date()
d.setDate(d.getDate() - offset)
d.setHours(h, 20, 0, 0)
return d.toISOString()
}
const logs = [
{ id: '1', action: '导出订单报表', operator: '张伟', time: dayOf(0, 16), module: '订单中心', type: '导出' },
{ id: '2', action: '修改商品价格', operator: '李娜', time: dayOf(1, 11), module: '商品中心', type: '修改' },
{ id: '3', action: '删除临时页面', operator: '王强', time: dayOf(2, 9), module: '营销中心', type: '删除' },
]
const refEl = ref<BizAuditLogInstance | null>(null)
const filterByExport = (): void => {
refEl.value?.setFilter({ keyword: '导出' })
}
const filterByGoods = (): void => {
refEl.value?.setFilter({ module: '商品中心' })
}
</script>
<template>
<div>
<div style="margin-bottom: 10px; display: flex; gap: 8px">
<ElButton size="small" @click="filterByExport">setFilter(关键字=导出)</ElButton>
<ElButton size="small" @click="filterByGoods">setFilter(模块=商品中心)</ElButton>
<ElButton size="small" @click="refEl?.clearFilter()">clearFilter()</ElButton>
</div>
<BizAuditLog
ref="refEl"
:logs="logs"
:module-options="[
{ label: '订单中心', value: '订单中心' },
{ label: '商品中心', value: '商品中心' },
{ label: '营销中心', value: '营销中心' },
]"
@filter-change="() => {}"
/>
</div>
</template>
显示代码
筛选条接管
操作人
今天3 条
张伟调整库存阈值成功15:40:00
商品中心
李娜新增会员标签成功11:40:00
会员中心
张伟调整库存预警成功09:40:00
商品中心
filter 插槽整体替换内置筛选条,配合业务侧统一数据流自行过滤。<script setup lang="ts">
/** 场景:filter 插槽整体接管——自定义筛选条(如接入统一查询区) */
import { ref } from 'vue'
import { ElInput, ElSelect, ElOption } from 'element-plus'
import { BizAuditLog } from 'vue3-ep-biz-lib'
import type { BizAuditLogItem } from 'vue3-ep-biz-lib'
const keyword = ref('')
const operator = ref('')
const dayOf = (h: number): string => {
const d = new Date()
d.setHours(h, 40, 0, 0)
return d.toISOString()
}
const allLogs: BizAuditLogItem[] = [
{ id: '1', action: '调整库存阈值', operator: '张伟', time: dayOf(15), module: '商品中心' },
{ id: '2', action: '新增会员标签', operator: '李娜', time: dayOf(11), module: '会员中心' },
{ id: '3', action: '调整库存预警', operator: '张伟', time: dayOf(9), module: '商品中心' },
]
const logs = ref<BizAuditLogItem[]>(allLogs)
const apply = (): void => {
logs.value = allLogs.filter(
(log) =>
(keyword.value === '' || log.action.includes(keyword.value)) &&
(operator.value === '' || log.operator === operator.value),
)
}
</script>
<template>
<BizAuditLog :logs="logs" :show-filter="false">
<template #filter>
<div style="display: flex; gap: 8px; margin-bottom: 10px">
<ElInput v-model="keyword" placeholder="操作关键字" clearable style="width: 200px" @input="apply" />
<ElSelect v-model="operator" placeholder="操作人" clearable style="width: 160px" @change="apply">
<ElOption label="张伟" value="张伟" />
<ElOption label="李娜" value="李娜" />
</ElSelect>
</div>
</template>
</BizAuditLog>
</template>
显示代码
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| logs | BizAuditLogItem[] | [] | 日志列表(组件内本地过滤) |
| loading | boolean | false | 加载态 |
| show-filter | boolean | true | 内置筛选条 |
| module-options | BizAuditLogOption[] | [] | 模块筛选项 |
| type-options | BizAuditLogOption[] | [] | 类型筛选项 |
| group-by-day | boolean | true | 按天分组;false 平铺(时间列显示完整日期) |
| show-result | boolean | true | 操作结果标记(成功 / 失败) |
| max-height | number | string | 480 | 列表最大高度(超出滚动) |
| empty-text | string | '暂无操作记录' | 空态文案 |
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| filter-change | (filter: BizAuditLogFilter) | 筛选变化(关键字 300ms 防抖),服务端查询时机 |
Slots
| 插槽名 | 作用域 | 说明 |
|---|---|---|
| filter | — | 筛选条整体接管 |
| meta | { log } | 第二行 meta 区接管 |
| detail | { log, expanded } | 展开明细接管 |
| empty | — | 空态接管 |
Expose
| 名称 | 类型 | 说明 |
|---|---|---|
| getFilter | () => BizAuditLogFilter | 取当前筛选(拷贝) |
| setFilter | (partial) => void | 合并写入筛选(触发过滤与 filter-change) |
| clearFilter | () => void | 清空筛选 |
TIP
组件只做展示与本地过滤:大数据量走服务端分页时监听 filter-change 拉取当页 logs 回填;行内仅展示当页数据同样按天分组。与 BizLogViewer(实时日志流)互补,本组件面向业务操作留痕。