This commit is contained in:
2025-11-07 14:40:47 +08:00
parent a411e42094
commit 9672e191e1
4 changed files with 1199 additions and 169 deletions

View File

@@ -1,188 +1,224 @@
<template>
<el-dialog
title="H-TF订单自动写入配置"
:visible.sync="visible"
width="600px"
width="900px"
:close-on-click-modal="false"
@close="handleClose"
top="5vh"
>
<!-- 配置状态 -->
<el-alert
v-if="config.isConfigured"
title="配置已完成"
type="success"
:description="config.hint"
show-icon
:closable="false"
style="margin-bottom: 20px;"
/>
<el-alert
v-else
title="配置未完成"
type="warning"
:description="config.hint"
show-icon
:closable="false"
style="margin-bottom: 20px;"
/>
<!-- 自定义标题 -->
<div slot="title" class="dialog-title">
<i class="el-icon-setting"></i>
<span>H-TF订单自动写入配置</span>
<el-tag v-if="config.isConfigured" type="success" size="mini" style="margin-left: 10px;">
<i class="el-icon-success"></i> 已配置
</el-tag>
<el-tag v-else type="warning" size="mini" style="margin-left: 10px;">
<i class="el-icon-warning"></i> 未配置
</el-tag>
</div>
<!-- 授权状态 -->
<el-card shadow="never" style="margin-bottom: 20px;">
<div slot="header">
<span>授权状态</span>
</div>
<el-form label-width="120px">
<el-form-item label="授权状态:">
<el-tag v-if="config.hasAccessToken" type="success">{{ config.accessTokenStatus }}</el-tag>
<el-tag v-else type="danger">{{ config.accessTokenStatus }}</el-tag>
<el-button
v-if="!config.hasAccessToken"
type="primary"
size="mini"
style="margin-left: 10px;"
@click="handleAuth"
>
立即授权
</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 文档配置 -->
<el-card shadow="never">
<div slot="header">
<span>目标文档配置</span>
</div>
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-form-item label="文件ID" prop="fileId">
<el-input
v-model="form.fileId"
placeholder="请输入腾讯文档的文件ID"
clearable
>
<div class="config-container">
<!-- 左侧配置表单 -->
<div class="config-left">
<!-- 授权状态 -->
<div class="config-section">
<div class="section-header">
<i class="el-icon-key"></i>
<span>授权状态</span>
</div>
<div class="auth-status">
<el-tag v-if="config.hasAccessToken" type="success" size="medium">
<i class="el-icon-circle-check"></i> {{ config.accessTokenStatus }}
</el-tag>
<el-tag v-else type="danger" size="medium">
<i class="el-icon-circle-close"></i> {{ config.accessTokenStatus }}
</el-tag>
<el-button
slot="append"
icon="el-icon-search"
@click="handleFetchSheets"
:disabled="!form.fileId"
v-if="!config.hasAccessToken"
type="primary"
size="small"
icon="el-icon-unlock"
@click="handleAuth"
>
获取工作表
立即授权
</el-button>
</el-input>
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
例如DUW50RUprWXh2TGJK从腾讯文档URL中获取
</div>
</el-form-item>
</div>
<el-form-item label="工作表ID" prop="sheetId">
<el-select
v-if="sheetList.length > 0"
v-model="form.sheetId"
placeholder="请选择工作表"
style="width: 100%;"
clearable
>
<el-option
v-for="sheet in sheetList"
:key="sheet.sheetId"
:label="sheet.title"
:value="sheet.sheetId"
/>
</el-select>
<el-input
v-else
v-model="form.sheetId"
placeholder="请输入工作表ID或点击'获取工作表'按钮选择"
clearable
/>
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
例如BB08J2
<!-- 文档配置表单 -->
<div class="config-section">
<div class="section-header">
<i class="el-icon-document"></i>
<span>目标文档</span>
</div>
</el-form-item>
<el-form ref="form" :model="form" :rules="rules" label-width="100px" size="small">
<el-form-item label="文件ID" prop="fileId">
<el-input
v-model="form.fileId"
placeholder="例如DUW50RUprWXh2TGJK"
clearable
>
<el-button
slot="append"
icon="el-icon-search"
@click="handleFetchSheets"
:disabled="!form.fileId"
>
获取工作表
</el-button>
</el-input>
</el-form-item>
<el-form-item label="表头行号:" prop="headerRow">
<el-input-number
v-model="form.headerRow"
:min="1"
placeholder="表头所在的行号"
style="width: 100%;"
/>
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
<i class="el-icon-info"></i>
表头所在的行包含"单号""物流单号"等列名默认为2
</div>
</el-form-item>
<el-form-item label="工作表ID" prop="sheetId">
<el-select
v-if="sheetList.length > 0"
v-model="form.sheetId"
placeholder="请选择工作表"
style="width: 100%;"
clearable
>
<el-option
v-for="sheet in sheetList"
:key="sheet.sheetId"
:label="sheet.title"
:value="sheet.sheetId"
>
<span style="float: left">{{ sheet.title }}</span>
<span style="float: right; color: #8492a6; font-size: 12px;">{{ sheet.sheetId }}</span>
</el-option>
</el-select>
<el-input
v-else
v-model="form.sheetId"
placeholder="例如BB08J2"
clearable
/>
</el-form-item>
<el-form-item label="数据起始行:" prop="startRow">
<el-input-number
v-model="form.startRow"
:min="1"
placeholder="数据从第几行开始"
style="width: 100%;"
/>
<div style="font-size: 12px; color: #909399; margin-top: 5px;">
<i class="el-icon-info"></i>
数据从第几行开始默认为3表示第3行是第一条数据
</div>
</el-form-item>
</el-form>
</el-card>
<!-- 同步进度显示 -->
<el-card v-if="config.progressHint" shadow="never" style="margin-top: 15px;">
<div slot="header" style="display: flex; align-items: center;">
<i class="el-icon-data-line" style="margin-right: 8px;"></i>
<span>同步进度</span>
<el-row :gutter="10">
<el-col :span="12">
<el-form-item label="表头行号" prop="headerRow">
<el-input-number
v-model="form.headerRow"
:min="1"
controls-position="right"
style="width: 100%;"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="起始行号" prop="startRow">
<el-input-number
v-model="form.startRow"
:min="1"
controls-position="right"
style="width: 100%;"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</div>
<el-alert
:title="config.progressHint"
:type="config.currentProgress ? 'success' : 'info'"
:closable="false"
show-icon
>
<template v-if="config.currentProgress">
<div style="margin-top: 10px; font-size: 13px;">
<p style="margin: 5px 0;">
<i class="el-icon-circle-check" style="color: #67c23a;"></i>
当前进度已处理到第 <strong>{{ config.currentProgress }}</strong>
</p>
<p style="margin: 5px 0;">
<i class="el-icon-right"></i>
下次同步
<span v-if="config.currentProgress <= (form.startRow + 49)">
将从第 <strong>{{ form.startRow }}</strong> 行重新开始进度较小
</span>
<span v-else-if="config.currentProgress > (form.startRow + 100)">
将从第 <strong>{{ config.currentProgress - 100 }}</strong> 行开始回溯100行防止遗漏
</span>
<span v-else>
将从第 <strong>{{ form.startRow }}</strong> 行重新开始
</span>
</p>
<p style="margin: 5px 0; color: #909399; font-size: 12px;">
<i class="el-icon-info"></i>
系统会自动回溯检查确保不遗漏数据如需完全重置请点击"清除配置"
</p>
<!-- 右侧状态信息 -->
<div class="config-right">
<!-- 配置状态提示 -->
<div class="status-card">
<div class="status-icon" :class="config.isConfigured ? 'success' : 'warning'">
<i :class="config.isConfigured ? 'el-icon-success' : 'el-icon-warning'"></i>
</div>
</template>
</el-alert>
</el-card>
<div class="status-text">
<div class="status-title">{{ config.isConfigured ? '配置完成' : '配置未完成' }}</div>
<div class="status-desc">{{ config.hint }}</div>
</div>
</div>
<!-- 同步进度 -->
<div v-if="config.progressHint" class="progress-card">
<div class="card-header">
<i class="el-icon-data-line"></i>
<span>同步进度</span>
</div>
<div class="progress-content">
<div v-if="config.currentProgress" class="progress-detail">
<div class="progress-item">
<span class="label">当前进度</span>
<span class="value"> {{ config.currentProgress }} </span>
</div>
<div class="progress-item">
<span class="label">下次同步</span>
<span class="value">
<template v-if="config.currentProgress <= (form.startRow + 49)">
{{ form.startRow }}
</template>
<template v-else-if="config.currentProgress > (form.startRow + 100)">
{{ config.currentProgress - 100 }}
</template>
<template v-else>
{{ form.startRow }}
</template>
</span>
</div>
<div class="progress-hint">
<i class="el-icon-info"></i>
系统自动回溯检查防止遗漏
</div>
</div>
<div v-else class="no-progress">
{{ config.progressHint }}
</div>
</div>
</div>
<!-- 快速帮助 -->
<div class="help-card">
<div class="card-header">
<i class="el-icon-question"></i>
<span>配置说明</span>
</div>
<div class="help-content">
<div class="help-item">
<i class="el-icon-check"></i>
<span>文件ID从腾讯文档URL中获取</span>
</div>
<div class="help-item">
<i class="el-icon-check"></i>
<span>点击"获取工作表"自动加载</span>
</div>
<div class="help-item">
<i class="el-icon-check"></i>
<span>表头行号默认为第2行</span>
</div>
<div class="help-item">
<i class="el-icon-check"></i>
<span>数据起始行默认为第3行</span>
</div>
</div>
</div>
</div>
</div>
<!-- 操作按钮 -->
<div slot="footer">
<el-button @click="showOperationLogs = true" icon="el-icon-document" type="info" plain>
查看操作日志
</el-button>
<el-button @click="handleTest" :loading="testLoading" icon="el-icon-setting">
测试配置
</el-button>
<el-button @click="handleClear" :loading="clearLoading" type="danger" plain>
清除配置
</el-button>
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleSave" :loading="saveLoading">
保存配置
</el-button>
<div slot="footer" class="footer-buttons">
<div class="footer-left">
<el-button @click="showOperationLogs = true" icon="el-icon-document" size="small">
操作日志
</el-button>
<el-button @click="handleTest" :loading="testLoading" icon="el-icon-setting" size="small">
测试配置
</el-button>
</div>
<div class="footer-right">
<el-button @click="handleClear" :loading="clearLoading" type="danger" plain size="small">
清除配置
</el-button>
<el-button @click="handleClose" size="small">取消</el-button>
<el-button type="primary" @click="handleSave" :loading="saveLoading" size="small">
<i class="el-icon-check"></i> 保存配置
</el-button>
</div>
</div>
<!-- 操作日志查看对话框 -->
@@ -450,8 +486,264 @@ export default {
</script>
<style scoped>
.el-card {
border: 1px solid #EBEEF5;
/* 标题样式 */
.dialog-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 500;
}
.dialog-title i {
margin-right: 8px;
font-size: 18px;
}
/* 容器布局 */
.config-container {
display: flex;
gap: 20px;
min-height: 400px;
}
.config-left {
flex: 1;
display: flex;
flex-direction: column;
gap: 15px;
}
.config-right {
width: 300px;
display: flex;
flex-direction: column;
gap: 15px;
}
/* 配置区块 */
.config-section {
background: #f5f7fa;
border-radius: 6px;
padding: 15px;
}
.section-header {
display: flex;
align-items: center;
font-size: 14px;
font-weight: 500;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 2px solid #e4e7ed;
}
.section-header i {
margin-right: 6px;
font-size: 16px;
color: #409eff;
}
/* 授权状态 */
.auth-status {
display: flex;
align-items: center;
gap: 10px;
}
/* 状态卡片 */
.status-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 8px;
padding: 20px;
color: white;
display: flex;
align-items: center;
gap: 15px;
box-shadow: 0 2px 12px rgba(102, 126, 234, 0.3);
}
.status-card.warning {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.status-icon {
width: 48px;
height: 48px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
flex-shrink: 0;
}
.status-icon.success {
background: rgba(103, 194, 58, 0.2);
}
.status-icon.warning {
background: rgba(230, 162, 60, 0.2);
}
.status-text {
flex: 1;
}
.status-title {
font-size: 16px;
font-weight: 500;
margin-bottom: 5px;
}
.status-desc {
font-size: 12px;
opacity: 0.9;
line-height: 1.5;
}
/* 进度卡片 */
.progress-card {
background: white;
border: 1px solid #e4e7ed;
border-radius: 6px;
overflow: hidden;
}
.card-header {
background: #f5f7fa;
padding: 12px 15px;
font-size: 14px;
font-weight: 500;
color: #303133;
display: flex;
align-items: center;
border-bottom: 1px solid #e4e7ed;
}
.card-header i {
margin-right: 6px;
color: #409eff;
}
.progress-content {
padding: 15px;
}
.progress-detail {
display: flex;
flex-direction: column;
gap: 10px;
}
.progress-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
background: #f0f9ff;
border-radius: 4px;
border-left: 3px solid #409eff;
}
.progress-item .label {
font-size: 13px;
color: #606266;
}
.progress-item .value {
font-size: 14px;
font-weight: 500;
color: #303133;
}
.progress-hint {
font-size: 12px;
color: #909399;
padding: 8px 12px;
background: #fef0f0;
border-radius: 4px;
border-left: 3px solid #f56c6c;
display: flex;
align-items: center;
gap: 5px;
}
.no-progress {
font-size: 13px;
color: #909399;
text-align: center;
padding: 10px;
}
/* 帮助卡片 */
.help-card {
background: white;
border: 1px solid #e4e7ed;
border-radius: 6px;
overflow: hidden;
}
.help-content {
padding: 15px;
display: flex;
flex-direction: column;
gap: 10px;
}
.help-item {
display: flex;
align-items: flex-start;
gap: 8px;
font-size: 13px;
color: #606266;
line-height: 1.6;
}
.help-item i {
color: #67c23a;
margin-top: 2px;
flex-shrink: 0;
}
/* 底部按钮 */
.footer-buttons {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 10px;
}
.footer-left,
.footer-right {
display: flex;
gap: 8px;
}
/* 响应式调整 */
@media (max-width: 768px) {
.config-container {
flex-direction: column;
}
.config-right {
width: 100%;
}
}
/* Element UI 覆盖样式 */
.config-section >>> .el-form-item {
margin-bottom: 18px;
}
.config-section >>> .el-form-item__label {
font-weight: 500;
color: #606266;
}
.config-section >>> .el-input-number {
width: 100%;
}
</style>