refactor(prefetch): 拆分预拉取订单日志和列表为独立组件
- 将预拉取订单日志相关代码拆分到 prefetch-logs 组件中 - 将预拉取订单列表相关代码拆分到 prefetch-orders 组件中 - 在主页面使用 prefetch-logs 和 prefetch-orders 组件替代原内嵌实现 - 优化主页面代码结构,移除重复和冗余的代码 - 保持功能与交互不变,方便后续维护与扩展
This commit is contained in:
284
src/views/camel-oil-info/prefetch/components/prefetch-logs.vue
Normal file
284
src/views/camel-oil-info/prefetch/components/prefetch-logs.vue
Normal file
@@ -0,0 +1,284 @@
|
||||
<template>
|
||||
<div class="prefetch-logs">
|
||||
<!-- 搜索表单区域 -->
|
||||
<a-row>
|
||||
<a-col :flex="1">
|
||||
<a-form
|
||||
:model="formModel"
|
||||
:label-col-props="{ span: 6 }"
|
||||
:wrapper-col-props="{ span: 18 }"
|
||||
label-align="left"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="8">
|
||||
<a-form-item field="startTime" label="开始时间">
|
||||
<a-date-picker
|
||||
v-model="formModel.startTime"
|
||||
style="width: 100%"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
show-time
|
||||
placeholder="请选择开始时间"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item field="endTime" label="结束时间">
|
||||
<a-date-picker
|
||||
v-model="formModel.endTime"
|
||||
style="width: 100%"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
show-time
|
||||
placeholder="请选择结束时间"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-col>
|
||||
<a-divider style="height: 42px" direction="vertical" />
|
||||
<a-col flex="180px" style="text-align: right">
|
||||
<a-space direction="horizontal" :size="18">
|
||||
<a-button type="primary" @click="searchLogs">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click="resetLogs">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider style="margin-top: 0" />
|
||||
|
||||
<!-- 表格操作按钮 -->
|
||||
<div class="table-actions">
|
||||
<a-button @click="$emit('showSettings')">
|
||||
<template #icon>
|
||||
<icon-settings />
|
||||
</template>
|
||||
设置
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<!-- 日志数据文本区域 -->
|
||||
<div class="log-container">
|
||||
<div class="log-header">
|
||||
<span class="log-title">预拉取订单日志</span>
|
||||
</div>
|
||||
<div ref="logContentRef" class="log-content">
|
||||
<div v-if="loading" class="log-loading">
|
||||
<a-spin />
|
||||
<span>加载日志中...</span>
|
||||
</div>
|
||||
<div v-else-if="logsRenderData.length === 0" class="log-empty">
|
||||
暂无日志数据
|
||||
</div>
|
||||
<div v-else class="log-entries">
|
||||
<div
|
||||
v-for="(log, index) in logsRenderData"
|
||||
:key="log.timestamp || index"
|
||||
class="log-entry"
|
||||
>
|
||||
<div class="log-time">
|
||||
{{ formatDateTime(log.timestamp) }}
|
||||
</div>
|
||||
<div class="log-response">
|
||||
<div class="log-response-header">
|
||||
<span>响应数据:</span>
|
||||
</div>
|
||||
<div class="log-response-content">
|
||||
{{ log.responseData || '无响应数据' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import type { KamiApiCamelOilV1PrefetchOrderLogItem } from '@/api/generated/index.ts';
|
||||
import { jdV2PrefetchClient } from '@/api/index.ts';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
interface Emits {
|
||||
(e: 'showSettings'): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const { loading, setLoading } = useLoading(false);
|
||||
|
||||
const formModel = reactive({
|
||||
startTime: null,
|
||||
endTime: null
|
||||
});
|
||||
|
||||
const logsRenderData = ref<KamiApiCamelOilV1PrefetchOrderLogItem[]>([]);
|
||||
|
||||
const generateFormModel = () => {
|
||||
const now = dayjs();
|
||||
return {
|
||||
startTime: now.subtract(1, 'day').toDate(),
|
||||
endTime: now.toDate()
|
||||
};
|
||||
};
|
||||
|
||||
// 初始化表单数据
|
||||
formModel.startTime = generateFormModel().startTime;
|
||||
formModel.endTime = generateFormModel().endTime;
|
||||
|
||||
const formatDateTime = (dateTime: string | undefined): string => {
|
||||
if (!dateTime) return '-';
|
||||
return dayjs(dateTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
};
|
||||
|
||||
const fetchLogs = async () => {
|
||||
if (!formModel.startTime || !formModel.endTime) {
|
||||
Message.warning({
|
||||
content: '请选择开始时间和结束时间',
|
||||
closable: true
|
||||
});
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const { data } = await jdV2PrefetchClient.apiJdV2PrefetchLogsGet({
|
||||
startTime: dayjs(formModel.startTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
endTime: dayjs(formModel.endTime).format('YYYY-MM-DD HH:mm:ss')
|
||||
});
|
||||
|
||||
// 直接使用API返回的全部日志数据
|
||||
logsRenderData.value = data.logs || [];
|
||||
} catch (err) {
|
||||
console.error('获取预拉取订单日志失败:', err);
|
||||
Message.error({
|
||||
content: '获取预拉取订单日志失败',
|
||||
closable: true
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const searchLogs = () => {
|
||||
fetchLogs();
|
||||
};
|
||||
|
||||
const resetLogs = () => {
|
||||
const defaultData = generateFormModel();
|
||||
formModel.startTime = defaultData.startTime;
|
||||
formModel.endTime = defaultData.endTime;
|
||||
searchLogs();
|
||||
};
|
||||
|
||||
// 组件挂载时加载数据
|
||||
fetchLogs();
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.prefetch-logs {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.table-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 日志容器样式 */
|
||||
.log-container {
|
||||
border: 1px solid var(--color-border-2);
|
||||
border-radius: var(--border-radius-medium);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.log-header {
|
||||
padding: 12px 16px;
|
||||
background-color: var(--color-fill-1);
|
||||
border-bottom: 1px solid var(--color-border-2);
|
||||
}
|
||||
|
||||
.log-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
|
||||
.log-content {
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
background-color: var(--color-bg-2);
|
||||
}
|
||||
|
||||
.log-loading,
|
||||
.log-empty {
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
color: var(--color-text-3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.log-entries {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.log-entry {
|
||||
margin-bottom: 16px;
|
||||
padding: 12px;
|
||||
background-color: var(--color-bg-1);
|
||||
border: 1px solid var(--color-border-2);
|
||||
border-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
.log-entry:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.log-time {
|
||||
font-size: 12px;
|
||||
color: var(--color-text-3);
|
||||
margin-bottom: 8px;
|
||||
font-family: Monaco, Menlo, 'Ubuntu Mono', monospace;
|
||||
}
|
||||
|
||||
.log-response-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.log-response-header span {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
|
||||
.log-response-content {
|
||||
font-size: 12px;
|
||||
color: var(--color-text-2);
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
background-color: var(--color-fill-1);
|
||||
padding: 8px;
|
||||
border-radius: var(--border-radius-small);
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
356
src/views/camel-oil-info/prefetch/components/prefetch-orders.vue
Normal file
356
src/views/camel-oil-info/prefetch/components/prefetch-orders.vue
Normal file
@@ -0,0 +1,356 @@
|
||||
<template>
|
||||
<div class="prefetch-orders">
|
||||
<!-- 搜索表单区域 -->
|
||||
<a-row>
|
||||
<a-col :flex="1">
|
||||
<a-form
|
||||
:model="formModel"
|
||||
:label-col-props="{ span: 6 }"
|
||||
:wrapper-col-props="{ span: 18 }"
|
||||
label-align="left"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="6">
|
||||
<a-form-item field="accountName" label="账号名称">
|
||||
<a-input
|
||||
v-model="formModel.accountName"
|
||||
placeholder="请输入账号名称"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item field="platformOrderNo" label="平台订单号">
|
||||
<a-input
|
||||
v-model="formModel.platformOrderNo"
|
||||
placeholder="请输入平台订单号"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item field="amount" label="订单金额">
|
||||
<a-input-number
|
||||
v-model="formModel.amount"
|
||||
placeholder="请输入订单金额"
|
||||
style="width: 100%"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item field="status" label="状态">
|
||||
<a-select
|
||||
v-model="formModel.status"
|
||||
placeholder="请选择状态"
|
||||
allow-clear
|
||||
>
|
||||
<a-option :value="1">待匹配</a-option>
|
||||
<a-option :value="2">已匹配</a-option>
|
||||
<a-option :value="3">已过期</a-option>
|
||||
<a-option :value="4">已失效</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="8">
|
||||
<a-form-item field="dateRange" label="创建时间">
|
||||
<a-range-picker
|
||||
v-model="formModel.dateRange"
|
||||
style="width: 100%"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
:placeholder="['开始日期', '结束日期']"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-col>
|
||||
<a-divider style="height: 42px" direction="vertical" />
|
||||
<a-col flex="180px" style="text-align: right">
|
||||
<a-space direction="horizontal" :size="18">
|
||||
<a-button type="primary" @click="searchOrders">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click="resetOrders">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider style="margin-top: 0" />
|
||||
|
||||
<!-- 订单数据表格区域 -->
|
||||
<a-table
|
||||
:loading="loading"
|
||||
:data="ordersRenderData"
|
||||
:columns="orderColumns"
|
||||
:scroll="{ x: 1600 }"
|
||||
:pagination="{
|
||||
current: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
total: pagination.total,
|
||||
pageSizeOptions: [10, 20, 50, 100],
|
||||
showPageSize: true
|
||||
}"
|
||||
row-key="id"
|
||||
@page-change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
>
|
||||
<!-- 订单金额列模板 -->
|
||||
<template #orderAmount="{ record }">
|
||||
<span v-if="record.amount">¥{{ record.amount.toFixed(2) }}</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<!-- 状态列模板 -->
|
||||
<template #orderStatus="{ record }">
|
||||
<a-tag v-if="record.status" :color="getStatusColor(record.status)">
|
||||
{{ record.statusText || getStatusText(record.status) }}
|
||||
</a-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<!-- 创建时间列模板 -->
|
||||
<template #createdAt="{ record }">
|
||||
<span v-if="record.createdAt">
|
||||
{{ formatDateTime(record.createdAt) }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<!-- 匹配时间列模板 -->
|
||||
<template #matchedAt="{ record }">
|
||||
<span v-if="record.matchedAt">
|
||||
{{ formatDateTime(record.matchedAt) }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<!-- 过期时间列模板 -->
|
||||
<template #expireAt="{ record }">
|
||||
<span v-if="record.expireAt">
|
||||
{{ formatDateTime(record.expireAt) }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import type { Pagination } from '@/types/global';
|
||||
import type { KamiApiCamelOilV1PrefetchOrderListItem } from '@/api/generated/index.ts';
|
||||
import { jdV2PrefetchClient } from '@/api/index.ts';
|
||||
import dayjs from 'dayjs';
|
||||
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
|
||||
|
||||
const { loading, setLoading } = useLoading(false);
|
||||
|
||||
// 订单列表相关状态
|
||||
const basePagination: Pagination = {
|
||||
current: 1,
|
||||
pageSize: 20
|
||||
};
|
||||
const pagination = reactive({
|
||||
...basePagination
|
||||
});
|
||||
|
||||
const ordersRenderData = ref<KamiApiCamelOilV1PrefetchOrderListItem[]>([]);
|
||||
|
||||
const generateOrderFormModel = () => {
|
||||
return {
|
||||
accountName: '',
|
||||
platformOrderNo: '',
|
||||
amount: undefined,
|
||||
status: undefined,
|
||||
dateRange: undefined as Array<string> | undefined
|
||||
};
|
||||
};
|
||||
|
||||
const formModel = ref(generateOrderFormModel());
|
||||
|
||||
const orderColumns: TableColumnData[] = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
width: 80,
|
||||
render: ({ rowIndex }) => {
|
||||
return rowIndex + 1 + (pagination.current - 1) * pagination.pageSize;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '账号名称',
|
||||
dataIndex: 'accountName',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
title: '平台订单号',
|
||||
dataIndex: 'platformOrderNo',
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
title: '订单金额',
|
||||
dataIndex: 'amount',
|
||||
slotName: 'orderAmount',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
slotName: 'orderStatus',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '匹配订单号',
|
||||
dataIndex: 'orderNo',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
slotName: 'createdAt',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
title: '匹配时间',
|
||||
dataIndex: 'matchedAt',
|
||||
slotName: 'matchedAt',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
title: '过期时间',
|
||||
dataIndex: 'expireAt',
|
||||
slotName: 'expireAt',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
title: '失败原因',
|
||||
dataIndex: 'failureReason',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
}
|
||||
];
|
||||
|
||||
const formatDateTime = (dateTime: string | undefined): string => {
|
||||
if (!dateTime) return '-';
|
||||
return dayjs(dateTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
};
|
||||
|
||||
const getStatusText = (status: number): string => {
|
||||
const statusMap: Record<number, string> = {
|
||||
1: '待匹配',
|
||||
2: '已匹配',
|
||||
3: '已过期',
|
||||
4: '已失效'
|
||||
};
|
||||
return statusMap[status] || '未知';
|
||||
};
|
||||
|
||||
const getStatusColor = (status: number): string => {
|
||||
const colorMap: Record<number, string> = {
|
||||
1: 'blue', // 待匹配
|
||||
2: 'green', // 已匹配
|
||||
3: 'orange', // 已过期
|
||||
4: 'red' // 已失效
|
||||
};
|
||||
return colorMap[status] || 'gray';
|
||||
};
|
||||
|
||||
const fetchOrders = async (params: any = { current: 1, pageSize: 20 }) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const requestParams: any = {
|
||||
current: params.current,
|
||||
pageSize: params.pageSize
|
||||
};
|
||||
|
||||
// 添加搜索条件
|
||||
if (formModel.value.accountName) {
|
||||
requestParams.accountName = formModel.value.accountName;
|
||||
}
|
||||
if (formModel.value.platformOrderNo) {
|
||||
requestParams.platformOrderNo = formModel.value.platformOrderNo;
|
||||
}
|
||||
if (formModel.value.amount) {
|
||||
requestParams.amount = formModel.value.amount;
|
||||
}
|
||||
if (formModel.value.status) {
|
||||
requestParams.status = formModel.value.status;
|
||||
}
|
||||
if (formModel.value.dateRange && formModel.value.dateRange.length === 2) {
|
||||
requestParams.dateRange = formModel.value.dateRange;
|
||||
}
|
||||
|
||||
const { data } =
|
||||
await jdV2PrefetchClient.apiJdV2PrefetchOrdersGet(requestParams);
|
||||
|
||||
ordersRenderData.value = data.list || [];
|
||||
pagination.current = params.current;
|
||||
pagination.pageSize = params.pageSize;
|
||||
pagination.total = data.total || 0;
|
||||
} catch (err) {
|
||||
console.error('获取预拉取订单列表失败:', err);
|
||||
Message.error({
|
||||
content: '获取预拉取订单列表失败',
|
||||
closable: true
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onPageChange = (current: number) => {
|
||||
fetchOrders({ ...pagination, current });
|
||||
};
|
||||
|
||||
const onPageSizeChange = (pageSize: number) => {
|
||||
fetchOrders({ ...pagination, pageSize, current: 1 });
|
||||
};
|
||||
|
||||
const searchOrders = () => {
|
||||
fetchOrders({
|
||||
...basePagination
|
||||
});
|
||||
};
|
||||
|
||||
const resetOrders = () => {
|
||||
formModel.value = generateOrderFormModel();
|
||||
searchOrders();
|
||||
};
|
||||
|
||||
// 组件挂载时加载数据
|
||||
fetchOrders();
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.prefetch-orders {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -10,269 +10,14 @@
|
||||
</a-radio-group>
|
||||
</template>
|
||||
|
||||
<!-- 预拉取订单日志内容 -->
|
||||
<div v-show="activeView === 'logs'">
|
||||
<!-- 搜索表单区域 -->
|
||||
<a-row>
|
||||
<a-col :flex="1">
|
||||
<a-form
|
||||
:model="logFormModel"
|
||||
:label-col-props="{ span: 6 }"
|
||||
:wrapper-col-props="{ span: 18 }"
|
||||
label-align="left"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="8">
|
||||
<a-form-item field="startTime" label="开始时间">
|
||||
<a-date-picker
|
||||
v-model="logFormModel.startTime"
|
||||
style="width: 100%"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
show-time
|
||||
placeholder="请选择开始时间"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item field="endTime" label="结束时间">
|
||||
<a-date-picker
|
||||
v-model="logFormModel.endTime"
|
||||
style="width: 100%"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
show-time
|
||||
placeholder="请选择结束时间"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-col>
|
||||
<a-divider style="height: 42px" direction="vertical" />
|
||||
<a-col flex="180px" style="text-align: right">
|
||||
<a-space direction="horizontal" :size="18">
|
||||
<a-button type="primary" @click="searchLogs">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click="resetLogs">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider style="margin-top: 0" />
|
||||
<!-- 预拉取订单日志组件 -->
|
||||
<prefetch-logs
|
||||
v-if="activeView === 'logs'"
|
||||
@showSettings="showSettingsModal"
|
||||
/>
|
||||
|
||||
<!-- 表格操作按钮 -->
|
||||
<div class="table-actions">
|
||||
<a-button @click="showSettingsModal">
|
||||
<template #icon>
|
||||
<icon-settings />
|
||||
</template>
|
||||
设置
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<!-- 日志数据文本区域 -->
|
||||
<div class="log-container">
|
||||
<div class="log-header">
|
||||
<a-space>
|
||||
<a-button size="small" @click="copyLogs">
|
||||
<template #icon>
|
||||
<icon-copy />
|
||||
</template>
|
||||
复制日志
|
||||
</a-button>
|
||||
<a-button size="small" @click="clearLogs">
|
||||
<template #icon>
|
||||
<icon-delete />
|
||||
</template>
|
||||
清空日志
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
<div ref="logContentRef" class="log-content">
|
||||
<div v-if="logsLoading" class="log-loading">
|
||||
<a-spin />
|
||||
<span>加载日志中...</span>
|
||||
</div>
|
||||
<div v-else-if="logsRenderData.length === 0" class="log-empty">
|
||||
暂无日志数据
|
||||
</div>
|
||||
<div v-else class="log-entries">
|
||||
<div
|
||||
v-for="(log, index) in logsRenderData"
|
||||
:key="log.timestamp || index"
|
||||
class="log-entry"
|
||||
>
|
||||
<div class="log-time">
|
||||
{{ formatDateTime(log.timestamp) }}
|
||||
</div>
|
||||
<div class="log-response">
|
||||
<div class="log-response-header">
|
||||
<span>响应数据:</span>
|
||||
</div>
|
||||
<div class="log-response-content">
|
||||
{{ log.responseData || '无响应数据' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 预拉取订单列表内容 -->
|
||||
<div v-show="activeView === 'orders'">
|
||||
<!-- 搜索表单区域 -->
|
||||
<a-row>
|
||||
<a-col :flex="1">
|
||||
<a-form
|
||||
:model="orderFormModel"
|
||||
:label-col-props="{ span: 6 }"
|
||||
:wrapper-col-props="{ span: 18 }"
|
||||
label-align="left"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="6">
|
||||
<a-form-item field="accountName" label="账号名称">
|
||||
<a-input
|
||||
v-model="orderFormModel.accountName"
|
||||
placeholder="请输入账号名称"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item field="platformOrderNo" label="平台订单号">
|
||||
<a-input
|
||||
v-model="orderFormModel.platformOrderNo"
|
||||
placeholder="请输入平台订单号"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item field="amount" label="订单金额">
|
||||
<a-input-number
|
||||
v-model="orderFormModel.amount"
|
||||
placeholder="请输入订单金额"
|
||||
style="width: 100%"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item field="status" label="状态">
|
||||
<a-select
|
||||
v-model="orderFormModel.status"
|
||||
placeholder="请选择状态"
|
||||
allow-clear
|
||||
>
|
||||
<a-option :value="1">待匹配</a-option>
|
||||
<a-option :value="2">已匹配</a-option>
|
||||
<a-option :value="3">已过期</a-option>
|
||||
<a-option :value="4">已失效</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="8">
|
||||
<a-form-item field="dateRange" label="创建时间">
|
||||
<a-range-picker
|
||||
v-model="orderFormModel.dateRange"
|
||||
style="width: 100%"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
:placeholder="['开始日期', '结束日期']"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-col>
|
||||
<a-divider style="height: 42px" direction="vertical" />
|
||||
<a-col flex="180px" style="text-align: right">
|
||||
<a-space direction="horizontal" :size="18">
|
||||
<a-button type="primary" @click="searchOrders">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click="resetOrders">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider style="margin-top: 0" />
|
||||
|
||||
<!-- 订单数据表格区域 -->
|
||||
<a-table
|
||||
:loading="ordersLoading"
|
||||
:data="ordersRenderData"
|
||||
:columns="orderColumns"
|
||||
:scroll="{ x: 1600 }"
|
||||
:pagination="{
|
||||
current: ordersPagination.current,
|
||||
pageSize: ordersPagination.pageSize,
|
||||
total: ordersPagination.total,
|
||||
pageSizeOptions: [10, 20, 50, 100],
|
||||
showPageSize: true
|
||||
}"
|
||||
row-key="id"
|
||||
@page-change="onOrdersPageChange"
|
||||
@page-size-change="onOrdersPageSizeChange"
|
||||
>
|
||||
<!-- 订单金额列模板 -->
|
||||
<template #orderAmount="{ record }">
|
||||
<span v-if="record.amount">¥{{ record.amount.toFixed(2) }}</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<!-- 状态列模板 -->
|
||||
<template #orderStatus="{ record }">
|
||||
<a-tag v-if="record.status" :color="getStatusColor(record.status)">
|
||||
{{ record.statusText || getStatusText(record.status) }}
|
||||
</a-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<!-- 创建时间列模板 -->
|
||||
<template #createdAt="{ record }">
|
||||
<span v-if="record.createdAt">
|
||||
{{ formatDateTime(record.createdAt) }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<!-- 匹配时间列模板 -->
|
||||
<template #matchedAt="{ record }">
|
||||
<span v-if="record.matchedAt">
|
||||
{{ formatDateTime(record.matchedAt) }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<!-- 过期时间列模板 -->
|
||||
<template #expireAt="{ record }">
|
||||
<span v-if="record.expireAt">
|
||||
{{ formatDateTime(record.expireAt) }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
<!-- 预拉取订单列表组件 -->
|
||||
<prefetch-orders v-else />
|
||||
</a-card>
|
||||
|
||||
<!-- 设置配置弹窗 -->
|
||||
@@ -289,17 +34,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { Pagination } from '@/types/global';
|
||||
import { onMounted, reactive, ref, computed, watch } from 'vue';
|
||||
import { Notification, Message } from '@arco-design/web-vue';
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
import SettingsForm from './components/settings-form.vue';
|
||||
import type {
|
||||
KamiApiCamelOilV1PrefetchOrderLogItem,
|
||||
KamiApiCamelOilV1PrefetchOrderListItem
|
||||
} from '@/api/generated/index.ts';
|
||||
import { jdV2PrefetchClient } from '@/api/index.ts';
|
||||
import dayjs from 'dayjs';
|
||||
import PrefetchLogs from './components/prefetch-logs.vue';
|
||||
import PrefetchOrders from './components/prefetch-orders.vue';
|
||||
|
||||
// 当前活跃视图
|
||||
const activeView = ref('logs');
|
||||
@@ -309,309 +47,13 @@ const cardTitle = computed(() => {
|
||||
return activeView.value === 'logs' ? '预拉取订单日志' : '预拉取订单列表';
|
||||
});
|
||||
|
||||
// 订单列表相关状态
|
||||
const baseOrdersPagination: Pagination = {
|
||||
current: 1,
|
||||
pageSize: 20
|
||||
};
|
||||
const ordersPagination = reactive({
|
||||
...baseOrdersPagination
|
||||
});
|
||||
|
||||
const generateLogFormModel = () => {
|
||||
const now = dayjs();
|
||||
return {
|
||||
startTime: now.subtract(1, 'day').toDate(),
|
||||
endTime: now.toDate()
|
||||
};
|
||||
};
|
||||
|
||||
const { loading: logsLoading, setLoading: setLogsLoading } = useLoading(false);
|
||||
const logsRenderData = ref<KamiApiCamelOilV1PrefetchOrderLogItem[]>([]);
|
||||
const logFormModel = ref(generateLogFormModel());
|
||||
|
||||
const { loading: ordersLoading, setLoading: setOrdersLoading } =
|
||||
useLoading(false);
|
||||
const ordersRenderData = ref<KamiApiCamelOilV1PrefetchOrderListItem[]>([]);
|
||||
|
||||
const generateOrderFormModel = () => {
|
||||
return {
|
||||
accountName: '',
|
||||
platformOrderNo: '',
|
||||
amount: undefined,
|
||||
status: undefined,
|
||||
dateRange: undefined as Array<string> | undefined
|
||||
};
|
||||
};
|
||||
|
||||
const orderFormModel = ref(generateOrderFormModel());
|
||||
|
||||
const orderColumns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
width: 80,
|
||||
render: ({ rowIndex }) => {
|
||||
return (
|
||||
rowIndex +
|
||||
1 +
|
||||
(ordersPagination.current - 1) * ordersPagination.pageSize
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '账号名称',
|
||||
dataIndex: 'accountName',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
title: '平台订单号',
|
||||
dataIndex: 'platformOrderNo',
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
title: '订单金额',
|
||||
dataIndex: 'amount',
|
||||
slotName: 'orderAmount',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
slotName: 'orderStatus',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '匹配订单号',
|
||||
dataIndex: 'orderNo',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
slotName: 'createdAt',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
title: '匹配时间',
|
||||
dataIndex: 'matchedAt',
|
||||
slotName: 'matchedAt',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
title: '过期时间',
|
||||
dataIndex: 'expireAt',
|
||||
slotName: 'expireAt',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
title: '失败原因',
|
||||
dataIndex: 'failureReason',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
}
|
||||
];
|
||||
|
||||
const state = reactive({
|
||||
settingsModalVisible: false
|
||||
});
|
||||
|
||||
// 日志相关方法
|
||||
const fetchLogs = async () => {
|
||||
if (!logFormModel.value.startTime || !logFormModel.value.endTime) {
|
||||
Notification.warning({
|
||||
content: '请选择开始时间和结束时间',
|
||||
closable: true
|
||||
});
|
||||
setLogsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setLogsLoading(true);
|
||||
try {
|
||||
const { data } = await jdV2PrefetchClient.apiJdV2PrefetchLogsGet({
|
||||
startTime: dayjs(logFormModel.value.startTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss'
|
||||
),
|
||||
endTime: dayjs(logFormModel.value.endTime).format('YYYY-MM-DD HH:mm:ss')
|
||||
});
|
||||
|
||||
// 直接使用API返回的全部日志数据
|
||||
logsRenderData.value = data.logs || [];
|
||||
} catch (err) {
|
||||
console.error('获取预拉取订单日志失败:', err);
|
||||
Notification.error({
|
||||
content: '获取预拉取订单日志失败',
|
||||
closable: true
|
||||
});
|
||||
} finally {
|
||||
setLogsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const searchLogs = () => {
|
||||
fetchLogs();
|
||||
};
|
||||
|
||||
const resetLogs = () => {
|
||||
logFormModel.value = generateLogFormModel();
|
||||
searchLogs();
|
||||
};
|
||||
|
||||
const copyLogs = async () => {
|
||||
try {
|
||||
const logText = logsRenderData.value
|
||||
.map(log => {
|
||||
const time = formatDateTime(log.timestamp);
|
||||
const data = log.responseData || '无响应数据';
|
||||
return `[${time}] ${data}`;
|
||||
})
|
||||
.join('\n\n');
|
||||
|
||||
await navigator.clipboard.writeText(logText);
|
||||
Message.success({
|
||||
content: '日志复制成功',
|
||||
duration: 2000
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('复制日志失败:', err);
|
||||
Message.error({
|
||||
content: '复制日志失败',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const clearLogs = () => {
|
||||
logsRenderData.value = [];
|
||||
Message.info({
|
||||
content: '日志已清空',
|
||||
duration: 2000
|
||||
});
|
||||
};
|
||||
|
||||
const showSettingsModal = () => {
|
||||
state.settingsModalVisible = true;
|
||||
};
|
||||
|
||||
const formatDateTime = (dateTime: string | undefined): string => {
|
||||
if (!dateTime) return '-';
|
||||
return dayjs(dateTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
};
|
||||
|
||||
// 订单列表相关方法
|
||||
const fetchOrders = async (params: any = { current: 1, pageSize: 20 }) => {
|
||||
setOrdersLoading(true);
|
||||
try {
|
||||
const requestParams: any = {
|
||||
current: params.current,
|
||||
pageSize: params.pageSize
|
||||
};
|
||||
|
||||
// 添加搜索条件
|
||||
if (orderFormModel.value.accountName) {
|
||||
requestParams.accountName = orderFormModel.value.accountName;
|
||||
}
|
||||
if (orderFormModel.value.platformOrderNo) {
|
||||
requestParams.platformOrderNo = orderFormModel.value.platformOrderNo;
|
||||
}
|
||||
if (orderFormModel.value.amount) {
|
||||
requestParams.amount = orderFormModel.value.amount;
|
||||
}
|
||||
if (orderFormModel.value.status) {
|
||||
requestParams.status = orderFormModel.value.status;
|
||||
}
|
||||
if (
|
||||
orderFormModel.value.dateRange &&
|
||||
orderFormModel.value.dateRange.length === 2
|
||||
) {
|
||||
requestParams.dateRange = orderFormModel.value.dateRange;
|
||||
}
|
||||
|
||||
const { data } =
|
||||
await jdV2PrefetchClient.apiJdV2PrefetchOrdersGet(requestParams);
|
||||
|
||||
ordersRenderData.value = data.list || [];
|
||||
ordersPagination.current = params.current;
|
||||
ordersPagination.pageSize = params.pageSize;
|
||||
ordersPagination.total = data.total || 0;
|
||||
} catch (err) {
|
||||
console.error('获取预拉取订单列表失败:', err);
|
||||
Notification.error({
|
||||
content: '获取预拉取订单列表失败',
|
||||
closable: true
|
||||
});
|
||||
} finally {
|
||||
setOrdersLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onOrdersPageChange = (current: number) => {
|
||||
fetchOrders({ ...ordersPagination, current });
|
||||
};
|
||||
|
||||
const onOrdersPageSizeChange = (pageSize: number) => {
|
||||
fetchOrders({ ...ordersPagination, pageSize, current: 1 });
|
||||
};
|
||||
|
||||
const searchOrders = () => {
|
||||
fetchOrders({
|
||||
...baseOrdersPagination
|
||||
});
|
||||
};
|
||||
|
||||
const resetOrders = () => {
|
||||
orderFormModel.value = generateOrderFormModel();
|
||||
searchOrders();
|
||||
};
|
||||
|
||||
// 状态相关方法
|
||||
const getStatusText = (status: number): string => {
|
||||
const statusMap: Record<number, string> = {
|
||||
1: '待匹配',
|
||||
2: '已匹配',
|
||||
3: '已过期',
|
||||
4: '已失效'
|
||||
};
|
||||
return statusMap[status] || '未知';
|
||||
};
|
||||
|
||||
const getStatusColor = (status: number): string => {
|
||||
const colorMap: Record<number, string> = {
|
||||
1: 'blue', // 待匹配
|
||||
2: 'green', // 已匹配
|
||||
3: 'orange', // 已过期
|
||||
4: 'red' // 已失效
|
||||
};
|
||||
return colorMap[status] || 'gray';
|
||||
};
|
||||
|
||||
// 视图切换处理
|
||||
watch(activeView, newValue => {
|
||||
if (newValue === 'orders' && ordersRenderData.value.length === 0) {
|
||||
// 首次切换到订单列表视图时加载数据
|
||||
fetchOrders();
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// 页面加载时默认加载日志数据
|
||||
fetchLogs();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -622,90 +64,4 @@ onMounted(() => {
|
||||
.general-card {
|
||||
min-height: calc(100vh - 200px);
|
||||
}
|
||||
|
||||
.table-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 日志容器样式 */
|
||||
.log-container {
|
||||
border: 1px solid var(--color-border-2);
|
||||
border-radius: var(--border-radius-medium);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.log-header {
|
||||
padding: 12px 16px;
|
||||
background-color: var(--color-fill-1);
|
||||
border-bottom: 1px solid var(--color-border-2);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.log-content {
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
background-color: var(--color-bg-2);
|
||||
}
|
||||
|
||||
.log-loading,
|
||||
.log-empty {
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
color: var(--color-text-3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.log-entries {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.log-entry {
|
||||
margin-bottom: 16px;
|
||||
padding: 12px;
|
||||
background-color: var(--color-bg-1);
|
||||
border: 1px solid var(--color-border-2);
|
||||
border-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
.log-entry:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.log-time {
|
||||
font-size: 12px;
|
||||
color: var(--color-text-3);
|
||||
margin-bottom: 8px;
|
||||
font-family: Monaco, Menlo, 'Ubuntu Mono', monospace;
|
||||
}
|
||||
|
||||
.log-response-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.log-response-header span {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
|
||||
.log-response-content {
|
||||
font-size: 12px;
|
||||
color: var(--color-text-2);
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
background-color: var(--color-fill-1);
|
||||
padding: 8px;
|
||||
border-radius: var(--border-radius-small);
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user