This commit is contained in:
2025-11-04 23:03:38 +08:00
parent 1a9edf7e1b
commit d7a71931a9
2 changed files with 320 additions and 2 deletions

82
src/api/jarvis/tendoc.js Normal file
View File

@@ -0,0 +1,82 @@
import request from '@/utils/request'
// 获取腾讯文档授权URL
export function getTencentDocAuthUrl() {
return request({
url: '/jarvis/tendoc/authUrl',
method: 'get'
})
}
// OAuth回调获取访问令牌
export function getTencentDocAccessToken(code) {
return request({
url: '/jarvis/tendoc/oauth/callback',
method: 'get',
params: { code }
})
}
// 刷新访问令牌
export function refreshTencentDocToken(data) {
return request({
url: '/jarvis/tendoc/refreshToken',
method: 'post',
data
})
}
// 根据单号填充物流链接
export function fillLogisticsByOrderNo(data) {
return request({
url: '/jarvis/tendoc/fillLogisticsByOrderNo',
method: 'post',
data
})
}
// 追加单个订单物流信息
export function appendLogistics(data) {
return request({
url: '/jarvis/tendoc/appendLogistics',
method: 'post',
data
})
}
// 自动发货
export function autoShip(data) {
return request({
url: '/jarvis/tendoc/autoShip',
method: 'post',
data
})
}
// 读取表格数据
export function readSheetData(params) {
return request({
url: '/jarvis/tendoc/readSheet',
method: 'get',
params
})
}
// 获取文件信息
export function getFileInfo(params) {
return request({
url: '/jarvis/tendoc/fileInfo',
method: 'get',
params
})
}
// 获取工作表列表
export function getSheetList(params) {
return request({
url: '/jarvis/tendoc/sheetList',
method: 'get',
params
})
}

View File

@@ -134,8 +134,11 @@
<el-table-column label="完成时间" prop="finishTime" width="160">
<template slot-scope="scope">{{ parseTime(scope.row.finishTime) }}</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="120">
<el-table-column label="操作" fixed="right" width="180">
<template slot-scope="scope">
<el-button type="text" size="mini" style="color: #409EFF;" @click="handleSyncLogistics(scope.row)">
同步物流
</el-button>
<el-button type="text" size="mini" style="color: #f56c6c;" @click="handleDelete(scope.row)">
删除
</el-button>
@@ -155,11 +158,102 @@
/>
</template>
</list-layout>
<!-- 同步物流对话框 -->
<el-dialog
title="同步物流到腾讯文档"
:visible.sync="syncLogisticsDialogVisible"
width="600px"
:close-on-click-modal="false"
>
<el-form :model="syncLogisticsForm" label-width="140px">
<el-form-item label="访问令牌">
<el-input
v-model="syncLogisticsForm.accessToken"
placeholder="点击下方按钮获取授权"
style="width: 100%"
/>
<el-button
type="primary"
size="small"
style="margin-top: 8px;"
@click="handleAuthorize"
>
获取授权
</el-button>
</el-form-item>
<el-form-item label="文件ID" required>
<el-input
v-model="syncLogisticsForm.fileId"
placeholder="从腾讯文档URL中获取例如Dxxxxxxxxxxxxx"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="工作表ID" required>
<el-input
v-model="syncLogisticsForm.sheetId"
placeholder="从腾讯文档URL中获取例如BB08J2"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="表头行号">
<el-input-number
v-model="syncLogisticsForm.headerRow"
:min="1"
style="width: 100%"
/>
<div style="font-size: 12px; color: #999; margin-top: 4px;">
表头所在行号默认第1行
</div>
</el-form-item>
<el-form-item label="单号列索引(可选)">
<el-input-number
v-model="syncLogisticsForm.orderNoColumn"
:min="0"
style="width: 100%"
placeholder="不填写则自动识别"
/>
<div style="font-size: 12px; color: #999; margin-top: 4px;">
单号列的索引从0开始不填写则自动识别
</div>
</el-form-item>
<el-form-item label="物流链接列索引(可选)">
<el-input-number
v-model="syncLogisticsForm.logisticsLinkColumn"
:min="0"
style="width: 100%"
placeholder="不填写则自动识别"
/>
<div style="font-size: 12px; color: #999; margin-top: 4px;">
物流链接列的索引从0开始不填写则自动识别
</div>
</el-form-item>
<el-form-item label="说明">
<div style="font-size: 12px; color: #666; line-height: 1.6;">
<p>1. 首次使用需要点击"获取授权"按钮完成腾讯文档授权</p>
<p>2. 文件ID和工作表ID可以从腾讯文档URL中获取</p>
<p>3. 系统会自动从上次处理的最大行数-100开始读取避免重复处理历史数据</p>
<p>4. 配置会自动保存下次使用时无需重新填写</p>
</div>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="syncLogisticsDialogVisible = false">取消</el-button>
<el-button
type="primary"
:loading="syncLogisticsLoading"
@click="handleSyncLogisticsSubmit"
>
开始同步
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listJDOrders, updateJDOrder, delJDOrder } from '@/api/system/jdorder'
import { fillLogisticsByOrderNo, getTencentDocAuthUrl, getTencentDocAccessToken } from '@/api/jarvis/tendoc'
import ListLayout from '@/components/ListLayout'
export default {
@@ -189,7 +283,19 @@ export default {
orderBy: 'create_time',
isAsc: 'desc',
hasFinishTime: false
}
},
// 同步物流对话框
syncLogisticsDialogVisible: false,
syncLogisticsLoading: false,
syncLogisticsForm: {
accessToken: '',
fileId: '',
sheetId: '',
headerRow: 1,
orderNoColumn: null,
logisticsLinkColumn: null
},
currentOrder: null
}
},
created() {
@@ -415,6 +521,136 @@ export default {
} finally {
this.loading = false
}
},
/** 同步物流到腾讯文档 */
handleSyncLogistics(row) {
// 检查是否有物流链接
if (!row.logisticsLink || !row.logisticsLink.trim()) {
this.$message.warning('该订单暂无物流链接,无法同步')
return
}
this.currentOrder = row
this.syncLogisticsDialogVisible = true
// 从localStorage获取之前保存的配置
const savedConfig = localStorage.getItem('tendoc_sync_config')
if (savedConfig) {
try {
const config = JSON.parse(savedConfig)
this.syncLogisticsForm = {
...this.syncLogisticsForm,
...config
}
} catch (e) {
console.error('解析保存的配置失败', e)
}
}
// 检查是否有访问令牌,如果没有则引导授权
if (!this.syncLogisticsForm.accessToken) {
this.handleAuthorize()
}
},
/** 腾讯文档授权 */
async handleAuthorize() {
try {
const res = await getTencentDocAuthUrl()
if (res.code === 200 && res.data) {
// 打开授权页面
const authUrl = res.data
this.$message.info('正在打开授权页面,授权完成后请将访问令牌复制到上方输入框')
const width = 600
const height = 700
const left = (window.screen.width - width) / 2
const top = (window.screen.height - height) / 2
window.open(
authUrl,
'腾讯文档授权',
`width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`
)
// 提示用户手动输入访问令牌
this.$prompt('授权完成后请从授权页面复制访问令牌access_token并粘贴到下方', '输入访问令牌', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPlaceholder: '请输入访问令牌',
inputValidator: (value) => {
if (!value || !value.trim()) {
return '访问令牌不能为空'
}
return true
}
}).then(({ value }) => {
this.syncLogisticsForm.accessToken = value.trim()
// 保存配置
localStorage.setItem('tendoc_sync_config', JSON.stringify(this.syncLogisticsForm))
this.$message.success('访问令牌已保存')
}).catch(() => {
// 用户取消
})
} else {
this.$message.error(res.msg || '获取授权URL失败')
}
} catch (e) {
this.$message.error('授权失败,请稍后重试')
console.error('授权失败', e)
}
},
/** 同步物流链接 */
async handleSyncLogisticsSubmit() {
if (!this.syncLogisticsForm.accessToken) {
this.$message.warning('请先完成腾讯文档授权')
return
}
if (!this.syncLogisticsForm.fileId || !this.syncLogisticsForm.sheetId) {
this.$message.warning('请填写文件ID和工作表ID')
return
}
// 保存配置到localStorage
localStorage.setItem('tendoc_sync_config', JSON.stringify(this.syncLogisticsForm))
this.syncLogisticsLoading = true
try {
const params = {
accessToken: this.syncLogisticsForm.accessToken,
fileId: this.syncLogisticsForm.fileId,
sheetId: this.syncLogisticsForm.sheetId,
headerRow: this.syncLogisticsForm.headerRow || 1
}
// 如果指定了列位置,则传递
if (this.syncLogisticsForm.orderNoColumn != null) {
params.orderNoColumn = this.syncLogisticsForm.orderNoColumn
}
if (this.syncLogisticsForm.logisticsLinkColumn != null) {
params.logisticsLinkColumn = this.syncLogisticsForm.logisticsLinkColumn
}
const res = await fillLogisticsByOrderNo(params)
if (res.code === 200) {
const data = res.data || {}
this.$message.success(
`同步成功!成功填充 ${data.filledCount || 0} 条,跳过 ${data.skippedCount || 0} 条,错误 ${data.errorCount || 0}`
)
this.syncLogisticsDialogVisible = false
} else {
this.$message.error(res.msg || '同步失败')
}
} catch (e) {
this.$message.error('同步失败,请稍后重试')
console.error('同步物流失败', e)
} finally {
this.syncLogisticsLoading = false
}
}
}