feat: 优化定时任务管理与日志体验

- 增加工作流选项、时间范围筛选和日志详情展示

- 支持可配置自动刷新、轻量局部更新与响应式布局
This commit is contained in:
2026-08-31 14:57:20 +08:00
parent 8c174e5c02
commit 155af9989c
9 changed files with 1533 additions and 133 deletions

View File

@@ -122,6 +122,109 @@ describe('page data recovery', () => {
expect(get).toHaveBeenCalledTimes(2);
});
it('does not let a lightweight refresh supersede an active page query', async () => {
let resolveInitialRequest: (value: {
data: { records: { id: string }[]; totalRow: number };
}) => void = () => {};
const initialRequest = new Promise<{
data: { records: { id: string }[]; totalRow: number };
}>((resolve) => {
resolveInitialRequest = resolve;
});
const get = vi.fn().mockReturnValueOnce(initialRequest);
const wrapper = mount(PageData, {
global: {
directives: { loading: {} },
},
props: {
pageUrl: '/page',
refreshUrl: '/refresh',
requestClient: { get },
},
});
const refreshRequest = (wrapper.vm as any).reload({
lightweight: true,
silent: true,
});
expect(get).toHaveBeenCalledTimes(1);
resolveInitialRequest({
data: { records: [{ id: 'counted-result' }], totalRow: 21 },
});
await refreshRequest;
await flushPromises();
expect(get).toHaveBeenCalledTimes(1);
expect(wrapper.emitted('loadSuccess')?.at(-1)?.[0]).toMatchObject({
lightweight: false,
recordCount: 1,
});
expect(wrapper.find('.el-pagination').exists()).toBe(true);
});
it('uses the lightweight refresh endpoint without replacing the total', async () => {
const get = vi
.fn()
.mockResolvedValueOnce({
data: { records: [{ id: 'initial' }], totalRow: 35 },
})
.mockResolvedValueOnce({ data: [{ id: 'latest' }] });
const wrapper = mount(PageData, {
global: {
directives: { loading: {} },
},
props: {
pageUrl: '/page',
refreshUrl: '/refresh',
requestClient: { get },
},
});
await flushPromises();
await (wrapper.vm as any).reload({ lightweight: true, silent: true });
await flushPromises();
expect(get).toHaveBeenLastCalledWith('/refresh', {
params: { pageNumber: 1, pageSize: 10 },
});
expect(wrapper.find('.el-pagination').exists()).toBe(true);
expect(wrapper.emitted('loadSuccess')?.at(-1)?.[0]).toMatchObject({
lightweight: true,
pageNumber: 1,
recordCount: 1,
});
});
it('falls back to the counted page endpoint outside the first page', async () => {
const get = vi
.fn()
.mockResolvedValue({ data: { records: [], totalRow: 30 } });
const wrapper = mount(PageData, {
global: {
directives: { loading: {} },
},
props: {
initialPageNumber: 2,
pageUrl: '/page',
refreshUrl: '/refresh',
requestClient: { get },
},
});
await flushPromises();
await (wrapper.vm as any).reload({ lightweight: true, silent: true });
await flushPromises();
expect(get).toHaveBeenLastCalledWith('/page', {
params: { pageNumber: 2, pageSize: 10 },
});
expect(wrapper.emitted('loadSuccess')?.at(-1)?.[0]).toMatchObject({
lightweight: false,
pageNumber: 2,
});
});
it('restores a mounted list to a new route state with one target request', async () => {
const get = vi
.fn()