|
|
@@ -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;
|
|
|
+ }
|
|
|
+}
|