<template>
|
<el-dialog
|
:model-value="dialogSyncVisible"
|
@update:model-value="$emit('update:dialogSyncVisible', $event)"
|
title="税控平台同步"
|
width="800px"
|
:close-on-click-modal="false"
|
>
|
<div class="sync-container">
|
<!-- 同步状态 -->
|
<el-card class="sync-status" shadow="never">
|
<template #header>
|
<div class="card-header">
|
<span>同步状态</span>
|
</div>
|
</template>
|
|
<div class="status-content">
|
<el-row :gutter="20">
|
<el-col :span="8">
|
<div class="status-item">
|
<div class="status-icon success">
|
<el-icon><Check /></el-icon>
|
</div>
|
<div class="status-text">
|
<div class="status-title">已同步</div>
|
<div class="status-count">{{ syncedCount }}</div>
|
</div>
|
</div>
|
</el-col>
|
<el-col :span="8">
|
<div class="status-item">
|
<div class="status-icon warning">
|
<el-icon><Clock /></el-icon>
|
</div>
|
<div class="status-text">
|
<div class="status-title">待同步</div>
|
<div class="status-count">{{ pendingCount }}</div>
|
</div>
|
</div>
|
</el-col>
|
<el-col :span="8">
|
<div class="status-item">
|
<div class="status-icon danger">
|
<el-icon><Close /></el-icon>
|
</div>
|
<div class="status-text">
|
<div class="status-title">同步失败</div>
|
<div class="status-count">{{ failedCount }}</div>
|
</div>
|
</div>
|
</el-col>
|
</el-row>
|
</div>
|
</el-card>
|
|
<!-- 同步配置 -->
|
<el-card class="sync-config" shadow="never">
|
<template #header>
|
<div class="card-header">
|
<span>同步配置</span>
|
</div>
|
</template>
|
|
<el-form :model="syncConfig" label-width="120px">
|
<el-form-item label="税控平台地址">
|
<el-input
|
v-model="syncConfig.taxControlUrl"
|
placeholder="请输入税控平台地址"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
<el-form-item label="同步频率">
|
<el-select
|
v-model="syncConfig.syncFrequency"
|
placeholder="请选择同步频率"
|
style="width: 100%"
|
>
|
<el-option label="实时同步" value="realtime" />
|
<el-option label="每小时同步" value="hourly" />
|
<el-option label="每天同步" value="daily" />
|
<el-option label="手动同步" value="manual" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="自动重试">
|
<el-switch
|
v-model="syncConfig.autoRetry"
|
active-text="开启"
|
inactive-text="关闭"
|
/>
|
</el-form-item>
|
<el-form-item label="重试次数" v-if="syncConfig.autoRetry">
|
<el-input-number
|
v-model="syncConfig.retryCount"
|
:min="1"
|
:max="10"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-form>
|
</el-card>
|
|
<!-- 同步日志 -->
|
<el-card class="sync-log" shadow="never">
|
<template #header>
|
<div class="card-header">
|
<span>同步日志</span>
|
<el-button type="primary" size="small" @click="refreshLog">
|
刷新日志
|
</el-button>
|
</div>
|
</template>
|
|
<el-table :data="syncLogs" border style="width: 100%" max-height="300">
|
<el-table-column label="时间" prop="time" width="160" />
|
<el-table-column label="操作" prop="action" width="120" />
|
<el-table-column label="状态" prop="status" width="100">
|
<template #default="scope">
|
<el-tag :type="getLogStatusType(scope.row.status)">
|
{{ getLogStatusText(scope.row.status) }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="详情" prop="detail" show-overflow-tooltip />
|
</el-table>
|
</el-card>
|
</div>
|
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button @click="handleClose">取消</el-button>
|
<el-button type="primary" @click="handleSync" :loading="syncLoading">
|
开始同步
|
</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted } from "vue";
|
import { ElMessage } from "element-plus";
|
import { Check, Clock, Close } from "@element-plus/icons-vue";
|
|
// Props
|
const props = defineProps({
|
dialogSyncVisible: {
|
type: Boolean,
|
default: false
|
}
|
});
|
|
// Emits
|
const emit = defineEmits(['update:dialogSyncVisible', 'success']);
|
|
// 响应式数据
|
const syncLoading = ref(false);
|
const syncedCount = ref(15);
|
const pendingCount = ref(8);
|
const failedCount = ref(2);
|
|
// 同步配置
|
const syncConfig = reactive({
|
taxControlUrl: "https://tax-control.example.com/api",
|
syncFrequency: "manual",
|
autoRetry: true,
|
retryCount: 3
|
});
|
|
// 同步日志
|
const syncLogs = ref([
|
{
|
time: "2024-12-01 15:30:00",
|
action: "发票同步",
|
status: "success",
|
detail: "成功同步15张发票到税控平台"
|
},
|
{
|
time: "2024-12-01 15:25:00",
|
action: "发票同步",
|
status: "success",
|
detail: "成功同步8张发票到税控平台"
|
},
|
{
|
time: "2024-12-01 15:20:00",
|
action: "发票同步",
|
status: "failed",
|
detail: "同步失败:网络连接超时"
|
},
|
{
|
time: "2024-12-01 15:15:00",
|
action: "发票同步",
|
status: "success",
|
detail: "成功同步12张发票到税控平台"
|
}
|
]);
|
|
// 获取日志状态类型
|
const getLogStatusType = (status) => {
|
const statusMap = {
|
success: "success",
|
failed: "danger",
|
pending: "warning"
|
};
|
return statusMap[status] || "";
|
};
|
|
// 获取日志状态文本
|
const getLogStatusText = (status) => {
|
const statusMap = {
|
success: "成功",
|
failed: "失败",
|
pending: "进行中"
|
};
|
return statusMap[status] || status;
|
};
|
|
// 刷新日志
|
const refreshLog = () => {
|
ElMessage.success("日志已刷新");
|
};
|
|
// 开始同步
|
const handleSync = async () => {
|
if (!syncConfig.taxControlUrl) {
|
ElMessage.warning("请先配置税控平台地址");
|
return;
|
}
|
|
syncLoading.value = true;
|
|
try {
|
// 模拟同步过程
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
// 更新同步状态
|
const newSynced = Math.min(pendingCount.value, 5);
|
syncedCount.value += newSynced;
|
pendingCount.value -= newSynced;
|
|
// 添加同步日志
|
syncLogs.value.unshift({
|
time: new Date().toLocaleString(),
|
action: "发票同步",
|
status: "success",
|
detail: `成功同步${newSynced}张发票到税控平台`
|
});
|
|
ElMessage.success("同步完成");
|
emit('success');
|
} catch (error) {
|
ElMessage.error("同步失败");
|
failedCount.value++;
|
|
// 添加失败日志
|
syncLogs.value.unshift({
|
time: new Date().toLocaleString(),
|
action: "发票同步",
|
status: "failed",
|
detail: "同步失败:系统错误"
|
});
|
} finally {
|
syncLoading.value = false;
|
}
|
};
|
|
// 关闭对话框
|
const handleClose = () => {
|
emit('update:dialogSyncVisible', false);
|
};
|
|
// 组件挂载时初始化数据
|
onMounted(() => {
|
// 可以在这里加载初始数据
|
});
|
</script>
|
|
<style scoped>
|
.sync-container {
|
padding: 0;
|
}
|
|
.sync-status,
|
.sync-config,
|
.sync-log {
|
margin-bottom: 20px;
|
}
|
|
.sync-status:last-child,
|
.sync-config:last-child,
|
.sync-log:last-child {
|
margin-bottom: 0;
|
}
|
|
.card-header {
|
font-weight: bold;
|
font-size: 16px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
}
|
|
.status-content {
|
padding: 20px 0;
|
}
|
|
.status-item {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
padding: 20px;
|
text-align: center;
|
}
|
|
.status-icon {
|
width: 60px;
|
height: 60px;
|
border-radius: 50%;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
margin-right: 15px;
|
font-size: 24px;
|
color: white;
|
}
|
|
.status-icon.success {
|
background-color: #67c23a;
|
}
|
|
.status-icon.warning {
|
background-color: #e6a23c;
|
}
|
|
.status-icon.danger {
|
background-color: #f56c6c;
|
}
|
|
.status-text {
|
text-align: left;
|
}
|
|
.status-title {
|
font-size: 14px;
|
color: #606266;
|
margin-bottom: 5px;
|
}
|
|
.status-count {
|
font-size: 24px;
|
font-weight: bold;
|
color: #303133;
|
}
|
|
.dialog-footer {
|
text-align: right;
|
}
|
|
.el-table {
|
margin-top: 10px;
|
}
|
</style>
|