This commit is contained in:
Leo
2026-01-14 22:55:39 +08:00
parent b215f34aa8
commit c3d13db31b
2 changed files with 608 additions and 0 deletions

155
src/api/jarvis/wps365.js Normal file
View File

@@ -0,0 +1,155 @@
import request from '@/utils/request'
// ==================== OAuth授权相关 ====================
/**
* 获取WPS365授权URL
*/
export function getWPS365AuthUrl(state) {
return request({
url: '/jarvis/wps365/authUrl',
method: 'get',
params: { state }
})
}
/**
* OAuth回调获取访问令牌
*/
export function getWPS365AccessToken(code) {
return request({
url: '/jarvis/wps365/oauth/callback',
method: 'get',
params: { code }
})
}
/**
* 刷新访问令牌
*/
export function refreshWPS365Token(data) {
return request({
url: '/jarvis/wps365/refreshToken',
method: 'post',
data
})
}
/**
* 获取token状态
*/
export function getWPS365TokenStatus(userId) {
return request({
url: '/jarvis/wps365/tokenStatus',
method: 'get',
params: { userId }
})
}
/**
* 设置token用于手动授权
*/
export function setWPS365Token(data) {
return request({
url: '/jarvis/wps365/setToken',
method: 'post',
data
})
}
// ==================== 用户信息相关 ====================
/**
* 获取用户信息
*/
export function getWPS365UserInfo(userId) {
return request({
url: '/jarvis/wps365/userInfo',
method: 'get',
params: { userId }
})
}
// ==================== 文件相关 ====================
/**
* 获取文件列表
*/
export function getWPS365FileList(params) {
return request({
url: '/jarvis/wps365/files',
method: 'get',
params
})
}
/**
* 获取文件信息
*/
export function getWPS365FileInfo(userId, fileToken) {
return request({
url: '/jarvis/wps365/fileInfo',
method: 'get',
params: { userId, fileToken }
})
}
// ==================== 工作表相关 ====================
/**
* 获取工作表列表
*/
export function getWPS365SheetList(userId, fileToken) {
return request({
url: '/jarvis/wps365/sheets',
method: 'get',
params: { userId, fileToken }
})
}
/**
* 创建数据表
*/
export function createWPS365Sheet(data) {
return request({
url: '/jarvis/wps365/createSheet',
method: 'post',
data
})
}
// ==================== 单元格操作相关 ====================
/**
* 读取单元格数据
*/
export function readWPS365Cells(params) {
return request({
url: '/jarvis/wps365/readCells',
method: 'get',
params
})
}
/**
* 更新单元格数据
*/
export function updateWPS365Cells(data) {
return request({
url: '/jarvis/wps365/updateCells',
method: 'post',
data
})
}
/**
* 批量更新单元格数据
*/
export function batchUpdateWPS365Cells(data) {
return request({
url: '/jarvis/wps365/batchUpdateCells',
method: 'post',
data
})
}

View File

@@ -0,0 +1,453 @@
<template>
<div class="app-container">
<el-card>
<div slot="header" class="clearfix">
<span>WPS365 在线表格管理</span>
<el-button
style="float: right; padding: 3px 0"
type="text"
@click="handleRefresh"
:loading="loading">
刷新
</el-button>
</div>
<!-- 授权状态 -->
<el-alert
v-if="!isAuthorized"
title="未授权"
type="warning"
:closable="false"
show-icon>
<template slot="default">
<span>请先完成WPS365授权才能使用文档编辑功能</span>
<el-button
type="primary"
size="small"
style="margin-left: 10px"
@click="handleAuthorize">
立即授权
</el-button>
</template>
</el-alert>
<el-alert
v-else
title="已授权"
type="success"
:closable="false"
show-icon>
<template slot="default">
<span>授权状态正常</span>
<el-button
type="danger"
size="small"
style="margin-left: 10px"
@click="handleRefreshToken">
刷新Token
</el-button>
</template>
</el-alert>
<!-- 用户信息 -->
<el-card v-if="isAuthorized && userInfo" style="margin-top: 20px">
<div slot="header">用户信息</div>
<el-descriptions :column="2" border>
<el-descriptions-item label="用户ID">{{ userInfo.user_id || '-' }}</el-descriptions-item>
<el-descriptions-item label="用户名">{{ userInfo.name || '-' }}</el-descriptions-item>
<el-descriptions-item label="邮箱">{{ userInfo.email || '-' }}</el-descriptions-item>
</el-descriptions>
</el-card>
<!-- 文件列表 -->
<el-card v-if="isAuthorized" style="margin-top: 20px">
<div slot="header">
<span>文件列表</span>
<el-button
type="primary"
size="small"
style="float: right"
@click="handleLoadFiles">
加载文件
</el-button>
</div>
<el-table
v-loading="fileListLoading"
:data="fileList"
border
style="width: 100%">
<el-table-column prop="file_name" label="文件名" width="200" />
<el-table-column prop="file_token" label="文件Token" width="250" />
<el-table-column prop="file_type" label="类型" width="100" />
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-button
type="primary"
size="mini"
@click="handleViewFile(scope.row)">
查看
</el-button>
<el-button
type="success"
size="mini"
@click="handleEditFile(scope.row)">
编辑
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="fileTotal > 0"
:total="fileTotal"
:page.sync="queryParams.page"
:limit.sync="queryParams.pageSize"
@pagination="handleLoadFiles"
/>
</el-card>
<!-- 编辑对话框 -->
<el-dialog
title="编辑表格"
:visible.sync="editDialogVisible"
width="80%"
:close-on-click-modal="false">
<div v-if="currentFile">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="工作表">
<el-select v-model="currentSheetIdx" placeholder="请选择工作表" @change="handleLoadSheetData">
<el-option
v-for="(sheet, index) in sheetList"
:key="index"
:label="sheet.name"
:value="index">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="单元格范围">
<el-input
v-model="cellRange"
placeholder="例如A1:B10"
style="width: 200px">
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleLoadSheetData">读取数据</el-button>
<el-button type="success" @click="handleUpdateCells">保存数据</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="sheetDataLoading"
:data="sheetData"
border
style="width: 100%; margin-top: 20px">
<el-table-column
v-for="(col, index) in sheetColumns"
:key="index"
:prop="'col' + index"
:label="getColumnLabel(index)"
min-width="120">
<template slot-scope="scope">
<el-input
v-model="scope.row['col' + index]"
size="small">
</el-input>
</template>
</el-table-column>
</el-table>
</div>
</el-dialog>
</el-card>
</div>
</template>
<script>
import {
getWPS365AuthUrl,
getWPS365TokenStatus,
getWPS365UserInfo,
getWPS365FileList,
getWPS365SheetList,
readWPS365Cells,
updateWPS365Cells,
refreshWPS365Token
} from '@/api/jarvis/wps365'
export default {
name: 'WPS365',
data() {
return {
loading: false,
isAuthorized: false,
userInfo: null,
userId: '', // 这里应该从登录用户获取,暂时使用配置
// 文件列表
fileList: [],
fileListLoading: false,
fileTotal: 0,
queryParams: {
page: 1,
pageSize: 20
},
// 编辑对话框
editDialogVisible: false,
currentFile: null,
currentSheetIdx: 0,
sheetList: [],
sheetData: [],
sheetDataLoading: false,
cellRange: 'A1:Z100',
sheetColumns: []
}
},
created() {
// 初始化时检查授权状态
// TODO: 从当前登录用户获取userId
this.userId = 'default_user' // 临时值需要替换为实际用户ID
this.checkAuthStatus()
},
methods: {
/**
* 检查授权状态
*/
async checkAuthStatus() {
try {
const response = await getWPS365TokenStatus(this.userId)
if (response.code === 200) {
this.isAuthorized = response.data.hasToken && response.data.isValid
if (this.isAuthorized) {
this.loadUserInfo()
}
}
} catch (error) {
console.error('检查授权状态失败', error)
}
},
/**
* 加载用户信息
*/
async loadUserInfo() {
try {
const response = await getWPS365UserInfo(this.userId)
if (response.code === 200) {
this.userInfo = response.data
}
} catch (error) {
console.error('加载用户信息失败', error)
}
},
/**
* 处理授权
*/
async handleAuthorize() {
try {
const response = await getWPS365AuthUrl()
if (response.code === 200) {
// 在新窗口打开授权页面
window.open(response.data, '_blank')
this.$message.success('请在新窗口中完成授权,授权完成后刷新此页面')
}
} catch (error) {
this.$message.error('获取授权URL失败' + (error.msg || error.message))
}
},
/**
* 刷新Token
*/
async handleRefreshToken() {
try {
// TODO: 从存储中获取refreshToken
const response = await refreshWPS365Token({
refreshToken: '' // 需要从存储中获取
})
if (response.code === 200) {
this.$message.success('Token刷新成功')
this.checkAuthStatus()
}
} catch (error) {
this.$message.error('刷新Token失败' + (error.msg || error.message))
}
},
/**
* 刷新
*/
handleRefresh() {
this.checkAuthStatus()
if (this.isAuthorized) {
this.handleLoadFiles()
}
},
/**
* 加载文件列表
*/
async handleLoadFiles() {
if (!this.isAuthorized) {
this.$message.warning('请先完成授权')
return
}
this.fileListLoading = true
try {
const response = await getWPS365FileList({
userId: this.userId,
page: this.queryParams.page,
pageSize: this.queryParams.pageSize
})
if (response.code === 200) {
this.fileList = response.data.files || []
this.fileTotal = response.data.total || 0
}
} catch (error) {
this.$message.error('加载文件列表失败:' + (error.msg || error.message))
} finally {
this.fileListLoading = false
}
},
/**
* 查看文件
*/
handleViewFile(file) {
this.$message.info('查看文件功能开发中')
},
/**
* 编辑文件
*/
async handleEditFile(file) {
this.currentFile = file
this.editDialogVisible = true
// 加载工作表列表
try {
const response = await getWPS365SheetList(this.userId, file.file_token)
if (response.code === 200) {
this.sheetList = response.data.sheets || []
if (this.sheetList.length > 0) {
this.currentSheetIdx = 0
this.handleLoadSheetData()
}
}
} catch (error) {
this.$message.error('加载工作表列表失败:' + (error.msg || error.message))
}
},
/**
* 加载工作表数据
*/
async handleLoadSheetData() {
if (!this.currentFile) {
return
}
this.sheetDataLoading = true
try {
const response = await readWPS365Cells({
userId: this.userId,
fileToken: this.currentFile.file_token,
sheetIdx: this.currentSheetIdx,
range: this.cellRange
})
if (response.code === 200) {
const values = response.data.values || []
this.processSheetData(values)
}
} catch (error) {
this.$message.error('加载工作表数据失败:' + (error.msg || error.message))
} finally {
this.sheetDataLoading = false
}
},
/**
* 处理工作表数据
*/
processSheetData(values) {
if (!values || values.length === 0) {
this.sheetData = []
this.sheetColumns = []
return
}
// 确定最大列数
const maxCols = Math.max(...values.map(row => row.length))
this.sheetColumns = Array.from({ length: maxCols }, (_, i) => i)
// 转换为表格数据格式
this.sheetData = values.map(row => {
const rowData = {}
row.forEach((cell, index) => {
rowData['col' + index] = cell !== null && cell !== undefined ? String(cell) : ''
})
// 填充空列
for (let i = row.length; i < maxCols; i++) {
rowData['col' + i] = ''
}
return rowData
})
},
/**
* 获取列标签
*/
getColumnLabel(index) {
let label = ''
let num = index
while (num >= 0) {
label = String.fromCharCode(65 + (num % 26)) + label
num = Math.floor(num / 26) - 1
}
return label
},
/**
* 更新单元格数据
*/
async handleUpdateCells() {
if (!this.currentFile) {
return
}
// 转换表格数据为二维数组
const values = this.sheetData.map(row => {
return this.sheetColumns.map(colIndex => {
const value = row['col' + colIndex]
return value !== undefined ? value : ''
})
})
try {
const response = await updateWPS365Cells({
userId: this.userId,
fileToken: this.currentFile.file_token,
sheetIdx: this.currentSheetIdx,
range: this.cellRange,
values: values
})
if (response.code === 200) {
this.$message.success('更新成功')
}
} catch (error) {
this.$message.error('更新失败:' + (error.msg || error.message))
}
}
}
}
</script>
<style scoped>
.app-container {
padding: 20px;
}
</style>