Просмотр исходного кода

腾讯在线文档-表格接入

lk 2 дней назад
Родитель
Сommit
7bcbba5b56

+ 45 - 0
fs-admin/src/main/java/com/fs/third/controller/TencentWordOpenApiController.java

@@ -0,0 +1,45 @@
+package com.fs.third.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.spring.SpringUtils;
+import com.fs.third.service.ITencentWordService;
+import okhttp3.Request;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.web.bind.annotation.*;
+
+
+import static com.fs.framework.datasource.DynamicDataSourceContextHolder.log;
+
+@RestController
+@RequestMapping("/third/tencentWord")
+public class TencentWordOpenApiController extends BaseController {
+    @Autowired
+    private RedisTemplate redisTemplate;
+    @Autowired
+    private ITencentWordService tencentWordService;
+
+    @PostMapping("/createFile")
+    public R createFile(@RequestBody String title) {
+        return tencentWordService.createFile(title);
+    }
+
+    @GetMapping("/getFiles")
+    public R getFiles() {
+        return R.ok().put("data",tencentWordService.getFiles());
+    }
+
+    @GetMapping("/synchronization/{fileId}")
+    public R synchronization(@PathVariable String fileId) {
+        tencentWordService.synchronization(fileId);
+        return R.ok();
+    }
+
+    @GetMapping("/authorizeCallback")
+    public void authorizeCallback(Request request) {
+//        redisTemplate.opsForSet()
+        log.error("授权回调 | request={}", request);
+    }
+}

+ 2 - 1
fs-service/src/main/java/com/fs/hisStore/enums/SysConfigEnum.java

@@ -89,7 +89,8 @@ public enum SysConfigEnum {
     //商城支付配置,store.pay
     STORE_PAY_CONFIG("store.pay", "商城支付配置"),
     //声纹复刻配置,vc.config
-    VS_CONFIG("vc.config", "声纹复刻配置");
+    VS_CONFIG("vc.config", "声纹复刻配置"),
+    TENCENT_WORD("tencent.sheetOnlineConfig", "腾讯在线表格配置");
     private final String key;
     private final String name;
 

+ 32 - 0
fs-service/src/main/java/com/fs/third/domain/TencentWord.java

@@ -0,0 +1,32 @@
+package com.fs.third.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+public class TencentWord extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @Excel(name = "标题")
+    private String title;
+
+    @Excel(name = "类型")
+    private String type;
+
+    @Excel(name = "模板版本")
+    private String templateVersion;
+
+    @Excel(name = "文档URL")
+    private String url;
+
+    @Excel(name = "文件ID")
+    private String fileId;
+
+}

+ 29 - 0
fs-service/src/main/java/com/fs/third/domain/TencentWordDetail.java

@@ -0,0 +1,29 @@
+package com.fs.third.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+public class TencentWordDetail extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @Excel(name = "文件ID")
+    private String fileId;
+
+    @Excel(name = "工作表ID")
+    private String sheetId;
+
+    @Excel(name = "问题")
+    private String q;
+
+    @Excel(name = "答案")
+    private String a;
+
+}

+ 38 - 0
fs-service/src/main/java/com/fs/third/domain/TencentWordSheet.java

@@ -0,0 +1,38 @@
+package com.fs.third.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+public class TencentWordSheet extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @Excel(name = "文件ID")
+    private String fileId;
+
+    @Excel(name = "工作表ID")
+    private String sheetId;
+
+    @Excel(name = "工作表标题")
+    private String title;
+
+    @Excel(name = "行数")
+    private Integer rowCount;
+
+    @Excel(name = "列数")
+    private Integer columnCount;
+
+    @Excel(name = "总行数")
+    private Integer rowTotal;
+
+    @Excel(name = "总列数")
+    private Integer columnTotal;
+
+}

+ 16 - 0
fs-service/src/main/java/com/fs/third/mapper/TencentWordDetailMapper.java

@@ -0,0 +1,16 @@
+package com.fs.third.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.third.domain.TencentWordDetail;
+
+import java.util.ArrayList;
+
+/**
+ * 腾讯文档详情Mapper接口
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+public interface TencentWordDetailMapper extends BaseMapper<TencentWordDetail> {
+    void updateBatchById(ArrayList<TencentWordDetail> updates);
+}

+ 13 - 0
fs-service/src/main/java/com/fs/third/mapper/TencentWordMapper.java

@@ -0,0 +1,13 @@
+package com.fs.third.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.third.domain.TencentWord;
+
+/**
+ * 腾讯文档Mapper接口
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+public interface TencentWordMapper extends BaseMapper<TencentWord> {
+}

+ 13 - 0
fs-service/src/main/java/com/fs/third/mapper/TencentWordSheetMapper.java

@@ -0,0 +1,13 @@
+package com.fs.third.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.third.domain.TencentWordSheet;
+
+/**
+ * 腾讯文档工作表Mapper接口
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+public interface TencentWordSheetMapper extends BaseMapper<TencentWordSheet> {
+}

+ 26 - 0
fs-service/src/main/java/com/fs/third/service/ITencentWordDetailService.java

@@ -0,0 +1,26 @@
+package com.fs.third.service;
+
+import com.fs.third.domain.TencentWordDetail;
+
+import java.util.List;
+
+/**
+ * 腾讯文档详情Service接口
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+public interface ITencentWordDetailService {
+
+    TencentWordDetail selectTencentWordDetailById(Long id);
+
+    List<TencentWordDetail> selectTencentWordDetailList(TencentWordDetail tencentWordDetail);
+
+    int insertTencentWordDetail(TencentWordDetail tencentWordDetail);
+
+    int updateTencentWordDetail(TencentWordDetail tencentWordDetail);
+
+    int deleteTencentWordDetailById(Long id);
+
+    int deleteTencentWordDetailByIds(Long[] ids);
+}

+ 34 - 0
fs-service/src/main/java/com/fs/third/service/ITencentWordService.java

@@ -0,0 +1,34 @@
+package com.fs.third.service;
+
+import com.fs.common.core.domain.R;
+import com.fs.third.domain.TencentWord;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 腾讯文档Service接口
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+public interface ITencentWordService {
+
+    TencentWord selectTencentWordById(Long id);
+
+    List<TencentWord> selectTencentWordList(TencentWord tencentWord);
+
+    int insertTencentWord(TencentWord tencentWord);
+
+    int updateTencentWord(TencentWord tencentWord);
+
+    int deleteTencentWordById(Long id);
+
+    int deleteTencentWordByIds(Long[] ids);
+
+    R createFile(String title);
+
+    List<TencentWord> getFiles();
+
+    void synchronization(String fileId);
+}

+ 26 - 0
fs-service/src/main/java/com/fs/third/service/ITencentWordSheetService.java

@@ -0,0 +1,26 @@
+package com.fs.third.service;
+
+import com.fs.third.domain.TencentWordSheet;
+
+import java.util.List;
+
+/**
+ * 腾讯文档工作表Service接口
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+public interface ITencentWordSheetService {
+
+    TencentWordSheet selectTencentWordSheetById(Long id);
+
+    List<TencentWordSheet> selectTencentWordSheetList(TencentWordSheet tencentWordSheet);
+
+    int insertTencentWordSheet(TencentWordSheet tencentWordSheet);
+
+    int updateTencentWordSheet(TencentWordSheet tencentWordSheet);
+
+    int deleteTencentWordSheetById(Long id);
+
+    int deleteTencentWordSheetByIds(Long[] ids);
+}

+ 49 - 0
fs-service/src/main/java/com/fs/third/service/impl/TencentWordDetailServiceImpl.java

@@ -0,0 +1,49 @@
+package com.fs.third.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.third.domain.TencentWordDetail;
+import com.fs.third.mapper.TencentWordDetailMapper;
+import com.fs.third.service.ITencentWordDetailService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 腾讯文档详情Service业务层处理
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+@Service
+public class TencentWordDetailServiceImpl extends ServiceImpl<TencentWordDetailMapper, TencentWordDetail> implements ITencentWordDetailService {
+
+    @Override
+    public TencentWordDetail selectTencentWordDetailById(Long id) {
+        return baseMapper.selectById(id);
+    }
+
+    @Override
+    public List<TencentWordDetail> selectTencentWordDetailList(TencentWordDetail tencentWordDetail) {
+        return baseMapper.selectList(null);
+    }
+
+    @Override
+    public int insertTencentWordDetail(TencentWordDetail tencentWordDetail) {
+        return baseMapper.insert(tencentWordDetail);
+    }
+
+    @Override
+    public int updateTencentWordDetail(TencentWordDetail tencentWordDetail) {
+        return baseMapper.updateById(tencentWordDetail);
+    }
+
+    @Override
+    public int deleteTencentWordDetailById(Long id) {
+        return baseMapper.deleteById(id);
+    }
+
+    @Override
+    public int deleteTencentWordDetailByIds(Long[] ids) {
+        return baseMapper.deleteBatchIds(java.util.Arrays.asList(ids));
+    }
+}

+ 282 - 0
fs-service/src/main/java/com/fs/third/service/impl/TencentWordServiceImpl.java

@@ -0,0 +1,282 @@
+package com.fs.third.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.hisStore.enums.SysConfigEnum;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
+import com.fs.third.domain.TencentWord;
+import com.fs.third.domain.TencentWordDetail;
+import com.fs.third.domain.TencentWordSheet;
+import com.fs.third.mapper.TencentWordMapper;
+import com.fs.third.mapper.TencentWordDetailMapper;
+import com.fs.third.mapper.TencentWordSheetMapper;
+import com.fs.third.service.ITencentWordService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+/**
+ * 腾讯文档Service业务层处理
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class TencentWordServiceImpl extends ServiceImpl<TencentWordMapper, TencentWord> implements ITencentWordService {
+
+    private final SysConfigMapper sysConfigMapper;
+    private final RedisCache redisCache;
+    private final TencentWordSheetMapper tencentWordSheetMapper;
+    private final TencentWordDetailMapper tencentWordDetailMapper;
+
+    @Override
+    public TencentWord selectTencentWordById(Long id) {
+        return baseMapper.selectById(id);
+    }
+
+    @Override
+    public List<TencentWord> selectTencentWordList(TencentWord tencentWord) {
+        return baseMapper.selectList(null);
+    }
+
+    @Override
+    public int insertTencentWord(TencentWord tencentWord) {
+        return baseMapper.insert(tencentWord);
+    }
+
+    @Override
+    public int updateTencentWord(TencentWord tencentWord) {
+        return baseMapper.updateById(tencentWord);
+    }
+
+    @Override
+    public int deleteTencentWordById(Long id) {
+        return baseMapper.deleteById(id);
+    }
+
+    @Override
+    public int deleteTencentWordByIds(Long[] ids) {
+        return baseMapper.deleteBatchIds(java.util.Arrays.asList(ids));
+    }
+
+    @Override
+    public R createFile(String title) {
+        Map<String, String> sysConfigCache;
+        try {
+            sysConfigCache = getSysConfigCache();
+        } catch (Exception e) {
+            return R.error("请先配置腾讯在线文档");
+        }
+
+        String clientId = sysConfigCache.get("clientId");
+        String accessToken = sysConfigCache.get("accessToken");
+        String openId = sysConfigCache.get("openId");
+
+        OkHttpClient client = new OkHttpClient();
+
+        RequestBody requestBody = new MultipartBody.Builder()
+                .setType(MultipartBody.FORM)
+                .addFormDataPart("title", title)
+                .addFormDataPart("type", "sheet")
+                .addFormDataPart("templateVersion", "0")
+                .build();
+
+        Request request = new Request.Builder()
+                .url("https://docs.qq.com/openapi/drive/v2/files")
+                .addHeader("Client-Id", clientId)
+                .addHeader("Access-Token", accessToken)
+                .addHeader("Open-Id", openId)
+                .post(requestBody)
+                .build();
+
+        try (Response response = client.newCall(request).execute()) {
+            if (response.isSuccessful() && response.body() != null) {
+                String responseBody = response.body().string();
+                log.info("腾讯文档创建文件成功 | response={}", responseBody);
+                JSONObject result = JSONObject.parseObject(responseBody);
+                JSONObject data = result.getJSONObject("data");
+                if (data != null) {
+                    TencentWord tencentWord = new TencentWord();
+                    tencentWord.setTitle(title);
+                    tencentWord.setType("sheet");
+                    tencentWord.setTemplateVersion("0");
+                    tencentWord.setUrl(data.getString("url"));
+                    tencentWord.setFileId(data.getString("ID"));
+                    baseMapper.insert(tencentWord);
+                }
+                return R.ok(result);
+            } else {
+                String errorBody = response.body() != null ? response.body().string() : "";
+                log.error("腾讯文档创建文件失败 | status={} | body={}", response.code(), errorBody);
+                return R.error("创建腾讯文档失败: " + errorBody);
+            }
+        } catch (IOException e) {
+            log.error("腾讯文档创建文件请求异常", e);
+            return R.error("创建腾讯文档请求异常: " + e.getMessage());
+        }
+    }
+
+    @Override
+    public List<TencentWord> getFiles() {
+        return baseMapper.selectList(new LambdaQueryWrapper<TencentWord>());
+    }
+
+    @Override
+    public void synchronization(String fileId) {
+        // 获取sheet
+        Map<String, String> sysConfigCache = getSysConfigCache();
+
+        String clientId = sysConfigCache.get("clientId");
+        String accessToken = sysConfigCache.get("accessToken");
+        String openId = sysConfigCache.get("openId");
+
+        OkHttpClient client = new OkHttpClient();
+
+        Request request = new Request.Builder()
+                .url("https://docs.qq.com/openapi/spreadsheet/v3/files/" + fileId)
+                .addHeader("Client-Id", clientId)
+                .addHeader("Access-Token", accessToken)
+                .addHeader("Open-Id", openId)
+                .get()
+                .build();
+
+        try (Response response = client.newCall(request).execute()) {
+            if (response.isSuccessful() && response.body() != null) {
+                String responseBody = response.body().string();
+                log.info("腾讯文档获取工作表成功 | fileId={} | response={}", fileId, responseBody);
+                JSONObject result = JSONObject.parseObject(responseBody);
+                JSONArray properties = result.getJSONArray("properties");
+                if (properties != null && !properties.isEmpty()) {
+                    for (int i = 0; i < properties.size(); i++) {
+                        JSONObject sheetJson = properties.getJSONObject(i);
+                        TencentWordSheet sheet = new TencentWordSheet();
+                        sheet.setFileId(fileId);
+                        sheet.setSheetId(sheetJson.getString("sheetId"));
+                        sheet.setTitle(sheetJson.getString("title"));
+                        sheet.setRowCount(sheetJson.getInteger("rowCount"));
+                        sheet.setColumnCount(sheetJson.getInteger("columnCount"));
+                        sheet.setRowTotal(sheetJson.getInteger("rowTotal"));
+                        sheet.setColumnTotal(sheetJson.getInteger("columnTotal"));
+                        tencentWordSheetMapper.insert(sheet);
+                    }
+                }
+            } else {
+                String errorBody = response.body() != null ? response.body().string() : "";
+                log.error("腾讯文档获取工作表失败 | fileId={} | status={} | body={}", fileId, response.code(), errorBody);
+            }
+        } catch (IOException e) {
+            log.error("腾讯文档获取工作表请求异常 | fileId={}", fileId, e);
+        }
+        List<TencentWordSheet> sheets = tencentWordSheetMapper.selectList(new LambdaQueryWrapper<TencentWordSheet>().eq(TencentWordSheet::getFileId, fileId));
+        sheets.forEach(sheet -> {
+            if (sheet.getRowCount() > 1) {
+                getSheetInfo(fileId, sheet);
+            }
+        });
+    }
+
+    private void getSheetInfo(String fileId, TencentWordSheet sheet) {
+        Map<String, String> sysConfigCache = getSysConfigCache();
+
+        String clientId = sysConfigCache.get("clientId");
+        String accessToken = sysConfigCache.get("accessToken");
+        String openId = sysConfigCache.get("openId");
+
+        String range = "A2:B" + sheet.getRowCount();
+
+        OkHttpClient client = new OkHttpClient();
+
+        Request request = new Request.Builder()
+                .url("https://docs.qq.com/openapi/spreadsheet/v3/files/" + fileId + "/" + sheet.getSheetId() + "/" + range)
+                .addHeader("Client-Id", clientId)
+                .addHeader("Access-Token", accessToken)
+                .addHeader("Open-Id", openId)
+                .get()
+                .build();
+
+        try (Response response = client.newCall(request).execute()) {
+            List<TencentWordDetail> tencentWordDetails = tencentWordDetailMapper.selectList(new LambdaQueryWrapper<TencentWordDetail>().eq(TencentWordDetail::getFileId, fileId).eq(TencentWordDetail::getSheetId, sheet.getSheetId()));
+            Map<String, Long> qIdMap = tencentWordDetails.stream().collect(Collectors.toMap(TencentWordDetail::getQ, TencentWordDetail::getId));
+            if (response.isSuccessful() && response.body() != null) {
+                ArrayList<TencentWordDetail> updates = new ArrayList<>();
+                String responseBody = response.body().string();
+                log.info("腾讯文档获取表格数据成功 | fileId={} | sheetId={} | response={}", fileId, sheet.getSheetId(), responseBody);
+                JSONObject result = JSONObject.parseObject(responseBody);
+                JSONObject gridData = result.getJSONObject("gridData");
+                if (gridData != null) {
+                    JSONArray rows = gridData.getJSONArray("rows");
+                    if (rows != null && !rows.isEmpty()) {
+                        for (int i = 0; i < rows.size(); i++) {
+                            JSONObject rowJson = rows.getJSONObject(i);
+                            JSONArray values = rowJson.getJSONArray("values");
+                            if (values != null && values.size() >= 2) {
+                                String q = getCellText(values.getJSONObject(0));
+                                String a = getCellText(values.getJSONObject(1));
+                                TencentWordDetail detail = new TencentWordDetail();
+                                detail.setFileId(fileId);
+                                detail.setSheetId(sheet.getSheetId());
+                                Long l = qIdMap.get(q);
+                                detail.setQ(q);
+                                detail.setA(a);
+                                if (l!= null){
+                                    detail.setId(l);
+                                    updates.add(detail);
+                                    continue;
+                                }
+                                tencentWordDetailMapper.insert(detail);
+                            }
+                        }
+                    }
+                }
+                if (!updates.isEmpty()) {
+                    tencentWordDetailMapper.updateBatchById(updates);
+                }
+            } else {
+                String errorBody = response.body() != null ? response.body().string() : "";
+                log.error("腾讯文档获取表格数据失败 | fileId={} | sheetId={} | status={} | body={}", fileId, sheet.getSheetId(), response.code(), errorBody);
+            }
+        } catch (IOException e) {
+            log.error("腾讯文档获取表格数据请求异常 | fileId={} | sheetId={}", fileId, sheet.getSheetId(), e);
+        }
+    }
+
+    private String getCellText(JSONObject cell) {
+        if (cell == null) {
+            return null;
+        }
+        JSONObject cellValue = cell.getJSONObject("cellValue");
+        if (cellValue != null) {
+            return cellValue.getString("text");
+        }
+        return null;
+    }
+
+    private Map<String, String> getSysConfigCache() {
+        Map<String, String> sysConfigMap = redisCache.getCacheMap(SysConfigEnum.TENCENT_WORD.getKey());
+        if (sysConfigMap == null || sysConfigMap.isEmpty()) {
+            SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey(SysConfigEnum.TENCENT_WORD.getKey());
+            if (sysConfig != null) {
+                JSONObject jsonObject = JSONObject.parseObject(sysConfig.getConfigValue());
+                if (jsonObject == null || jsonObject.isEmpty()) throw new RuntimeException("请先配置腾讯在线文档");
+                sysConfigMap = jsonObject.toJavaObject(Map.class);
+                redisCache.setCacheMap(SysConfigEnum.TENCENT_WORD.getKey(), sysConfigMap);
+            } else throw new RuntimeException("请先配置腾讯在线文档");
+        }
+        return sysConfigMap;
+    }
+}

+ 49 - 0
fs-service/src/main/java/com/fs/third/service/impl/TencentWordSheetServiceImpl.java

@@ -0,0 +1,49 @@
+package com.fs.third.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.third.domain.TencentWordSheet;
+import com.fs.third.mapper.TencentWordSheetMapper;
+import com.fs.third.service.ITencentWordSheetService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 腾讯文档工作表Service业务层处理
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+@Service
+public class TencentWordSheetServiceImpl extends ServiceImpl<TencentWordSheetMapper, TencentWordSheet> implements ITencentWordSheetService {
+
+    @Override
+    public TencentWordSheet selectTencentWordSheetById(Long id) {
+        return baseMapper.selectById(id);
+    }
+
+    @Override
+    public List<TencentWordSheet> selectTencentWordSheetList(TencentWordSheet tencentWordSheet) {
+        return baseMapper.selectList(null);
+    }
+
+    @Override
+    public int insertTencentWordSheet(TencentWordSheet tencentWordSheet) {
+        return baseMapper.insert(tencentWordSheet);
+    }
+
+    @Override
+    public int updateTencentWordSheet(TencentWordSheet tencentWordSheet) {
+        return baseMapper.updateById(tencentWordSheet);
+    }
+
+    @Override
+    public int deleteTencentWordSheetById(Long id) {
+        return baseMapper.deleteById(id);
+    }
+
+    @Override
+    public int deleteTencentWordSheetByIds(Long[] ids) {
+        return baseMapper.deleteBatchIds(java.util.Arrays.asList(ids));
+    }
+}

+ 61 - 0
fs-service/src/main/resources/db/tenant-initTable.sql

@@ -18004,5 +18004,66 @@ CREATE TABLE `company_ai_workflow_version`
     INDEX             `idx_workflow_version_no`(`workflow_id`, `version_no`) USING BTREE
 ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
 
+
+-- ----------------------------
+-- Table structure for tencent_word
+-- ----------------------------
+DROP TABLE IF EXISTS `tencent_word`;
+CREATE TABLE `tencent_word`  (
+    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '标题',
+    `type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '类型',
+    `template_version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模板版本',
+    `url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文档URL',
+    `file_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '文件ID',
+    `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建者',
+    `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新者',
+    `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
+    PRIMARY KEY (`id`) USING BTREE,
+    INDEX `idx_file_id`(`file_id` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '腾讯文档表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for tencent_word_sheet
+-- ----------------------------
+DROP TABLE IF EXISTS `tencent_word_sheet`;
+CREATE TABLE `tencent_word_sheet`  (
+    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `file_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '文件ID',
+    `sheet_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '工作表ID',
+    `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '工作表标题',
+    `row_count` int NULL DEFAULT NULL COMMENT '行数',
+    `column_count` int NULL DEFAULT NULL COMMENT '列数',
+    `row_total` int NULL DEFAULT NULL COMMENT '总行数',
+    `column_total` int NULL DEFAULT NULL COMMENT '总列数',
+    `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建者',
+    `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新者',
+    `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
+    PRIMARY KEY (`id`) USING BTREE,
+    INDEX `idx_file_id`(`file_id` ASC) USING BTREE,
+    INDEX `idx_sheet_id`(`sheet_id` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '腾讯文档工作表表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for tencent_word_detail
+-- ----------------------------
+DROP TABLE IF EXISTS `tencent_word_detail`;
+CREATE TABLE `tencent_word_detail`  (
+    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `file_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '文件ID',
+    `sheet_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '工作表ID',
+    `q` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '问题',
+    `a` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '答案',
+    `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建者',
+    `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新者',
+    `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
+    PRIMARY KEY (`id`) USING BTREE,
+    INDEX `idx_file_id`(`file_id` ASC) USING BTREE,
+    INDEX `idx_sheet_id`(`sheet_id` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '腾讯文档详情表' ROW_FORMAT = Dynamic;
+
 SET
 FOREIGN_KEY_CHECKS = 1;

+ 28 - 0
fs-service/src/main/resources/mapper/third/TencentWordDetailMapper.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.third.mapper.TencentWordDetailMapper">
+    <resultMap id="TencentWordDetailResult" type="com.fs.third.domain.TencentWordDetail">
+        <id property="id" column="id"/>
+        <result property="fileID" column="file_id"/>
+        <result property="sheetId" column="sheet_id"/>
+        <result property="q" column="q"/>
+        <result property="a" column="a"/>
+        <result property="createBy" column="create_by"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateBy" column="update_by"/>
+        <result property="updateTime" column="update_time"/>
+    </resultMap>
+
+    <update id="updateBatchById">
+        <foreach collection="list" item="item" separator=";">
+            update tencent_word_detail
+            <set>
+                <if test="item.a != null">a = #{item.a},</if>
+                update_time = now()
+            </set>
+            where id = #{item.id}
+        </foreach>
+    </update>
+</mapper>