diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..acb7754
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,39 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+.idea
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..ff0be76
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+
+ cn.isliu
+ feishu-table-helper
+ 1.0-SNAPSHOT
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ com.larksuite.oapi
+ oapi-sdk
+ 2.4.21
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.12.0
+
+
+ com.google.code.gson
+ gson
+ 2.8.9
+
+
+
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/FsHelper.java b/src/main/java/cn/isliu/FsHelper.java
new file mode 100644
index 0000000..db689af
--- /dev/null
+++ b/src/main/java/cn/isliu/FsHelper.java
@@ -0,0 +1,136 @@
+package cn.isliu;
+
+import cn.isliu.core.BaseEntity;
+import cn.isliu.core.FsTableData;
+import cn.isliu.core.Sheet;
+import cn.isliu.core.config.FsConfig;
+import cn.isliu.core.pojo.FieldProperty;
+import cn.isliu.core.service.CustomValueService;
+import cn.isliu.core.utils.*;
+import com.google.gson.JsonObject;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+public class FsHelper {
+
+ public static Boolean create(String sheetName, String spreadsheetToken, Class clazz) {
+ Map fieldsMap = PropertyUtil.getTablePropertyFieldsMap(clazz);
+ List headers = PropertyUtil.getHeaders(fieldsMap);
+
+ // 1、创建sheet
+ String sheetId = FsApiUtil.createSheet(sheetName, FsClientUtil.getFeishuClient(), spreadsheetToken);
+
+ // 2 添加表头数据
+ FsApiUtil.putValues(spreadsheetToken, FsTableUtil.getHeadTemplateBuilder(sheetId, headers), FsClientUtil.getFeishuClient());
+
+ // 3 设置表格样式
+ FsApiUtil.setTableStyle(FsTableUtil.getDefaultTableStyle(sheetId, headers.size()), sheetId, FsClientUtil.getFeishuClient(), spreadsheetToken);
+
+ // 4 设置单元格为文本格式
+ if (FsConfig.CELL_TEXT) {
+ String column = FsTableUtil.getColumnNameByNuNumber(headers.size());
+ FsApiUtil.setCellType(sheetId, "@", "A1", column + 200, FsClientUtil.getFeishuClient(), spreadsheetToken);
+ }
+
+ // 5 设置表格下拉
+ FsTableUtil.setTableOptions(spreadsheetToken, headers, fieldsMap, sheetId);
+ return true;
+ }
+
+
+ public static List read(String sheetId, String spreadsheetToken, Class clazz) {
+ List results = new ArrayList<>();
+ Sheet sheet = FsApiUtil.getSheetMetadata(sheetId, FsClientUtil.getFeishuClient(), spreadsheetToken);
+ List fsTableDataList = FsTableUtil.getFsTableData(sheet, spreadsheetToken);
+
+ Map fieldsMap = PropertyUtil.getTablePropertyFieldsMap(clazz);
+ List fieldPathList = fieldsMap.values().stream().map(FieldProperty::getField).collect(Collectors.toList());
+
+ fsTableDataList.forEach(tableData -> {
+ Object data = tableData.getData();
+ if (data instanceof HashMap) {
+ JsonObject jsonObject = JSONUtil.convertHashMapToJsonObject((HashMap) data);
+ Map dataMap = ConvertFieldUtil.convertPositionToField(jsonObject, fieldsMap);
+ T t = GenerateUtil.generateInstance(fieldPathList, clazz, dataMap);
+ if (t instanceof BaseEntity) {
+ ((BaseEntity) t).setUniqueId(tableData.getUniqueId());
+ }
+ results.add(t);
+ }
+ });
+ return results;
+ }
+
+ public static Object write(String sheetId, String spreadsheetToken, List dataList) {
+ if (dataList.isEmpty()) {
+ return null;
+ }
+
+ Class> aClass = dataList.get(0).getClass();
+ Map fieldsMap = PropertyUtil.getTablePropertyFieldsMap(aClass);
+
+ Sheet sheet = FsApiUtil.getSheetMetadata(sheetId, FsClientUtil.getFeishuClient(), spreadsheetToken);
+ List fsTableDataList = FsTableUtil.getFsTableData(sheet, spreadsheetToken);
+ Map currTableRowMap = fsTableDataList.stream().collect(Collectors.toMap(FsTableData::getUniqueId, FsTableData::getRow));
+
+ final Integer[] row = {0};
+ fsTableDataList.forEach(fsTableData -> {
+ if (fsTableData.getRow() > row[0]) {
+ row[0] = fsTableData.getRow();
+ }
+ });
+
+ Map titlePostionMap = FsTableUtil.getTitlePostionMap(sheet, spreadsheetToken);
+
+ Map fieldMap = new HashMap<>();
+ fieldsMap.forEach((field, fieldProperty) -> fieldMap.put(field, fieldProperty.getField()));
+
+ // 初始化批量插入对象
+ CustomValueService.ValueRequest.BatchPutValuesBuilder resultValuesBuilder = CustomValueService.ValueRequest.batchPutValues();
+
+ AtomicInteger rowCount = new AtomicInteger(row[0] + 1);
+
+ for (T data : dataList) {
+ Map values = GenerateUtil.getFieldValue(data, fieldMap);
+
+ String uniqueId = GenerateUtil.getUniqueId(data);
+
+ AtomicReference rowNum = new AtomicReference<>(currTableRowMap.get(uniqueId));
+ if (uniqueId != null && rowNum.get() != null) {
+ rowNum.set(rowNum.get() + 1);
+ values.forEach((field, fieldValue) -> {
+ if (!FsConfig.isCover && fieldValue == null) {
+ return;
+ }
+
+ String position = titlePostionMap.get(field);
+ resultValuesBuilder.addRange(sheetId, position + rowNum.get(), position + rowNum.get())
+ .addRow(fieldValue instanceof List ? GenerateUtil.getFieldValueList(fieldValue) : fieldValue);
+ });
+ } else {
+ int rowCou = rowCount.incrementAndGet();
+ values.forEach((field, fieldValue) -> {
+ if (!FsConfig.isCover && fieldValue == null) {
+ return;
+ }
+
+ String position = titlePostionMap.get(field);
+ resultValuesBuilder.addRange(sheetId, position + rowCou, position + rowCou)
+ .addRow(fieldValue instanceof List ? GenerateUtil.getFieldValueList(fieldValue) : fieldValue);
+
+ });
+ }
+ }
+
+ int rowTotal = sheet.getGridProperties().getRowCount();
+ int rowNum = rowCount.get();
+ if (rowNum > rowTotal) {
+ FsApiUtil.addRowColumns(sheetId, spreadsheetToken, "ROWS", rowTotal - rowNum, FsClientUtil.getFeishuClient());
+ }
+
+ return FsApiUtil.batchPutValues(sheetId, spreadsheetToken, resultValuesBuilder.build(), FsClientUtil.getFeishuClient());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/AddSheet.java b/src/main/java/cn/isliu/core/AddSheet.java
new file mode 100644
index 0000000..d59c8a7
--- /dev/null
+++ b/src/main/java/cn/isliu/core/AddSheet.java
@@ -0,0 +1,42 @@
+package cn.isliu.core;
+
+import java.util.Objects;
+
+public class AddSheet {
+
+ private Properties properties;
+
+ public AddSheet() {
+ }
+
+ public AddSheet(Properties properties) {
+ this.properties = properties;
+ }
+
+ public Properties getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Properties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ AddSheet addSheet = (AddSheet) o;
+ return Objects.equals(properties, addSheet.properties);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(properties);
+ }
+
+ @Override
+ public String toString() {
+ return "AddSheet{" +
+ "properties=" + properties +
+ '}';
+ }
+}
diff --git a/src/main/java/cn/isliu/core/BaseEntity.java b/src/main/java/cn/isliu/core/BaseEntity.java
new file mode 100644
index 0000000..360e2a7
--- /dev/null
+++ b/src/main/java/cn/isliu/core/BaseEntity.java
@@ -0,0 +1,14 @@
+package cn.isliu.core;
+
+public abstract class BaseEntity {
+
+ public String uniqueId;
+
+ public String getUniqueId() {
+ return uniqueId;
+ }
+
+ public void setUniqueId(String uniqueId) {
+ this.uniqueId = uniqueId;
+ }
+}
diff --git a/src/main/java/cn/isliu/core/Cell.java b/src/main/java/cn/isliu/core/Cell.java
new file mode 100644
index 0000000..655adc5
--- /dev/null
+++ b/src/main/java/cn/isliu/core/Cell.java
@@ -0,0 +1,72 @@
+package cn.isliu.core;
+
+
+public class Cell {
+
+ private int row;
+ private int col;
+ private Object value;
+ private Merge merge;
+
+ public int getRow() {
+ return row;
+ }
+
+ public void setRow(int row) {
+ this.row = row;
+ }
+
+ public Merge getMerge() {
+ return merge;
+ }
+
+ public void setMerge(Merge merge) {
+ this.merge = merge;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ public int getCol() {
+ return col;
+ }
+
+ public void setCol(int col) {
+ this.col = col;
+ }
+
+ @Override
+ public String toString() {
+ return "Cell{" +
+ "row=" + row +
+ ", col=" + col +
+ ", value=" + value +
+ ", merge=" + merge +
+ '}';
+ }
+
+ public Cell(int row, int col, Object o) {
+ this.row = row;
+ this.col = col;
+ this.value = o;
+ }
+
+ public Cell(int row, int col, Object o, Merge merge) {
+ this.row = row;
+ this.col = col;
+ this.value = o;
+ this.merge = merge;
+ }
+
+ public Cell() {
+ }
+
+ public boolean isMerged() {
+ return merge != null;
+ }
+}
diff --git a/src/main/java/cn/isliu/core/CopySheet.java b/src/main/java/cn/isliu/core/CopySheet.java
new file mode 100644
index 0000000..185c492
--- /dev/null
+++ b/src/main/java/cn/isliu/core/CopySheet.java
@@ -0,0 +1,43 @@
+package cn.isliu.core;
+
+
+import java.util.Objects;
+
+public class CopySheet {
+
+ private Properties properties;
+
+ public CopySheet() {
+ }
+
+ public CopySheet(Properties properties) {
+ this.properties = properties;
+ }
+
+ public Properties getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Properties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ CopySheet copySheet = (CopySheet) o;
+ return Objects.equals(properties, copySheet.properties);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(properties);
+ }
+
+ @Override
+ public String toString() {
+ return "CopySheet{" +
+ "properties=" + properties +
+ '}';
+ }
+}
diff --git a/src/main/java/cn/isliu/core/DeleteSheet.java b/src/main/java/cn/isliu/core/DeleteSheet.java
new file mode 100644
index 0000000..b29ede4
--- /dev/null
+++ b/src/main/java/cn/isliu/core/DeleteSheet.java
@@ -0,0 +1,53 @@
+package cn.isliu.core;
+
+import java.util.Objects;
+
+public class DeleteSheet {
+
+ private boolean result;
+ private String sheetId;
+
+ public boolean isResult() {
+ return result;
+ }
+
+ public void setResult(boolean result) {
+ this.result = result;
+ }
+
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ public DeleteSheet() {
+ }
+
+ public DeleteSheet(boolean result, String sheetId) {
+ this.result = result;
+ this.sheetId = sheetId;
+ }
+
+ @Override
+ public String toString() {
+ return "DeleteSheet{" +
+ "result=" + result +
+ ", sheetId='" + sheetId + '\'' +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ DeleteSheet deleteSheet = (DeleteSheet) o;
+ return result == deleteSheet.result && Objects.equals(sheetId, deleteSheet.sheetId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(result, sheetId);
+ }
+}
diff --git a/src/main/java/cn/isliu/core/FsTableData.java b/src/main/java/cn/isliu/core/FsTableData.java
new file mode 100644
index 0000000..40dbc8c
--- /dev/null
+++ b/src/main/java/cn/isliu/core/FsTableData.java
@@ -0,0 +1,64 @@
+package cn.isliu.core;
+
+import java.util.Objects;
+
+public class FsTableData {
+
+ private Integer row;
+ private String uniqueId;
+ private Object data;
+
+ public FsTableData() {
+ }
+
+ public FsTableData(Integer row, String uniqueId, Object data) {
+ this.row = row;
+ this.uniqueId = uniqueId;
+ this.data = data;
+ }
+
+ public Integer getRow() {
+ return row;
+ }
+
+ public void setRow(Integer row) {
+ this.row = row;
+ }
+
+ public String getUniqueId() {
+ return uniqueId;
+ }
+
+ public void setUniqueId(String uniqueId) {
+ this.uniqueId = uniqueId;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public void setData(Object data) {
+ this.data = data;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ FsTableData that = (FsTableData) o;
+ return Objects.equals(row, that.row) && Objects.equals(uniqueId, that.uniqueId) && Objects.equals(data, that.data);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(row, uniqueId, data);
+ }
+
+ @Override
+ public String toString() {
+ return "FsTableData{" +
+ "row=" + row +
+ ", uniqueId='" + uniqueId + '\'' +
+ ", data=" + data +
+ '}';
+ }
+}
diff --git a/src/main/java/cn/isliu/core/GridProperties.java b/src/main/java/cn/isliu/core/GridProperties.java
new file mode 100644
index 0000000..e93cca0
--- /dev/null
+++ b/src/main/java/cn/isliu/core/GridProperties.java
@@ -0,0 +1,70 @@
+package cn.isliu.core;
+
+import com.google.gson.annotations.SerializedName;
+import java.util.Objects;
+
+public class GridProperties {
+ @SerializedName("frozen_row_count")
+ private int frozenRowCount;
+
+ @SerializedName("frozen_column_count")
+ private int frozenColumnCount;
+
+ @SerializedName("row_count")
+ private int rowCount;
+
+ @SerializedName("column_count")
+ private int columnCount;
+
+ public GridProperties() {
+ }
+ public GridProperties(int frozenRowCount, int frozenColumnCount, int rowCount, int columnCount) {
+ this.frozenRowCount = frozenRowCount;
+ this.frozenColumnCount = frozenColumnCount;
+ this.rowCount = rowCount;
+ this.columnCount = columnCount;
+ }
+ public int getFrozenRowCount() {
+ return frozenRowCount;
+ }
+ public int getFrozenColumnCount() {
+ return frozenColumnCount;
+ }
+ public int getRowCount() {
+ return rowCount;
+ }
+ public int getColumnCount() {
+ return columnCount;
+ }
+ public void setFrozenRowCount(int frozenRowCount) {
+ this.frozenRowCount = frozenRowCount;
+ }
+ public void setFrozenColumnCount(int frozenColumnCount) {
+ this.frozenColumnCount = frozenColumnCount;
+ }
+ public void setRowCount(int rowCount) {
+ this.rowCount = rowCount;
+ }
+ public void setColumnCount(int columnCount) {
+ this.columnCount = columnCount;
+ }
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ GridProperties gridProperties = (GridProperties) o;
+ return frozenRowCount == gridProperties.frozenRowCount && frozenColumnCount == gridProperties.frozenColumnCount && rowCount == gridProperties.rowCount && columnCount == gridProperties.columnCount;
+ }
+ @Override
+ public int hashCode() {
+ return Objects.hash(frozenRowCount, frozenColumnCount, rowCount, columnCount);
+ }
+ @Override
+ public String toString() {
+ return "GridProperties{" +
+ "frozenRowCount=" + frozenRowCount +
+ ", frozenColumnCount=" + frozenColumnCount +
+ ", rowCount=" + rowCount +
+ ", columnCount=" + columnCount +
+ '}';
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/Merge.java b/src/main/java/cn/isliu/core/Merge.java
new file mode 100644
index 0000000..861d565
--- /dev/null
+++ b/src/main/java/cn/isliu/core/Merge.java
@@ -0,0 +1,77 @@
+package cn.isliu.core;
+
+import com.google.gson.annotations.SerializedName;
+
+public class Merge {
+ @SerializedName("start_row_index")
+ private int startRowIndex;
+
+ @SerializedName("end_row_index")
+ private int endRowIndex;
+
+ @SerializedName("start_column_index")
+ private int startColumnIndex;
+
+ @SerializedName("end_column_index")
+ private int endColumnIndex;
+
+ public Merge(int startRowIndex, int endRowIndex, int startColumnIndex, int endColumnIndex) {
+ this.startRowIndex = startRowIndex;
+ this.endRowIndex = endRowIndex;
+ this.startColumnIndex = startColumnIndex;
+ this.endColumnIndex = endColumnIndex;
+ }
+
+ public Merge() {
+ }
+
+ public int getStartRowIndex() {
+ return startRowIndex;
+ }
+
+ public void setStartRowIndex(int startRowIndex) {
+ this.startRowIndex = startRowIndex;
+ }
+
+ public int getEndRowIndex() {
+ return endRowIndex;
+ }
+
+ public void setEndRowIndex(int endRowIndex) {
+ this.endRowIndex = endRowIndex;
+ }
+
+ public int getStartColumnIndex() {
+ return startColumnIndex;
+ }
+
+ public void setStartColumnIndex(int startColumnIndex) {
+ this.startColumnIndex = startColumnIndex;
+ }
+
+ public int getEndColumnIndex() {
+ return endColumnIndex;
+ }
+
+ public void setEndColumnIndex(int endColumnIndex) {
+ this.endColumnIndex = endColumnIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "Merge{" +
+ "startRowIndex=" + startRowIndex +
+ ", endRowIndex=" + endRowIndex +
+ ", startColumnIndex=" + startColumnIndex +
+ ", endColumnIndex=" + endColumnIndex +
+ '}';
+ }
+
+ public int getRowSpan() {
+ return (endRowIndex - startRowIndex) + 1;
+ }
+
+ public int getColSpan() {
+ return (endColumnIndex - startColumnIndex) + 1;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/MergedCell.java b/src/main/java/cn/isliu/core/MergedCell.java
new file mode 100644
index 0000000..9e4fbf1
--- /dev/null
+++ b/src/main/java/cn/isliu/core/MergedCell.java
@@ -0,0 +1,55 @@
+package cn.isliu.core;
+
+import java.util.Objects;
+
+public class MergedCell extends Cell {
+
+ private int rowSpan;
+ private int colSpan;
+
+ public MergedCell() {
+ super(0, 0, null);
+ }
+
+ public MergedCell(int rowSpan, int colSpan) {
+ super(rowSpan, colSpan, null);
+ this.rowSpan = rowSpan;
+ this.colSpan = colSpan;
+ }
+
+ public int getRowSpan() {
+ return rowSpan;
+ }
+
+ public void setRowSpan(int rowSpan) {
+ this.rowSpan = rowSpan;
+ }
+
+ public int getColSpan() {
+ return colSpan;
+ }
+
+ public void setColSpan(int colSpan) {
+ this.colSpan = colSpan;
+ }
+
+ @Override
+ public String toString() {
+ return "MergedCell{" +
+ "rowSpan=" + rowSpan +
+ ", colSpan=" + colSpan +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ MergedCell that = (MergedCell) o;
+ return rowSpan == that.rowSpan && colSpan == that.colSpan;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(rowSpan, colSpan);
+ }
+}
diff --git a/src/main/java/cn/isliu/core/Properties.java b/src/main/java/cn/isliu/core/Properties.java
new file mode 100644
index 0000000..672f187
--- /dev/null
+++ b/src/main/java/cn/isliu/core/Properties.java
@@ -0,0 +1,65 @@
+package cn.isliu.core;
+
+
+import java.util.Objects;
+
+public class Properties {
+
+ private String sheetId;
+ private String title;
+ private int index;
+
+ public Properties() {
+ }
+
+ public Properties(String sheetId, String title, int index) {
+ this.sheetId = sheetId;
+ this.title = title;
+ this.index = index;
+ }
+
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ Properties that = (Properties) o;
+ return index == that.index && Objects.equals(sheetId, that.sheetId) && Objects.equals(title, that.title);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(sheetId, title, index);
+ }
+
+ @Override
+ public String toString() {
+ return "Properties{" +
+ "sheetId='" + sheetId + '\'' +
+ ", title='" + title + '\'' +
+ ", index=" + index +
+ '}';
+ }
+}
diff --git a/src/main/java/cn/isliu/core/Reply.java b/src/main/java/cn/isliu/core/Reply.java
new file mode 100644
index 0000000..66abd21
--- /dev/null
+++ b/src/main/java/cn/isliu/core/Reply.java
@@ -0,0 +1,64 @@
+package cn.isliu.core;
+
+
+import java.util.Objects;
+
+public class Reply {
+ private AddSheet addSheet;
+ private CopySheet copySheet;
+ private DeleteSheet deleteSheet;
+
+ public Reply() {
+ }
+
+ public Reply(AddSheet addSheet, CopySheet copySheet, DeleteSheet deleteSheet) {
+ this.addSheet = addSheet;
+ this.copySheet = copySheet;
+ this.deleteSheet = deleteSheet;
+ }
+
+ public AddSheet getAddSheet() {
+ return addSheet;
+ }
+
+ public void setAddSheet(AddSheet addSheet) {
+ this.addSheet = addSheet;
+ }
+
+ public CopySheet getCopySheet() {
+ return copySheet;
+ }
+
+ public void setCopySheet(CopySheet copySheet) {
+ this.copySheet = copySheet;
+ }
+
+ public DeleteSheet getDeleteSheet() {
+ return deleteSheet;
+ }
+
+ public void setDeleteSheet(DeleteSheet deleteSheet) {
+ this.deleteSheet = deleteSheet;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ Reply reply = (Reply) o;
+ return Objects.equals(addSheet, reply.addSheet) && Objects.equals(copySheet, reply.copySheet) && Objects.equals(deleteSheet, reply.deleteSheet);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(addSheet, copySheet, deleteSheet);
+ }
+
+ @Override
+ public String toString() {
+ return "Reply{" +
+ "addSheet=" + addSheet +
+ ", copySheet=" + copySheet +
+ ", deleteSheet=" + deleteSheet +
+ '}';
+ }
+}
diff --git a/src/main/java/cn/isliu/core/Sheet.java b/src/main/java/cn/isliu/core/Sheet.java
new file mode 100644
index 0000000..f7a0592
--- /dev/null
+++ b/src/main/java/cn/isliu/core/Sheet.java
@@ -0,0 +1,97 @@
+package cn.isliu.core;
+
+import com.google.gson.annotations.SerializedName;
+import java.util.List;
+
+public class Sheet {
+
+ @SerializedName("sheet_id")
+ private String sheetId;
+
+ @SerializedName("title")
+ private String title;
+
+ @SerializedName("index")
+ private int index;
+
+ @SerializedName("hidden")
+ private boolean hidden;
+
+ @SerializedName("grid_properties")
+ private GridProperties gridProperties;
+
+ @SerializedName("resource_type")
+ private String resourceType;
+
+ @SerializedName("merges")
+ private List merges;
+
+ public Sheet() {
+ }
+
+ public Sheet(String sheetId, String title, int index, boolean hidden, GridProperties gridProperties, String resourceType, List merges) {
+ this.sheetId = sheetId;
+ this.title = title;
+ this.index = index;
+ this.hidden = hidden;
+ this.gridProperties = gridProperties;
+ this.resourceType = resourceType;
+ this.merges = merges;
+ }
+
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public boolean isHidden() {
+ return hidden;
+ }
+
+ public GridProperties getGridProperties() {
+ return gridProperties;
+ }
+
+ public String getResourceType() {
+ return resourceType;
+ }
+
+ public List getMerges() {
+ return merges;
+ }
+
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public void setHidden(boolean hidden) {
+ this.hidden = hidden;
+ }
+
+ public void setGridProperties(GridProperties gridProperties) {
+ this.gridProperties = gridProperties;
+ }
+
+ public void setResourceType(String resourceType) {
+ this.resourceType = resourceType;
+ }
+
+ public void setMerges(List merges) {
+ this.merges = merges;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/SheetMeta.java b/src/main/java/cn/isliu/core/SheetMeta.java
new file mode 100644
index 0000000..f1cd574
--- /dev/null
+++ b/src/main/java/cn/isliu/core/SheetMeta.java
@@ -0,0 +1,40 @@
+package cn.isliu.core;
+
+import com.google.gson.annotations.SerializedName;
+import java.util.List;
+import java.util.Objects;
+
+public class SheetMeta {
+ @SerializedName("sheets")
+ private List sheets;
+
+ public List getSheets() {
+ return sheets;
+ }
+
+ public void setSheets(List sheets) {
+ this.sheets = sheets;
+ }
+
+ public SheetMeta() {
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ SheetMeta sheetMeta = (SheetMeta) o;
+ return Objects.equals(sheets, sheetMeta.sheets);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(sheets);
+ }
+
+ @Override
+ public String toString() {
+ return "SheetMeta{" +
+ "sheets=" + sheets +
+ '}';
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/TableData.java b/src/main/java/cn/isliu/core/TableData.java
new file mode 100644
index 0000000..b7c39c0
--- /dev/null
+++ b/src/main/java/cn/isliu/core/TableData.java
@@ -0,0 +1,38 @@
+package cn.isliu.core;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+
+public class TableData {
+ private List rows = new ArrayList<>();
+
+ public List getRows() {
+ return rows;
+ }
+
+ public void setRows(List rows) {
+ this.rows = rows;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ TableData tableData = (TableData) o;
+ return Objects.equals(rows, tableData.rows);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(rows);
+ }
+
+ public TableData(List rows) {
+ this.rows = rows;
+ }
+
+ public TableData() {
+ }
+}
diff --git a/src/main/java/cn/isliu/core/TableRow.java b/src/main/java/cn/isliu/core/TableRow.java
new file mode 100644
index 0000000..5578385
--- /dev/null
+++ b/src/main/java/cn/isliu/core/TableRow.java
@@ -0,0 +1,43 @@
+package cn.isliu.core;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class TableRow {
+ private List cells = new ArrayList<>();
+
+ public List getCells() {
+ return cells;
+ }
+
+ public void setCells(List cells) {
+ this.cells = cells;
+ }
+
+ public TableRow(List cells) {
+ this.cells = cells;
+ }
+
+ public TableRow() {
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ TableRow tableRow = (TableRow) o;
+ return Objects.equals(cells, tableRow.cells);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(cells);
+ }
+
+ @Override
+ public String toString() {
+ return "TableRow{" +
+ "cells=" + cells +
+ '}';
+ }
+}
diff --git a/src/main/java/cn/isliu/core/ValueRange.java b/src/main/java/cn/isliu/core/ValueRange.java
new file mode 100644
index 0000000..b80a44d
--- /dev/null
+++ b/src/main/java/cn/isliu/core/ValueRange.java
@@ -0,0 +1,76 @@
+package cn.isliu.core;
+
+import java.util.List;
+import java.util.Objects;
+
+public class ValueRange {
+
+ private String majorDimension;
+ private String range;
+ private int revision;
+ private List> values;
+
+ public ValueRange() {
+ }
+
+ public ValueRange(String majorDimension, String range, int revision, List> values) {
+ this.majorDimension = majorDimension;
+ this.range = range;
+ this.revision = revision;
+ this.values = values;
+ }
+
+ public String getMajorDimension() {
+ return majorDimension;
+ }
+
+ public void setMajorDimension(String majorDimension) {
+ this.majorDimension = majorDimension;
+ }
+
+ public String getRange() {
+ return range;
+ }
+
+ public void setRange(String range) {
+ this.range = range;
+ }
+
+ public int getRevision() {
+ return revision;
+ }
+
+ public void setRevision(int revision) {
+ this.revision = revision;
+ }
+
+ public List> getValues() {
+ return values;
+ }
+
+ public void setValues(List> values) {
+ this.values = values;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ ValueRange that = (ValueRange) o;
+ return revision == that.revision && Objects.equals(majorDimension, that.majorDimension) && Objects.equals(range, that.range) && Objects.equals(values, that.values);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(majorDimension, range, revision, values);
+ }
+
+ @Override
+ public String toString() {
+ return "ValueRange{" +
+ "majorDimension='" + majorDimension + '\'' +
+ ", range='" + range + '\'' +
+ ", revision=" + revision +
+ ", values=" + values +
+ '}';
+ }
+}
diff --git a/src/main/java/cn/isliu/core/ValuesBatch.java b/src/main/java/cn/isliu/core/ValuesBatch.java
new file mode 100644
index 0000000..fa088e3
--- /dev/null
+++ b/src/main/java/cn/isliu/core/ValuesBatch.java
@@ -0,0 +1,76 @@
+package cn.isliu.core;
+
+import java.util.List;
+import java.util.Objects;
+
+public class ValuesBatch {
+ private int revision;
+ private String spreadsheetToken;
+ private int totalCells;
+ private List valueRanges;
+
+ public ValuesBatch() {
+ }
+
+ public ValuesBatch(int revision, String spreadsheetToken, int totalCells, List valueRanges) {
+ this.revision = revision;
+ this.spreadsheetToken = spreadsheetToken;
+ this.totalCells = totalCells;
+ this.valueRanges = valueRanges;
+ }
+
+
+ public int getRevision() {
+ return revision;
+ }
+
+ public void setRevision(int revision) {
+ this.revision = revision;
+ }
+
+ public String getSpreadsheetToken() {
+ return spreadsheetToken;
+ }
+
+ public void setSpreadsheetToken(String spreadsheetToken) {
+ this.spreadsheetToken = spreadsheetToken;
+ }
+
+ public int getTotalCells() {
+ return totalCells;
+ }
+
+ public void setTotalCells(int totalCells) {
+ this.totalCells = totalCells;
+ }
+
+ public List getValueRanges() {
+ return valueRanges;
+ }
+
+ public void setValueRanges(List valueRanges) {
+ this.valueRanges = valueRanges;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ ValuesBatch that = (ValuesBatch) o;
+ return revision == that.revision && totalCells == that.totalCells && Objects.equals(spreadsheetToken, that.spreadsheetToken) && Objects.equals(valueRanges, that.valueRanges);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(revision, spreadsheetToken, totalCells, valueRanges);
+ }
+
+ @Override
+ public String toString() {
+ return "ValuesBatch{" +
+ "revision=" + revision +
+ ", spreadsheetToken='" + spreadsheetToken + '\'' +
+ ", totalCells=" + totalCells +
+ ", valueRanges=" + valueRanges +
+ '}';
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/annotation/TableProperty.java b/src/main/java/cn/isliu/core/annotation/TableProperty.java
new file mode 100644
index 0000000..6739164
--- /dev/null
+++ b/src/main/java/cn/isliu/core/annotation/TableProperty.java
@@ -0,0 +1,28 @@
+package cn.isliu.core.annotation;
+
+import cn.isliu.core.converters.FieldValueProcess;
+import cn.isliu.core.converters.OptionsValueProcess;
+import cn.isliu.core.enums.BaseEnum;
+import cn.isliu.core.enums.TypeEnum;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface TableProperty {
+
+ String value() default "";
+
+ String field() default "";
+
+ int order() default Integer.MAX_VALUE;
+
+ TypeEnum type() default TypeEnum.TEXT;
+
+ Class extends BaseEnum> enumClass() default BaseEnum.class;
+
+ Class extends FieldValueProcess> fieldFormatClass() default FieldValueProcess.class;
+
+ Class extends OptionsValueProcess> optionsClass() default OptionsValueProcess.class;
+}
diff --git a/src/main/java/cn/isliu/core/client/FeishuApiClient.java b/src/main/java/cn/isliu/core/client/FeishuApiClient.java
new file mode 100644
index 0000000..bca8151
--- /dev/null
+++ b/src/main/java/cn/isliu/core/client/FeishuApiClient.java
@@ -0,0 +1,99 @@
+package cn.isliu.core.client;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.lark.oapi.core.utils.Jsons;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 飞书API客户端抽象类 提供基础的HTTP请求处理和认证逻辑
+ */
+public abstract class FeishuApiClient {
+ protected final FeishuClient feishuClient;
+ protected final OkHttpClient httpClient;
+ protected final Gson gson;
+
+ protected static final String BASE_URL = "https://open.feishu.cn/open-apis";
+ protected static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
+
+ /**
+ * 构造函数
+ *
+ * @param feishuClient 飞书客户端
+ */
+ public FeishuApiClient(FeishuClient feishuClient) {
+ this.feishuClient = feishuClient;
+ this.httpClient = feishuClient.getHttpClient();
+ this.gson = Jsons.DEFAULT;
+ }
+
+ /**
+ * 获取租户访问令牌
+ *
+ * @return 访问令牌
+ * @throws IOException 请求异常
+ */
+ protected String getTenantAccessToken() throws IOException {
+ Map params = new HashMap<>();
+ params.put("app_id", feishuClient.getAppId());
+ params.put("app_secret", feishuClient.getAppSecret());
+
+ RequestBody body = RequestBody.create(gson.toJson(params), JSON_MEDIA_TYPE);
+
+ Request request =
+ new Request.Builder().url(BASE_URL + "/auth/v3/tenant_access_token/internal").post(body).build();
+
+ try (Response response = httpClient.newCall(request).execute()) {
+ if (!response.isSuccessful() || response.body() == null) {
+ throw new IOException("Failed to get tenant access token: " + response);
+ }
+
+ JsonObject jsonResponse = gson.fromJson(response.body().string(), JsonObject.class);
+ if (jsonResponse.has("tenant_access_token")) {
+ return jsonResponse.get("tenant_access_token").getAsString();
+ } else {
+ throw new IOException("Invalid token response: " + jsonResponse);
+ }
+ }
+ }
+
+ /**
+ * 构建带认证的请求
+ *
+ * @param url 请求URL
+ * @param method HTTP方法
+ * @param body 请求体
+ * @return 请求构建器
+ * @throws IOException 认证异常
+ */
+ protected Request.Builder createAuthenticatedRequest(String url, String method, RequestBody body)
+ throws IOException {
+ String token = getTenantAccessToken();
+ return new Request.Builder().url(url).header("Authorization", "Bearer " + token)
+ .header("Content-Type", "application/json; charset=utf-8").method(method, body);
+ }
+
+ /**
+ * 执行请求并处理响应
+ *
+ * @param request 请求对象
+ * @param responseClass 响应类型
+ * @param 响应类型
+ * @return 响应对象
+ * @throws IOException 请求异常
+ */
+ protected T executeRequest(Request request, Class responseClass) throws IOException {
+ try (Response response = httpClient.newCall(request).execute()) {
+ if (!response.isSuccessful() || response.body() == null) {
+ throw new IOException("Request failed: " + response);
+ }
+
+ String responseBody = response.body().string();
+ return gson.fromJson(responseBody, responseClass);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/client/FeishuClient.java b/src/main/java/cn/isliu/core/client/FeishuClient.java
new file mode 100644
index 0000000..b833450
--- /dev/null
+++ b/src/main/java/cn/isliu/core/client/FeishuClient.java
@@ -0,0 +1,266 @@
+package cn.isliu.core.client;
+
+import cn.isliu.core.service.*;
+import com.lark.oapi.Client;
+import com.lark.oapi.core.enums.AppType;
+import com.lark.oapi.service.drive.DriveService;
+import com.lark.oapi.service.sheets.SheetsService;
+import okhttp3.ConnectionPool;
+import okhttp3.OkHttpClient;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 飞书扩展客户端 封装官方SDK客户端并提供额外API支持
+ */
+public class FeishuClient {
+ private final Client officialClient;
+ private final OkHttpClient httpClient;
+ private final String appId;
+ private final String appSecret;
+
+ // 自定义服务,处理官方SDK未覆盖的API
+ private volatile CustomSheetService customSheetService;
+ private volatile CustomDimensionService customDimensionService;
+ private volatile CustomCellService customCellService;
+ private volatile CustomValueService customValueService;
+ private volatile CustomDataValidationService customDataValidationService;
+ private volatile CustomProtectedDimensionService customProtectedDimensionService;
+
+ private FeishuClient(String appId, String appSecret, Client officialClient, OkHttpClient httpClient) {
+ this.appId = appId;
+ this.appSecret = appSecret;
+ this.officialClient = officialClient;
+ this.httpClient = httpClient;
+ }
+
+ /**
+ * 创建客户端构建器
+ *
+ * @param appId 应用ID
+ * @param appSecret 应用密钥
+ * @return 构建器
+ */
+ public static Builder newBuilder(String appId, String appSecret) {
+ return new Builder(appId, appSecret);
+ }
+
+ /**
+ * 获取官方表格服务
+ *
+ * @return 官方表格服务
+ */
+ public SheetsService sheets() {
+ return officialClient.sheets();
+ }
+
+ /**
+ * 获取官方驱动服务
+ *
+ * @return 官方驱动服务
+ */
+ public DriveService drive() {
+ return officialClient.drive();
+ }
+
+ /**
+ * 获取扩展表格服务
+ *
+ * @return 扩展表格服务
+ */
+ public CustomSheetService customSheets() {
+ if (customSheetService == null) {
+ synchronized (this) {
+ if (customSheetService == null) {
+ customSheetService = new CustomSheetService(this);
+ }
+ }
+ }
+ return customSheetService;
+ }
+
+ /**
+ * 获取扩展行列服务
+ *
+ * @return 扩展行列服务
+ */
+ public CustomDimensionService customDimensions() {
+ if (customDimensionService == null) {
+ synchronized (this) {
+ if (customDimensionService == null) {
+ customDimensionService = new CustomDimensionService(this);
+ }
+ }
+ }
+ return customDimensionService;
+ }
+
+ /**
+ * 获取扩展单元格服务
+ *
+ * @return 扩展单元格服务
+ */
+ public CustomCellService customCells() {
+ if (customCellService == null) {
+ synchronized (this) {
+ if (customCellService == null) {
+ customCellService = new CustomCellService(this);
+ }
+ }
+ }
+ return customCellService;
+ }
+
+ /**
+ * 获取扩展数据值服务
+ *
+ * @return 扩展数据值服务
+ */
+ public CustomValueService customValues() {
+ if (customValueService == null) {
+ synchronized (this) {
+ if (customValueService == null) {
+ customValueService = new CustomValueService(this);
+ }
+ }
+ }
+ return customValueService;
+ }
+
+ /**
+ * 获取自定义数据验证服务
+ *
+ * @return 自定义数据验证服务
+ */
+ public CustomDataValidationService customDataValidations() {
+ if (customDataValidationService == null) {
+ synchronized (this) {
+ if (customDataValidationService == null) {
+ customDataValidationService = new CustomDataValidationService(this);
+ }
+ }
+ }
+ return customDataValidationService;
+ }
+
+ /**
+ * 获取扩展保护范围服务
+ *
+ * @return 扩展保护范围服务
+ */
+ public CustomProtectedDimensionService customProtectedDimensions() {
+ if (customProtectedDimensionService == null) {
+ synchronized (this) {
+ if (customProtectedDimensionService == null) {
+ customProtectedDimensionService = new CustomProtectedDimensionService(this);
+ }
+ }
+ }
+ return customProtectedDimensionService;
+ }
+
+ /**
+ * 获取官方客户端
+ *
+ * @return 官方Client实例
+ */
+ public Client getOfficialClient() {
+ return officialClient;
+ }
+
+ /**
+ * 获取HTTP客户端
+ *
+ * @return OkHttp客户端实例
+ */
+ OkHttpClient getHttpClient() {
+ return httpClient;
+ }
+
+ /**
+ * 获取应用ID
+ *
+ * @return 应用ID
+ */
+ public String getAppId() {
+ return appId;
+ }
+
+ /**
+ * 获取应用密钥
+ *
+ * @return 应用密钥
+ */
+ public String getAppSecret() {
+ return appSecret;
+ }
+
+ /**
+ * FeishuClient构建器
+ */
+ public static class Builder {
+ private final String appId;
+ private final String appSecret;
+ private OkHttpClient.Builder httpClientBuilder;
+ private AppType appType = AppType.SELF_BUILT;
+ private boolean logReqAtDebug = false;
+
+ private Builder(String appId, String appSecret) {
+ this.appId = appId;
+ this.appSecret = appSecret;
+ // 默认OkHttp配置
+ this.httpClientBuilder =
+ new OkHttpClient.Builder().connectTimeout(10, TimeUnit.MINUTES).readTimeout(10, TimeUnit.MINUTES)
+ .writeTimeout(10, TimeUnit.MINUTES).connectionPool(new ConnectionPool(5, 5, TimeUnit.MINUTES));
+ }
+
+ /**
+ * 配置HTTP客户端
+ *
+ * @param builder OkHttp客户端构建器
+ * @return 当前构建器
+ */
+ public Builder httpClient(OkHttpClient.Builder builder) {
+ this.httpClientBuilder = builder;
+ return this;
+ }
+
+ /**
+ * 设置应用类型
+ *
+ * @param appType 应用类型
+ * @return 当前构建器
+ */
+ public Builder appType(AppType appType) {
+ this.appType = appType;
+ return this;
+ }
+
+ /**
+ * 是否在debug级别打印请求
+ *
+ * @param logReqAtDebug 是否打印
+ * @return 当前构建器
+ */
+ public Builder logReqAtDebug(boolean logReqAtDebug) {
+ this.logReqAtDebug = logReqAtDebug;
+ return this;
+ }
+
+ /**
+ * 构建FeishuClient实例
+ *
+ * @return FeishuClient实例
+ */
+ public FeishuClient build() {
+ // 构建官方Client
+ Client officialClient =
+ Client.newBuilder(appId, appSecret).appType(appType).logReqAtDebug(logReqAtDebug).build();
+
+ // 构建OkHttpClient
+ OkHttpClient httpClient = httpClientBuilder.build();
+
+ return new FeishuClient(appId, appSecret, officialClient, httpClient);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/config/FsConfig.java b/src/main/java/cn/isliu/core/config/FsConfig.java
new file mode 100644
index 0000000..823d83e
--- /dev/null
+++ b/src/main/java/cn/isliu/core/config/FsConfig.java
@@ -0,0 +1,56 @@
+package cn.isliu.core.config;
+
+import cn.isliu.core.client.FeishuClient;
+import cn.isliu.core.utils.FsClientUtil;
+
+public class FsConfig {
+
+
+ public static int headLine = 1;
+
+ public static int titleLine = 1;
+
+ public static boolean isCover = false;
+ public static boolean CELL_TEXT = false;
+ public static String FORE_COLOR = "#000000";
+ public static String BACK_COLOR = "#d5d5d5";
+
+ public static void initConfig(String appId, String appSecret) {
+ FsClientUtil.initFeishuClient(appId, appSecret);
+ }
+
+ public static void initConfig(int headLine, int titleLine, String appId, String appSecret) {
+ FsConfig.headLine = headLine;
+ FsConfig.titleLine = titleLine;
+ FsClientUtil.initFeishuClient(appId, appSecret);
+ }
+
+ public static void initConfig(int headLine, FeishuClient client) {
+ FsConfig.headLine = headLine;
+ FsClientUtil.client = client;
+ }
+
+ public static void initConfig(FeishuClient client) {
+ FsClientUtil.client = client;
+ }
+
+ public static int getHeadLine() {
+ return headLine;
+ }
+
+ public static int getTitleLine() {
+ return titleLine;
+ }
+
+ public static FeishuClient getFeishuClient() {
+ return FsClientUtil.client;
+ }
+
+ public static void setHeadLine(int headLine) {
+ FsConfig.headLine = headLine;
+ }
+
+ public static void setTitleLine(int titleLine) {
+ FsConfig.titleLine = titleLine;
+ }
+}
diff --git a/src/main/java/cn/isliu/core/converters/FieldValueProcess.java b/src/main/java/cn/isliu/core/converters/FieldValueProcess.java
new file mode 100644
index 0000000..2eb441c
--- /dev/null
+++ b/src/main/java/cn/isliu/core/converters/FieldValueProcess.java
@@ -0,0 +1,11 @@
+package cn.isliu.core.converters;
+
+public interface FieldValueProcess {
+
+ T process(Object value);
+
+ /**
+ * 反向处理,将枚举值转换为原始值
+ */
+ T reverseProcess(Object value);
+}
diff --git a/src/main/java/cn/isliu/core/converters/FileUrlProcess.java b/src/main/java/cn/isliu/core/converters/FileUrlProcess.java
new file mode 100644
index 0000000..35aee3f
--- /dev/null
+++ b/src/main/java/cn/isliu/core/converters/FileUrlProcess.java
@@ -0,0 +1,128 @@
+package cn.isliu.core.converters;
+
+import cn.isliu.core.utils.FsApiUtil;
+import cn.isliu.core.utils.FsClientUtil;
+import cn.isliu.core.utils.FileUtil;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class FileUrlProcess implements FieldValueProcess {
+
+ private static final Logger log = Logger.getLogger(FileUrlProcess.class.getName());
+
+ @Override
+ public String process(Object value) {
+ if (value instanceof String) {
+ return value.toString();
+ }
+
+ List fileUrls = new ArrayList<>();
+ if (value instanceof JsonArray) {
+ JsonArray arr = (JsonArray) value;
+ for (int i = 0; i < arr.size(); i++) {
+ JsonElement jsonElement = arr.get(i);
+ if (jsonElement.isJsonObject()) {
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+ String url = getUrlByTextFile(jsonObject);
+ fileUrls.add(url);
+ }
+ }
+ } else if (value instanceof JsonObject) {
+ JsonObject jsb = (JsonObject) value;
+ String url = getUrlByTextFile(jsb);
+ fileUrls.add(url);
+ }
+ return String.join(",", fileUrls);
+ }
+
+ @Override
+ public String reverseProcess(Object value) {
+ // 简单实现,可以根据需要进行更复杂的反向处理
+ if (value == null) {
+ return null;
+ }
+ return value.toString();
+ }
+
+ private synchronized String getUrlByTextFile(JsonObject jsb) {
+ String url = "";
+ String cellType = jsb.get("type").getAsString();
+
+ switch (cellType) {
+ case "url":
+ String link = jsb.get("link").getAsString();
+ if (link == null) {
+ url = jsb.get("text").getAsString();
+ } else {
+ url = link;
+ }
+ break;
+ case "embed-image":
+ url = getImageOssUrl(jsb);
+ break;
+ case "attachment":
+ url = getAttachmentOssUrl(jsb);
+ break;
+ }
+ return url;
+ }
+
+ public static String getImageOssUrl(JsonObject jsb) {
+ String url = "";
+ String fileToken = jsb.get("fileToken").getAsString();
+
+ String fileUuid = UUID.randomUUID().toString();
+ String filePath = FileUtil.getRootPath() + File.separator + fileUuid + ".png";
+
+ boolean isSuccess = true;
+ try {
+ FsApiUtil.downloadMaterial(fileToken, filePath , FsClientUtil.getFeishuClient(), null);
+ url = filePath;
+ } catch (Exception e) {
+ log.log(Level.WARNING,"【飞书表格】 根据文件FileToken下载失败!fileToken: {0}, e: {1}", new Object[]{fileToken, e.getMessage()});
+ isSuccess = false;
+ }
+
+ if (!isSuccess) {
+ String tmpUrl = FsApiUtil.downloadTmpMaterialUrl(fileToken, FsClientUtil.getFeishuClient());
+ // 根据临时下载地址下载
+ FileUtil.downloadFile(tmpUrl, filePath);
+ }
+
+ log.info("【飞书表格】 文件上传-飞书图片上传成功!fileToken: " + fileToken + ", filePath: " + filePath);
+ return url;
+ }
+
+ public String getAttachmentOssUrl(JsonObject jsb) {
+ String url = "";
+ String token = jsb.get("fileToken").getAsString();
+ String fileName = jsb.get("text").getAsString();
+
+ String fileUuid = UUID.randomUUID().toString();
+ String path = FileUtil.getRootPath() + File.separator + fileUuid + fileName;
+
+ boolean isSuccess = true;
+ try {
+ FsApiUtil.downloadMaterial(token, path , FsClientUtil.getFeishuClient(), null);
+ url = path;
+ } catch (Exception e) {
+ log.log(Level.WARNING, "【飞书表格】 附件-根据文件FileToken下载失败!fileToken: {0}, e: {1}", new Object[]{token, e.getMessage()});
+ isSuccess = false;
+ }
+
+ if (!isSuccess) {
+ String tmpUrl = FsApiUtil.downloadTmpMaterialUrl(token, FsClientUtil.getFeishuClient());
+ FileUtil.downloadFile(tmpUrl, path);
+ }
+
+ log.info("【飞书表格】 文件上传-附件上传成功!fileToken: " + token + ", filePath: " + path);
+ return url;
+ }
+}
diff --git a/src/main/java/cn/isliu/core/converters/OptionsValueProcess.java b/src/main/java/cn/isliu/core/converters/OptionsValueProcess.java
new file mode 100644
index 0000000..50e8afa
--- /dev/null
+++ b/src/main/java/cn/isliu/core/converters/OptionsValueProcess.java
@@ -0,0 +1,6 @@
+package cn.isliu.core.converters;
+
+public interface OptionsValueProcess {
+
+ T process();
+}
diff --git a/src/main/java/cn/isliu/core/enums/BaseEnum.java b/src/main/java/cn/isliu/core/enums/BaseEnum.java
new file mode 100644
index 0000000..e8a3561
--- /dev/null
+++ b/src/main/java/cn/isliu/core/enums/BaseEnum.java
@@ -0,0 +1,53 @@
+package cn.isliu.core.enums;
+
+import java.util.Arrays;
+
+public interface BaseEnum {
+
+ /**
+ * 获取枚举代码
+ */
+ String getCode();
+
+ /**
+ * 获取枚举描述
+ */
+ String getDesc();
+
+ /**
+ * 根据描述获取枚举实例
+ *
+ * @param enumClass 枚举类
+ * @param desc 描述
+ * @param 枚举类型
+ * @return 枚举实例
+ */
+ static T getByDesc(Class enumClass, Object desc) {
+ if (desc == null) {
+ return null;
+ }
+
+ return Arrays.stream(enumClass.getEnumConstants())
+ .filter(e -> e.getDesc().equals(desc.toString()))
+ .findFirst()
+ .orElse(null);
+ }
+
+ /**
+ * 根据代码获取枚举实例
+ *
+ * @param enumClass 枚举类
+ * @param code 代码
+ * @param 枚举类型
+ * @return 枚举实例
+ */
+ static T getByCode(Class enumClass, Object code) {
+ if (code == null) {
+ return null;
+ }
+ return Arrays.stream(enumClass.getEnumConstants())
+ .filter(e -> e.getCode().equals(code.toString()))
+ .findFirst()
+ .orElse(null);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/enums/TypeEnum.java b/src/main/java/cn/isliu/core/enums/TypeEnum.java
new file mode 100644
index 0000000..066a62a
--- /dev/null
+++ b/src/main/java/cn/isliu/core/enums/TypeEnum.java
@@ -0,0 +1,41 @@
+package cn.isliu.core.enums;
+
+
+public enum TypeEnum {
+
+ SINGLE_SELECT("SINGLE_SELECT", "单选"),
+ MULTI_SELECT("MULTI_SELECT", "多选"),
+ TEXT("TEXT", "文本"),
+ NUMBER("NUMBER", "数字"),
+ DATE("DATE", "日期"),
+ TEXT_FILE("TEXT_FILE", "文本文件"),
+ MULTI_TEXT("MULTI_TEXT", "多个文本(逗号分割)"),
+ TEXT_URL("TEXT_URL", "文本链接")
+
+ ;
+
+ private final String code;
+ private final String desc;
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ TypeEnum(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static TypeEnum getByCode(String code) {
+ for (TypeEnum value : values()) {
+ if (value.getCode().equals(code)) {
+ return value;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/cn/isliu/core/exception/FsHelperException.java b/src/main/java/cn/isliu/core/exception/FsHelperException.java
new file mode 100644
index 0000000..e78886d
--- /dev/null
+++ b/src/main/java/cn/isliu/core/exception/FsHelperException.java
@@ -0,0 +1,12 @@
+package cn.isliu.core.exception;
+
+public class FsHelperException extends RuntimeException {
+
+ public FsHelperException(String message) {
+ super(message);
+ }
+
+ public FsHelperException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/cn/isliu/core/pojo/ApiResponse.java b/src/main/java/cn/isliu/core/pojo/ApiResponse.java
new file mode 100644
index 0000000..3c1daa0
--- /dev/null
+++ b/src/main/java/cn/isliu/core/pojo/ApiResponse.java
@@ -0,0 +1,80 @@
+package cn.isliu.core.pojo;
+
+/**
+ * API响应基类
+ *
+ * @param 响应数据类型
+ */
+public class ApiResponse {
+
+ private int code;
+ private String msg;
+ private T data;
+
+ /**
+ * 无参构造函数
+ */
+ public ApiResponse() {}
+
+ /**
+ * 构造函数
+ *
+ * @param code 响应码
+ * @param msg 响应消息
+ * @param data 响应数据
+ */
+ public ApiResponse(int code, String msg, T data) {
+ this.code = code;
+ this.msg = msg;
+ this.data = data;
+ }
+
+ /**
+ * 获取响应码
+ *
+ * @return 响应码
+ */
+ public int getCode() {
+ return code;
+ }
+
+ /**
+ * 获取响应消息
+ *
+ * @return 响应消息
+ */
+ public String getMsg() {
+ return msg;
+ }
+
+ /**
+ * 获取响应数据
+ *
+ * @return 响应数据
+ */
+ public T getData() {
+ return data;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public void setData(T data) {
+ this.data = data;
+ }
+
+ /**
+ * 判断请求是否成功
+ *
+ * @return true表示成功,false表示失败
+ */
+ public boolean success() {
+ return code == 0;
+ }
+
+}
diff --git a/src/main/java/cn/isliu/core/pojo/FieldProperty.java b/src/main/java/cn/isliu/core/pojo/FieldProperty.java
new file mode 100644
index 0000000..a687e10
--- /dev/null
+++ b/src/main/java/cn/isliu/core/pojo/FieldProperty.java
@@ -0,0 +1,65 @@
+package cn.isliu.core.pojo;
+
+import cn.isliu.core.annotation.TableProperty;
+import cn.isliu.core.converters.FieldValueProcess;
+import cn.isliu.core.enums.BaseEnum;
+import cn.isliu.core.enums.TypeEnum;
+
+public class FieldProperty {
+
+ private String field;
+ private TableProperty tableProperty;
+
+ public FieldProperty() {
+ }
+
+ public FieldProperty(String field, TableProperty tableProperty) {
+ this.field = field;
+ this.tableProperty = tableProperty;
+ }
+
+ public String getField() {
+ return field;
+ }
+
+ public void setField(String field) {
+ this.field = field;
+ }
+
+ public TableProperty getTableProperty() {
+ return tableProperty;
+ }
+
+ public void setTableProperty(TableProperty tableProperty) {
+ this.tableProperty = tableProperty;
+ }
+
+ public String getFieldField() {
+ return tableProperty.field();
+ }
+
+ public String getFieldName() {
+ return tableProperty.value();
+ }
+
+ public TypeEnum getFieldType() {
+ return tableProperty.type();
+ }
+
+ public Class extends FieldValueProcess> getFieldFormat() {
+ return tableProperty.fieldFormatClass();
+ }
+
+ public Class extends BaseEnum> getFieldEnum() {
+ return tableProperty.enumClass();
+ }
+
+ @Override
+ public String toString() {
+ return "FieldProperty{" +
+ "field='" + field + '\'' +
+ ", tableProperty=" + tableProperty +
+ '}';
+ }
+
+}
diff --git a/src/main/java/cn/isliu/core/service/CustomCellService.java b/src/main/java/cn/isliu/core/service/CustomCellService.java
new file mode 100644
index 0000000..386f938
--- /dev/null
+++ b/src/main/java/cn/isliu/core/service/CustomCellService.java
@@ -0,0 +1,2164 @@
+package cn.isliu.core.service;
+
+
+import cn.isliu.core.client.FeishuApiClient;
+import cn.isliu.core.client.FeishuClient;
+import cn.isliu.core.pojo.ApiResponse;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 自定义单元格服务 提供官方SDK未覆盖的单元格操作API
+ */
+public class CustomCellService extends FeishuApiClient {
+
+ /**
+ * 构造函数
+ *
+ * @param feishuClient 飞书客户端
+ */
+ public CustomCellService(FeishuClient feishuClient) {
+ super(feishuClient);
+ }
+
+ /**
+ * 批量操作单元格 支持合并单元格等操作 支持处理多个请求,如果有请求失败则中断后续请求
+ *
+ * @param spreadsheetToken 电子表格Token
+ * @param request 批量操作请求
+ * @return 批量操作响应
+ * @throws IOException 请求异常
+ */
+ public ApiResponse cellsBatchUpdate(String spreadsheetToken, CellBatchUpdateRequest request)
+ throws IOException {
+ List requests = request.getRequests();
+ ApiResponse response = null;
+
+ // 如果没有请求,返回空响应
+ if (requests == null || requests.isEmpty()) {
+ ApiResponse emptyResponse = new ApiResponse();
+ emptyResponse.setCode(400);
+ emptyResponse.setMsg("No cell operations found");
+ return emptyResponse;
+ }
+
+ // 依次处理每个请求
+ for (CellRequest cellRequest : requests) {
+ // 处理合并单元格请求
+ if (cellRequest.getMergeCells() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/merge_cells";
+
+ String params;
+
+ String type = cellRequest.getMergeCells().getType();
+ if (type != null && !type.isEmpty() && "JSON_STR".equals(type)) {
+ params = cellRequest.getMergeCells().getParams();
+ } else {
+ // 获取合并单元格范围
+ String range = cellRequest.getMergeCells().getRange();
+ if (range == null) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("Invalid cell range");
+ return errorResponse;
+ }
+ params = gson.toJson(new MergeCellsRequestBody(range, cellRequest.getMergeCells().getMergeType()));
+ }
+
+ // 构建合并单元格请求体
+ RequestBody body = RequestBody.create(params, JSON_MEDIA_TYPE);
+
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理拆分单元格请求
+ else if (cellRequest.getUnmergeCells() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/unmerge_cells";
+
+ // 获取拆分单元格范围
+ String range = cellRequest.getUnmergeCells().getRange();
+ if (range == null) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("Invalid cell range");
+ return errorResponse;
+ }
+
+ // 构建拆分单元格请求体
+ RequestBody body = RequestBody.create(gson.toJson(new UnmergeCellsRequestBody(range)), JSON_MEDIA_TYPE);
+
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理设置单元格样式请求
+ else if (cellRequest.getStyleCells() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/style";
+
+ // 获取单元格范围
+ String range = cellRequest.getStyleCells().getRange();
+ if (range == null) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("Invalid cell range");
+ return errorResponse;
+ }
+
+ // 构建设置样式请求体
+ RequestBody body = RequestBody.create(
+ gson.toJson(new StyleCellsRequestBody(range, cellRequest.getStyleCells().getStyle())),
+ JSON_MEDIA_TYPE);
+
+ Request httpRequest = createAuthenticatedRequest(url, "PUT", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理批量设置单元格样式请求
+ else if (cellRequest.getStyleCellsBatch() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/styles_batch_update";
+
+ String type = cellRequest.getStyleCellsBatch().getType();
+ String params = "";
+ if (type != null && !type.isEmpty() && "JSON_STR".equals(type)) {
+ params = cellRequest.getStyleCellsBatch().getParams();
+ } else {
+ // 获取单元格范围和样式
+ List ranges = cellRequest.getStyleCellsBatch().getRanges();
+ Style style = cellRequest.getStyleCellsBatch().getStyle();
+
+ if (ranges == null || ranges.isEmpty()) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("Invalid cell ranges");
+ return errorResponse;
+ }
+
+ // 构建批量设置样式请求体
+ StyleBatchUpdateRequest styleBatchRequest = new StyleBatchUpdateRequest();
+ StyleBatchData styleBatchData = new StyleBatchData();
+ styleBatchData.setRanges(ranges);
+ styleBatchData.setStyle(style);
+ styleBatchRequest.getData().add(styleBatchData);
+ params = gson.toJson(styleBatchRequest);
+ }
+
+ RequestBody body = RequestBody.create(params, JSON_MEDIA_TYPE);
+ Request httpRequest = createAuthenticatedRequest(url, "PUT", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 这里可以添加其他单元格操作类型
+ }
+
+ // 如果所有请求都成功处理,返回最后一个成功的响应
+ // 如果没有处理任何请求(没有有效的操作类型),返回错误响应
+ if (response == null) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("No valid cell operation found");
+ return errorResponse;
+ }
+
+ return response;
+ }
+
+ /**
+ * 批量操作单元格请求
+ */
+ public static class CellBatchUpdateRequest {
+ private List requests;
+
+ public CellBatchUpdateRequest() {
+ this.requests = new ArrayList<>();
+ }
+
+ public List getRequests() {
+ return requests;
+ }
+
+ public void setRequests(List requests) {
+ this.requests = requests;
+ }
+
+ /**
+ * 创建批量操作单元格请求的构建器
+ *
+ * @return 批量操作单元格请求的构建器
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * 批量操作单元格请求的构建器
+ */
+ public static class Builder {
+ private final CellBatchUpdateRequest request;
+
+ public Builder() {
+ request = new CellBatchUpdateRequest();
+ }
+
+ /**
+ * 添加一个单元格操作请求
+ *
+ * @param cellRequest 单元格操作请求
+ * @return 当前构建器
+ */
+ public Builder addRequest(CellRequest cellRequest) {
+ request.requests.add(cellRequest);
+ return this;
+ }
+
+ /**
+ * 构建批量操作单元格请求
+ *
+ * @return 批量操作单元格请求
+ */
+ public CellBatchUpdateRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 单元格操作请求
+ */
+ public static class CellRequest {
+ private MergeCellsRequest mergeCells;
+ private UnmergeCellsRequest unmergeCells;
+ private StyleCellsRequest styleCells;
+ private StyleCellsBatchRequest styleCellsBatch;
+
+ /**
+ * 获取合并单元格请求
+ *
+ * @return 合并单元格请求
+ */
+ public MergeCellsRequest getMergeCells() {
+ return mergeCells;
+ }
+
+ /**
+ * 设置合并单元格请求
+ *
+ * @param mergeCells 合并单元格请求
+ */
+ public void setMergeCells(MergeCellsRequest mergeCells) {
+ this.mergeCells = mergeCells;
+ }
+
+ /**
+ * 获取拆分单元格请求
+ *
+ * @return 拆分单元格请求
+ */
+ public UnmergeCellsRequest getUnmergeCells() {
+ return unmergeCells;
+ }
+
+ /**
+ * 设置拆分单元格请求
+ *
+ * @param unmergeCells 拆分单元格请求
+ */
+ public void setUnmergeCells(UnmergeCellsRequest unmergeCells) {
+ this.unmergeCells = unmergeCells;
+ }
+
+ /**
+ * 获取设置单元格样式请求
+ *
+ * @return 设置单元格样式请求
+ */
+ public StyleCellsRequest getStyleCells() {
+ return styleCells;
+ }
+
+ /**
+ * 设置单元格样式请求
+ *
+ * @param styleCells 设置单元格样式请求
+ */
+ public void setStyleCells(StyleCellsRequest styleCells) {
+ this.styleCells = styleCells;
+ }
+
+ /**
+ * 获取批量设置单元格样式请求
+ *
+ * @return 批量设置单元格样式请求
+ */
+ public StyleCellsBatchRequest getStyleCellsBatch() {
+ return styleCellsBatch;
+ }
+
+ /**
+ * 设置批量设置单元格样式请求
+ *
+ * @param styleCellsBatch 批量设置单元格样式请求
+ */
+ public void setStyleCellsBatch(StyleCellsBatchRequest styleCellsBatch) {
+ this.styleCellsBatch = styleCellsBatch;
+ }
+
+ /**
+ * 创建合并单元格的请求构建器 用于合并指定范围的单元格
+ *
+ * @return 合并单元格的构建器
+ */
+ public static MergeCellsBuilder mergeCells() {
+ return new MergeCellsBuilder();
+ }
+
+ /**
+ * 创建拆分单元格的请求构建器 用于拆分指定范围的单元格
+ *
+ * @return 拆分单元格的构建器
+ */
+ public static UnmergeCellsBuilder unmergeCells() {
+ return new UnmergeCellsBuilder();
+ }
+
+ /**
+ * 创建设置单元格样式的请求构建器 用于设置指定范围单元格的样式
+ *
+ * @return 设置单元格样式的构建器
+ */
+ public static StyleCellsBuilder styleCells() {
+ return new StyleCellsBuilder();
+ }
+
+ /**
+ * 创建批量设置单元格样式的请求构建器 用于一次设置多个区域单元格的样式
+ *
+ * @return 批量设置单元格样式的构建器
+ */
+ public static StyleCellsBatchBuilder styleCellsBatch() {
+ return new StyleCellsBatchBuilder();
+ }
+
+ /**
+ * 合并单元格的构建器 用于构建合并单元格的请求
+ */
+ public static class MergeCellsBuilder {
+ private final CellRequest request;
+ private final MergeCellsRequest mergeCells;
+
+ public MergeCellsBuilder() {
+ request = new CellRequest();
+ mergeCells = new MergeCellsRequest();
+ request.setMergeCells(mergeCells);
+ }
+
+ public MergeCellsBuilder setReqType(String reqType) {
+ mergeCells.setType(reqType);
+ return this;
+ }
+
+ public MergeCellsBuilder setReqParams(String reqParams) {
+ mergeCells.setParams(reqParams);
+ return this;
+ }
+
+ /**
+ * 设置要合并的单元格所在的工作表ID
+ *
+ * @param sheetId 工作表ID
+ * @return 当前构建器
+ */
+ public MergeCellsBuilder sheetId(String sheetId) {
+ mergeCells.sheetId = sheetId;
+ return this;
+ }
+
+ /**
+ * 设置要合并的单元格范围的开始位置
+ *
+ * @param startPosition 开始位置,如A1
+ * @return 当前构建器
+ */
+ public MergeCellsBuilder startPosition(String startPosition) {
+ mergeCells.startPosition = startPosition;
+ return this;
+ }
+
+ /**
+ * 设置要合并的单元格范围的结束位置
+ *
+ * @param endPosition 结束位置,如B2
+ * @return 当前构建器
+ */
+ public MergeCellsBuilder endPosition(String endPosition) {
+ mergeCells.endPosition = endPosition;
+ return this;
+ }
+
+ /**
+ * 设置合并方式
+ *
+ * @param mergeType 合并方式,可选值:MERGE_ALL(合并所有单元格)、MERGE_ROWS(按行合并)、MERGE_COLUMNS(按列合并)
+ * @return 当前构建器
+ */
+ public MergeCellsBuilder mergeType(String mergeType) {
+ mergeCells.mergeType = mergeType;
+ return this;
+ }
+
+ /**
+ * 构建合并单元格请求
+ *
+ * @return 单元格操作请求
+ */
+ public CellRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 拆分单元格的构建器 用于构建拆分单元格的请求
+ */
+ public static class UnmergeCellsBuilder {
+ private final CellRequest request;
+ private final UnmergeCellsRequest unmergeCells;
+
+ public UnmergeCellsBuilder() {
+ request = new CellRequest();
+ unmergeCells = new UnmergeCellsRequest();
+ request.setUnmergeCells(unmergeCells);
+ }
+
+ /**
+ * 设置要拆分的单元格所在的工作表ID
+ *
+ * @param sheetId 工作表ID
+ * @return 当前构建器
+ */
+ public UnmergeCellsBuilder sheetId(String sheetId) {
+ unmergeCells.sheetId = sheetId;
+ return this;
+ }
+
+ /**
+ * 设置要拆分的单元格范围的开始位置
+ *
+ * @param startPosition 开始位置,如A1
+ * @return 当前构建器
+ */
+ public UnmergeCellsBuilder startPosition(String startPosition) {
+ unmergeCells.startPosition = startPosition;
+ return this;
+ }
+
+ /**
+ * 设置要拆分的单元格范围的结束位置
+ *
+ * @param endPosition 结束位置,如B2
+ * @return 当前构建器
+ */
+ public UnmergeCellsBuilder endPosition(String endPosition) {
+ unmergeCells.endPosition = endPosition;
+ return this;
+ }
+
+ /**
+ * 构建拆分单元格请求
+ *
+ * @return 单元格操作请求
+ */
+ public CellRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 合并单元格请求
+ */
+ public static class MergeCellsRequest {
+ /**
+ * 工作表ID
+ */
+ private String sheetId;
+
+ /**
+ * 单元格范围的开始位置
+ */
+ private String startPosition;
+
+ /**
+ * 单元格范围的结束位置
+ */
+ private String endPosition;
+
+ /**
+ * 兼容旧版接口的完整range
+ */
+ private String legacyRange;
+
+ /**
+ * 合并方式 可选值: MERGE_ALL:合并所有单元格 MERGE_ROWS:按行合并 MERGE_COLUMNS:按列合并
+ */
+ private String mergeType;
+
+ private String type;
+ private String params;
+
+ /**
+ * 获取要合并的单元格范围
+ *
+ * @return 单元格范围,格式为 !<开始位置>:<结束位置>
+ */
+ public String getRange() {
+ if (legacyRange != null && !legacyRange.isEmpty()) {
+ return legacyRange;
+ }
+
+ if (sheetId != null && startPosition != null && endPosition != null) {
+ return sheetId + "!" + startPosition + ":" + endPosition;
+ }
+
+ return null;
+ }
+
+ /**
+ * 获取工作表ID
+ *
+ * @return 工作表ID
+ */
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ */
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ /**
+ * 获取单元格范围的开始位置
+ *
+ * @return 开始位置
+ */
+ public String getStartPosition() {
+ return startPosition;
+ }
+
+ /**
+ * 设置单元格范围的开始位置
+ *
+ * @param startPosition 开始位置,如A1
+ */
+ public void setStartPosition(String startPosition) {
+ this.startPosition = startPosition;
+ }
+
+ /**
+ * 获取单元格范围的结束位置
+ *
+ * @return 结束位置
+ */
+ public String getEndPosition() {
+ return endPosition;
+ }
+
+ /**
+ * 设置单元格范围的结束位置
+ *
+ * @param endPosition 结束位置,如B2
+ */
+ public void setEndPosition(String endPosition) {
+ this.endPosition = endPosition;
+ }
+
+ /**
+ * 获取合并方式
+ *
+ * @return 合并方式
+ */
+ public String getMergeType() {
+ return mergeType;
+ }
+
+ /**
+ * 设置合并方式
+ *
+ * @param mergeType 合并方式,可选值:MERGE_ALL、MERGE_ROWS、MERGE_COLUMNS
+ */
+ public void setMergeType(String mergeType) {
+ this.mergeType = mergeType;
+ }
+
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getParams() {
+ return params;
+ }
+
+ public void setParams(String params) {
+ this.params = params;
+ }
+ }
+
+ /**
+ * 拆分单元格请求
+ */
+ public static class UnmergeCellsRequest {
+ /**
+ * 工作表ID
+ */
+ private String sheetId;
+
+ /**
+ * 单元格范围的开始位置
+ */
+ private String startPosition;
+
+ /**
+ * 单元格范围的结束位置
+ */
+ private String endPosition;
+
+ /**
+ * 兼容旧版接口的完整range
+ */
+ private String legacyRange;
+
+ /**
+ * 获取要拆分的单元格范围
+ *
+ * @return 单元格范围,格式为 !<开始位置>:<结束位置>
+ */
+ public String getRange() {
+ if (legacyRange != null && !legacyRange.isEmpty()) {
+ return legacyRange;
+ }
+
+ if (sheetId != null && startPosition != null && endPosition != null) {
+ return sheetId + "!" + startPosition + ":" + endPosition;
+ }
+
+ return null;
+ }
+
+ /**
+ * 获取工作表ID
+ *
+ * @return 工作表ID
+ */
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ */
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ /**
+ * 获取单元格范围的开始位置
+ *
+ * @return 开始位置
+ */
+ public String getStartPosition() {
+ return startPosition;
+ }
+
+ /**
+ * 设置单元格范围的开始位置
+ *
+ * @param startPosition 开始位置,如A1
+ */
+ public void setStartPosition(String startPosition) {
+ this.startPosition = startPosition;
+ }
+
+ /**
+ * 获取单元格范围的结束位置
+ *
+ * @return 结束位置
+ */
+ public String getEndPosition() {
+ return endPosition;
+ }
+
+ /**
+ * 设置单元格范围的结束位置
+ *
+ * @param endPosition 结束位置,如B2
+ */
+ public void setEndPosition(String endPosition) {
+ this.endPosition = endPosition;
+ }
+ }
+
+ /**
+ * 设置单元格样式请求
+ */
+ public static class StyleCellsRequest {
+ /**
+ * 工作表ID
+ */
+ private String sheetId;
+
+ /**
+ * 单元格范围的开始位置
+ */
+ private String startPosition;
+
+ /**
+ * 单元格范围的结束位置
+ */
+ private String endPosition;
+
+ /**
+ * 兼容旧版接口的完整range
+ */
+ private String legacyRange;
+
+ /**
+ * 单元格样式
+ */
+ private Style style;
+
+ /**
+ * 获取要设置样式的单元格范围
+ *
+ * @return 单元格范围,格式为 !<开始位置>:<结束位置>
+ */
+ public String getRange() {
+ if (legacyRange != null && !legacyRange.isEmpty()) {
+ return legacyRange;
+ }
+
+ if (sheetId != null && startPosition != null && endPosition != null) {
+ return sheetId + "!" + startPosition + ":" + endPosition;
+ }
+
+ return null;
+ }
+
+ /**
+ * 获取工作表ID
+ *
+ * @return 工作表ID
+ */
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ */
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ /**
+ * 获取单元格范围的开始位置
+ *
+ * @return 开始位置
+ */
+ public String getStartPosition() {
+ return startPosition;
+ }
+
+ /**
+ * 设置单元格范围的开始位置
+ *
+ * @param startPosition 开始位置,如A1
+ */
+ public void setStartPosition(String startPosition) {
+ this.startPosition = startPosition;
+ }
+
+ /**
+ * 获取单元格范围的结束位置
+ *
+ * @return 结束位置
+ */
+ public String getEndPosition() {
+ return endPosition;
+ }
+
+ /**
+ * 设置单元格范围的结束位置
+ *
+ * @param endPosition 结束位置,如B2
+ */
+ public void setEndPosition(String endPosition) {
+ this.endPosition = endPosition;
+ }
+
+ /**
+ * 设置兼容旧版接口的完整range
+ *
+ * @param legacyRange 完整range
+ */
+ public void setLegacyRange(String legacyRange) {
+ this.legacyRange = legacyRange;
+ }
+
+ /**
+ * 获取单元格样式
+ *
+ * @return 单元格样式
+ */
+ public Style getStyle() {
+ return style;
+ }
+
+ /**
+ * 设置单元格样式
+ *
+ * @param style 单元格样式
+ */
+ public void setStyle(Style style) {
+ this.style = style;
+ }
+ }
+
+ /**
+ * 单元格样式
+ */
+ public static class Style {
+ private Font font;
+ private Integer textDecoration;
+ private String formatter;
+ private Integer hAlign;
+ private Integer vAlign;
+ private String foreColor;
+ private String backColor;
+ private String borderType;
+ private String borderColor;
+ private Boolean clean;
+
+ /**
+ * 获取字体样式
+ *
+ * @return 字体样式
+ */
+ public Font getFont() {
+ return font;
+ }
+
+ /**
+ * 设置字体样式
+ *
+ * @param font 字体样式
+ */
+ public void setFont(Font font) {
+ this.font = font;
+ }
+
+ /**
+ * 获取文本装饰
+ *
+ * @return 文本装饰,0:默认样式,1:下划线,2:删除线,3:下划线和删除线
+ */
+ public Integer getTextDecoration() {
+ return textDecoration;
+ }
+
+ /**
+ * 设置文本装饰
+ *
+ * @param textDecoration 文本装饰,0:默认样式,1:下划线,2:删除线,3:下划线和删除线
+ */
+ public void setTextDecoration(Integer textDecoration) {
+ this.textDecoration = textDecoration;
+ }
+
+ /**
+ * 获取数字格式
+ *
+ * @return 数字格式
+ */
+ public String getFormatter() {
+ return formatter;
+ }
+
+ /**
+ * 设置数字格式
+ *
+ * @param formatter 数字格式
+ */
+ public void setFormatter(String formatter) {
+ this.formatter = formatter;
+ }
+
+ /**
+ * 获取水平对齐方式
+ *
+ * @return 水平对齐方式,0:左对齐,1:中对齐,2:右对齐
+ */
+ public Integer getHAlign() {
+ return hAlign;
+ }
+
+ /**
+ * 设置水平对齐方式
+ *
+ * @param hAlign 水平对齐方式,0:左对齐,1:中对齐,2:右对齐
+ */
+ public void setHAlign(Integer hAlign) {
+ this.hAlign = hAlign;
+ }
+
+ /**
+ * 获取垂直对齐方式
+ *
+ * @return 垂直对齐方式,0:上对齐,1:中对齐,2:下对齐
+ */
+ public Integer getVAlign() {
+ return vAlign;
+ }
+
+ /**
+ * 设置垂直对齐方式
+ *
+ * @param vAlign 垂直对齐方式,0:上对齐,1:中对齐,2:下对齐
+ */
+ public void setVAlign(Integer vAlign) {
+ this.vAlign = vAlign;
+ }
+
+ /**
+ * 获取字体颜色
+ *
+ * @return 字体颜色,十六进制颜色代码
+ */
+ public String getForeColor() {
+ return foreColor;
+ }
+
+ /**
+ * 设置字体颜色
+ *
+ * @param foreColor 字体颜色,十六进制颜色代码
+ */
+ public void setForeColor(String foreColor) {
+ this.foreColor = foreColor;
+ }
+
+ /**
+ * 获取背景颜色
+ *
+ * @return 背景颜色,十六进制颜色代码
+ */
+ public String getBackColor() {
+ return backColor;
+ }
+
+ /**
+ * 设置背景颜色
+ *
+ * @param backColor 背景颜色,十六进制颜色代码
+ */
+ public void setBackColor(String backColor) {
+ this.backColor = backColor;
+ }
+
+ /**
+ * 获取边框类型
+ *
+ * @return 边框类型
+ */
+ public String getBorderType() {
+ return borderType;
+ }
+
+ /**
+ * 设置边框类型
+ *
+ * @param borderType
+ * 边框类型,可选值:FULL_BORDER、OUTER_BORDER、INNER_BORDER、NO_BORDER、LEFT_BORDER、RIGHT_BORDER、TOP_BORDER、BOTTOM_BORDER
+ */
+ public void setBorderType(String borderType) {
+ this.borderType = borderType;
+ }
+
+ /**
+ * 获取边框颜色
+ *
+ * @return 边框颜色,十六进制颜色代码
+ */
+ public String getBorderColor() {
+ return borderColor;
+ }
+
+ /**
+ * 设置边框颜色
+ *
+ * @param borderColor 边框颜色,十六进制颜色代码
+ */
+ public void setBorderColor(String borderColor) {
+ this.borderColor = borderColor;
+ }
+
+ /**
+ * 获取是否清除所有格式
+ *
+ * @return 是否清除所有格式
+ */
+ public Boolean getClean() {
+ return clean;
+ }
+
+ /**
+ * 设置是否清除所有格式
+ *
+ * @param clean 是否清除所有格式
+ */
+ public void setClean(Boolean clean) {
+ this.clean = clean;
+ }
+ }
+
+ /**
+ * 字体样式
+ */
+ public static class Font {
+ private Boolean bold;
+ private Boolean italic;
+ private String fontSize;
+ private Boolean clean;
+
+ /**
+ * 获取是否加粗
+ *
+ * @return 是否加粗
+ */
+ public Boolean getBold() {
+ return bold;
+ }
+
+ /**
+ * 设置是否加粗
+ *
+ * @param bold 是否加粗
+ */
+ public void setBold(Boolean bold) {
+ this.bold = bold;
+ }
+
+ /**
+ * 获取是否斜体
+ *
+ * @return 是否斜体
+ */
+ public Boolean getItalic() {
+ return italic;
+ }
+
+ /**
+ * 设置是否斜体
+ *
+ * @param italic 是否斜体
+ */
+ public void setItalic(Boolean italic) {
+ this.italic = italic;
+ }
+
+ /**
+ * 获取字体大小
+ *
+ * @return 字体大小,如10pt/1.5
+ */
+ public String getFontSize() {
+ return fontSize;
+ }
+
+ /**
+ * 设置字体大小
+ *
+ * @param fontSize 字体大小,如10pt/1.5
+ */
+ public void setFontSize(String fontSize) {
+ this.fontSize = fontSize;
+ }
+
+ /**
+ * 获取是否清除字体格式
+ *
+ * @return 是否清除字体格式
+ */
+ public Boolean getClean() {
+ return clean;
+ }
+
+ /**
+ * 设置是否清除字体格式
+ *
+ * @param clean 是否清除字体格式
+ */
+ public void setClean(Boolean clean) {
+ this.clean = clean;
+ }
+ }
+
+ /**
+ * 合并单元格请求体(用于API请求)
+ */
+ private static class MergeCellsRequestBody {
+ private final String range;
+ private final String mergeType;
+
+ /**
+ * 构造函数
+ *
+ * @param range 单元格范围
+ * @param mergeType 合并方式
+ */
+ public MergeCellsRequestBody(String range, String mergeType) {
+ this.range = range;
+ this.mergeType = mergeType;
+ }
+
+ /**
+ * 获取单元格范围
+ *
+ * @return 单元格范围
+ */
+ public String getRange() {
+ return range;
+ }
+
+ /**
+ * 获取合并方式
+ *
+ * @return 合并方式
+ */
+ public String getMergeType() {
+ return mergeType;
+ }
+ }
+
+ /**
+ * 拆分单元格请求体(用于API请求)
+ */
+ private static class UnmergeCellsRequestBody {
+ private final String range;
+
+ /**
+ * 构造函数
+ *
+ * @param range 单元格范围
+ */
+ public UnmergeCellsRequestBody(String range) {
+ this.range = range;
+ }
+
+ /**
+ * 获取单元格范围
+ *
+ * @return 单元格范围
+ */
+ public String getRange() {
+ return range;
+ }
+ }
+
+ /**
+ * 设置单元格样式请求体(用于API请求)
+ */
+ private static class StyleCellsRequestBody {
+ private final AppendStyle appendStyle;
+
+ /**
+ * 构造函数
+ *
+ * @param range 单元格范围
+ * @param style 单元格样式
+ */
+ public StyleCellsRequestBody(String range, Style style) {
+ this.appendStyle = new AppendStyle(range, style);
+ }
+
+ /**
+ * 获取appendStyle
+ *
+ * @return appendStyle
+ */
+ public AppendStyle getAppendStyle() {
+ return appendStyle;
+ }
+
+ /**
+ * 设置单元格样式请求的appendStyle部分
+ */
+ private static class AppendStyle {
+ private final String range;
+ private final Style style;
+
+ /**
+ * 构造函数
+ *
+ * @param range 单元格范围
+ * @param style 单元格样式
+ */
+ public AppendStyle(String range, Style style) {
+ this.range = range;
+ this.style = style;
+ }
+
+ /**
+ * 获取单元格范围
+ *
+ * @return 单元格范围
+ */
+ public String getRange() {
+ return range;
+ }
+
+ /**
+ * 获取单元格样式
+ *
+ * @return 单元格样式
+ */
+ public Style getStyle() {
+ return style;
+ }
+ }
+ }
+
+ /**
+ * 设置单元格样式的构建器 用于构建设置单元格样式的请求
+ */
+ public static class StyleCellsBuilder {
+ private final CellRequest request;
+ private final StyleCellsRequest styleCells;
+ private final Style style;
+ private Font font;
+
+ public StyleCellsBuilder() {
+ request = new CellRequest();
+ styleCells = new StyleCellsRequest();
+ style = new Style();
+ styleCells.setStyle(style);
+ request.setStyleCells(styleCells);
+ }
+
+ /**
+ * 设置要设置样式的单元格所在的工作表ID
+ *
+ * @param sheetId 工作表ID
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder sheetId(String sheetId) {
+ styleCells.setSheetId(sheetId);
+ return this;
+ }
+
+ /**
+ * 设置要设置样式的单元格范围的开始位置
+ *
+ * @param startPosition 开始位置,如A1
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder startPosition(String startPosition) {
+ styleCells.setStartPosition(startPosition);
+ return this;
+ }
+
+ /**
+ * 设置要设置样式的单元格范围的结束位置
+ *
+ * @param endPosition 结束位置,如B2
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder endPosition(String endPosition) {
+ styleCells.setEndPosition(endPosition);
+ return this;
+ }
+
+ /**
+ * 设置是否加粗
+ *
+ * @param bold 是否加粗
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder bold(Boolean bold) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setBold(bold);
+ return this;
+ }
+
+ /**
+ * 设置是否斜体
+ *
+ * @param italic 是否斜体
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder italic(Boolean italic) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setItalic(italic);
+ return this;
+ }
+
+ /**
+ * 设置字体大小
+ *
+ * @param fontSize 字体大小,如10pt/1.5
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder fontSize(String fontSize) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setFontSize(fontSize);
+ return this;
+ }
+
+ /**
+ * 设置是否清除字体格式
+ *
+ * @param clean 是否清除字体格式
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder fontClean(Boolean clean) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setClean(clean);
+ return this;
+ }
+
+ /**
+ * 设置文本装饰
+ *
+ * @param textDecoration 文本装饰,0:默认样式,1:下划线,2:删除线,3:下划线和删除线
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder textDecoration(Integer textDecoration) {
+ style.setTextDecoration(textDecoration);
+ return this;
+ }
+
+ /**
+ * 设置数字格式
+ *
+ * @param formatter 数字格式
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder formatter(String formatter) {
+ style.setFormatter(formatter);
+ return this;
+ }
+
+ /**
+ * 设置水平对齐方式
+ *
+ * @param hAlign 水平对齐方式,0:左对齐,1:中对齐,2:右对齐
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder hAlign(Integer hAlign) {
+ style.setHAlign(hAlign);
+ return this;
+ }
+
+ /**
+ * 设置垂直对齐方式
+ *
+ * @param vAlign 垂直对齐方式,0:上对齐,1:中对齐,2:下对齐
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder vAlign(Integer vAlign) {
+ style.setVAlign(vAlign);
+ return this;
+ }
+
+ /**
+ * 设置字体颜色
+ *
+ * @param foreColor 字体颜色,十六进制颜色代码
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder foreColor(String foreColor) {
+ style.setForeColor(foreColor);
+ return this;
+ }
+
+ /**
+ * 设置背景颜色
+ *
+ * @param backColor 背景颜色,十六进制颜色代码
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder backColor(String backColor) {
+ style.setBackColor(backColor);
+ return this;
+ }
+
+ /**
+ * 设置边框类型
+ *
+ * @param borderType
+ * 边框类型,可选值:FULL_BORDER、OUTER_BORDER、INNER_BORDER、NO_BORDER、LEFT_BORDER、RIGHT_BORDER、TOP_BORDER、BOTTOM_BORDER
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder borderType(String borderType) {
+ style.setBorderType(borderType);
+ return this;
+ }
+
+ /**
+ * 设置边框颜色
+ *
+ * @param borderColor 边框颜色,十六进制颜色代码
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder borderColor(String borderColor) {
+ style.setBorderColor(borderColor);
+ return this;
+ }
+
+ /**
+ * 设置是否清除所有格式
+ *
+ * @param clean 是否清除所有格式
+ * @return 当前构建器
+ */
+ public StyleCellsBuilder clean(Boolean clean) {
+ style.setClean(clean);
+ return this;
+ }
+
+ /**
+ * 构建设置单元格样式请求
+ *
+ * @return 单元格操作请求
+ */
+ public CellRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 批量设置单元格样式请求
+ */
+ public static class StyleBatchUpdateRequest {
+ private List data;
+
+ public StyleBatchUpdateRequest() {
+ this.data = new ArrayList<>();
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ /**
+ * 创建批量设置单元格样式请求的构建器
+ *
+ * @return 批量设置单元格样式请求的构建器
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * 批量设置单元格样式请求的构建器
+ */
+ public static class Builder {
+ private final StyleBatchUpdateRequest request;
+
+ public Builder() {
+ request = new StyleBatchUpdateRequest();
+ }
+
+ /**
+ * 添加一组样式设置
+ *
+ * @param styleBatchData 样式设置数据
+ * @return 当前构建器
+ */
+ public Builder addStyleBatch(StyleBatchData styleBatchData) {
+ request.data.add(styleBatchData);
+ return this;
+ }
+
+ /**
+ * 构建批量设置单元格样式请求
+ *
+ * @return 批量设置单元格样式请求
+ */
+ public StyleBatchUpdateRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 批量设置单元格样式数据
+ */
+ public static class StyleBatchData {
+ private List ranges;
+ private Style style;
+
+ public StyleBatchData() {
+ this.ranges = new ArrayList<>();
+ }
+
+ public List getRanges() {
+ return ranges;
+ }
+
+ public void setRanges(List ranges) {
+ this.ranges = ranges;
+ }
+
+ public Style getStyle() {
+ return style;
+ }
+
+ public void setStyle(Style style) {
+ this.style = style;
+ }
+
+ /**
+ * 创建批量设置单元格样式数据的构建器
+ *
+ * @return 批量设置单元格样式数据的构建器
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * 批量设置单元格样式数据的构建器
+ */
+ public static class Builder {
+ private final StyleBatchData data;
+ private final Style style;
+ private Font font;
+
+ public Builder() {
+ data = new StyleBatchData();
+ style = new Style();
+ data.setStyle(style);
+ }
+
+ /**
+ * 添加要设置样式的单元格范围
+ *
+ * @param range 单元格范围,格式为 !<开始位置>:<结束位置>
+ * @return 当前构建器
+ */
+ public Builder addRange(String range) {
+ data.ranges.add(range);
+ return this;
+ }
+
+ /**
+ * 设置是否加粗
+ *
+ * @param bold 是否加粗
+ * @return 当前构建器
+ */
+ public Builder bold(Boolean bold) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setBold(bold);
+ return this;
+ }
+
+ /**
+ * 设置是否斜体
+ *
+ * @param italic 是否斜体
+ * @return 当前构建器
+ */
+ public Builder italic(Boolean italic) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setItalic(italic);
+ return this;
+ }
+
+ /**
+ * 设置字体大小
+ *
+ * @param fontSize 字体大小,如10pt/1.5
+ * @return 当前构建器
+ */
+ public Builder fontSize(String fontSize) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setFontSize(fontSize);
+ return this;
+ }
+
+ /**
+ * 设置是否清除字体格式
+ *
+ * @param clean 是否清除字体格式
+ * @return 当前构建器
+ */
+ public Builder fontClean(Boolean clean) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setClean(clean);
+ return this;
+ }
+
+ /**
+ * 设置文本装饰
+ *
+ * @param textDecoration 文本装饰,0:默认样式,1:下划线,2:删除线,3:下划线和删除线
+ * @return 当前构建器
+ */
+ public Builder textDecoration(Integer textDecoration) {
+ style.setTextDecoration(textDecoration);
+ return this;
+ }
+
+ /**
+ * 设置数字格式
+ *
+ * @param formatter 数字格式
+ * @return 当前构建器
+ */
+ public Builder formatter(String formatter) {
+ style.setFormatter(formatter);
+ return this;
+ }
+
+ /**
+ * 设置水平对齐方式
+ *
+ * @param hAlign 水平对齐方式,0:左对齐,1:中对齐,2:右对齐
+ * @return 当前构建器
+ */
+ public Builder hAlign(Integer hAlign) {
+ style.setHAlign(hAlign);
+ return this;
+ }
+
+ /**
+ * 设置垂直对齐方式
+ *
+ * @param vAlign 垂直对齐方式,0:上对齐,1:中对齐,2:下对齐
+ * @return 当前构建器
+ */
+ public Builder vAlign(Integer vAlign) {
+ style.setVAlign(vAlign);
+ return this;
+ }
+
+ /**
+ * 设置字体颜色
+ *
+ * @param foreColor 字体颜色,十六进制颜色代码
+ * @return 当前构建器
+ */
+ public Builder foreColor(String foreColor) {
+ style.setForeColor(foreColor);
+ return this;
+ }
+
+ /**
+ * 设置背景颜色
+ *
+ * @param backColor 背景颜色,十六进制颜色代码
+ * @return 当前构建器
+ */
+ public Builder backColor(String backColor) {
+ style.setBackColor(backColor);
+ return this;
+ }
+
+ /**
+ * 设置边框类型
+ *
+ * @param borderType
+ * 边框类型,可选值:FULL_BORDER、OUTER_BORDER、INNER_BORDER、NO_BORDER、LEFT_BORDER、RIGHT_BORDER、TOP_BORDER、BOTTOM_BORDER
+ * @return 当前构建器
+ */
+ public Builder borderType(String borderType) {
+ style.setBorderType(borderType);
+ return this;
+ }
+
+ /**
+ * 设置边框颜色
+ *
+ * @param borderColor 边框颜色,十六进制颜色代码
+ * @return 当前构建器
+ */
+ public Builder borderColor(String borderColor) {
+ style.setBorderColor(borderColor);
+ return this;
+ }
+
+ /**
+ * 设置是否清除所有格式
+ *
+ * @param clean 是否清除所有格式
+ * @return 当前构建器
+ */
+ public Builder clean(Boolean clean) {
+ style.setClean(clean);
+ return this;
+ }
+
+ /**
+ * 构建批量设置单元格样式数据
+ *
+ * @return 批量设置单元格样式数据
+ */
+ public StyleBatchData build() {
+ return data;
+ }
+ }
+ }
+
+ /**
+ * 批量设置单元格样式请求
+ */
+ public static class StyleCellsBatchRequest {
+ @Deprecated
+ private List ranges;
+ private List cellRanges;
+ private Style style;
+ private String type;
+ private String params;
+
+ public StyleCellsBatchRequest() {
+ this.ranges = new ArrayList<>();
+ this.cellRanges = new ArrayList<>();
+ }
+
+ /**
+ * 获取单元格范围列表(用于API请求)
+ *
+ * @return 单元格范围列表
+ */
+ public List getRanges() {
+ // 如果有新的结构化范围,优先使用它们
+ if (cellRanges != null && !cellRanges.isEmpty()) {
+ List result = new ArrayList<>();
+ for (CellRange cellRange : cellRanges) {
+ result.add(cellRange.getRange());
+ }
+ return result;
+ }
+ return ranges;
+ }
+
+ /**
+ * 获取单元格结构化范围列表
+ *
+ * @return 单元格结构化范围列表
+ */
+ public List getCellRanges() {
+ return cellRanges;
+ }
+
+ /**
+ * 设置单元格结构化范围列表
+ *
+ * @param cellRanges 单元格结构化范围列表
+ */
+ public void setCellRanges(List cellRanges) {
+ this.cellRanges = cellRanges;
+ }
+
+ /**
+ * 添加单元格结构化范围
+ *
+ * @param cellRange 单元格结构化范围
+ */
+ public void addCellRange(CellRange cellRange) {
+ if (this.cellRanges == null) {
+ this.cellRanges = new ArrayList<>();
+ }
+ this.cellRanges.add(cellRange);
+ }
+
+ /**
+ * 添加单元格结构化范围
+ *
+ * @param sheetId 工作表ID
+ * @param startPosition 开始位置
+ * @param endPosition 结束位置
+ */
+ public void addCellRange(String sheetId, String startPosition, String endPosition) {
+ addCellRange(new CellRange(sheetId, startPosition, endPosition));
+ }
+
+ public Style getStyle() {
+ return style;
+ }
+
+ public void setStyle(Style style) {
+ this.style = style;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getParams() {
+ return params;
+ }
+ public void setParams(String params) {
+ this.params = params;
+ }
+ }
+
+ /**
+ * 单元格范围
+ */
+ public static class CellRange {
+ private String sheetId;
+ private String startPosition;
+ private String endPosition;
+
+ /**
+ * 默认构造函数
+ */
+ public CellRange() {}
+
+ /**
+ * 构造函数
+ *
+ * @param sheetId 工作表ID
+ * @param startPosition 开始位置
+ * @param endPosition 结束位置
+ */
+ public CellRange(String sheetId, String startPosition, String endPosition) {
+ this.sheetId = sheetId;
+ this.startPosition = startPosition;
+ this.endPosition = endPosition;
+ }
+
+ /**
+ * 获取单元格范围
+ *
+ * @return 单元格范围,格式为 !<开始位置>:<结束位置>
+ */
+ public String getRange() {
+ if (sheetId != null && startPosition != null && endPosition != null) {
+ return sheetId + "!" + startPosition + ":" + endPosition;
+ }
+ return null;
+ }
+
+ /**
+ * 从范围字符串解析
+ *
+ * @param range 单元格范围,格式为 !<开始位置>:<结束位置>
+ * @return 单元格范围对象
+ */
+ public static CellRange fromRange(String range) {
+ CellRange cellRange = new CellRange();
+ try {
+ String[] parts = range.split("!");
+ cellRange.sheetId = parts[0];
+ String[] positions = parts[1].split(":");
+ cellRange.startPosition = positions[0];
+ cellRange.endPosition = positions[1];
+ } catch (Exception e) {
+ // 解析失败,返回空对象
+ }
+ return cellRange;
+ }
+
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ public String getStartPosition() {
+ return startPosition;
+ }
+
+ public void setStartPosition(String startPosition) {
+ this.startPosition = startPosition;
+ }
+
+ public String getEndPosition() {
+ return endPosition;
+ }
+
+ public void setEndPosition(String endPosition) {
+ this.endPosition = endPosition;
+ }
+ }
+
+ /**
+ * 批量设置单元格样式的构建器 用于构建批量设置单元格样式的请求
+ */
+ public static class StyleCellsBatchBuilder {
+ private final CellRequest request;
+ private final StyleCellsBatchRequest styleCellsBatch;
+ private final Style style;
+ private Font font;
+
+ public StyleCellsBatchBuilder() {
+ request = new CellRequest();
+ styleCellsBatch = new StyleCellsBatchRequest();
+ style = new Style();
+ styleCellsBatch.setStyle(style);
+ request.setStyleCellsBatch(styleCellsBatch);
+ }
+
+ public StyleCellsBatchBuilder setReqType(String reqType) {
+ styleCellsBatch.setType(reqType);
+ return this;
+ }
+
+ public StyleCellsBatchBuilder setParams(String params) {
+ styleCellsBatch.setParams(params);
+ return this;
+ }
+
+ /**
+ * 添加要设置样式的单元格范围
+ *
+ * @param sheetId 工作表ID
+ * @param startPosition 开始位置,如A1
+ * @param endPosition 结束位置,如B2
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder addRange(String sheetId, String startPosition, String endPosition) {
+ styleCellsBatch.addCellRange(sheetId, startPosition, endPosition);
+ return this;
+ }
+
+ /**
+ * 设置是否加粗
+ *
+ * @param bold 是否加粗
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder bold(Boolean bold) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setBold(bold);
+ return this;
+ }
+
+ /**
+ * 设置是否斜体
+ *
+ * @param italic 是否斜体
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder italic(Boolean italic) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setItalic(italic);
+ return this;
+ }
+
+ /**
+ * 设置字体大小
+ *
+ * @param fontSize 字体大小,如10pt/1.5
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder fontSize(String fontSize) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setFontSize(fontSize);
+ return this;
+ }
+
+ /**
+ * 设置是否清除字体格式
+ *
+ * @param clean 是否清除字体格式
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder fontClean(Boolean clean) {
+ if (font == null) {
+ font = new Font();
+ style.setFont(font);
+ }
+ font.setClean(clean);
+ return this;
+ }
+
+ /**
+ * 设置文本装饰
+ *
+ * @param textDecoration 文本装饰,0:默认样式,1:下划线,2:删除线,3:下划线和删除线
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder textDecoration(Integer textDecoration) {
+ style.setTextDecoration(textDecoration);
+ return this;
+ }
+
+ /**
+ * 设置数字格式
+ *
+ * @param formatter 数字格式
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder formatter(String formatter) {
+ style.setFormatter(formatter);
+ return this;
+ }
+
+ /**
+ * 设置水平对齐方式
+ *
+ * @param hAlign 水平对齐方式,0:左对齐,1:中对齐,2:右对齐
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder hAlign(Integer hAlign) {
+ style.setHAlign(hAlign);
+ return this;
+ }
+
+ /**
+ * 设置垂直对齐方式
+ *
+ * @param vAlign 垂直对齐方式,0:上对齐,1:中对齐,2:下对齐
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder vAlign(Integer vAlign) {
+ style.setVAlign(vAlign);
+ return this;
+ }
+
+ /**
+ * 设置字体颜色
+ *
+ * @param foreColor 字体颜色,十六进制颜色代码
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder foreColor(String foreColor) {
+ style.setForeColor(foreColor);
+ return this;
+ }
+
+ /**
+ * 设置背景颜色
+ *
+ * @param backColor 背景颜色,十六进制颜色代码
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder backColor(String backColor) {
+ style.setBackColor(backColor);
+ return this;
+ }
+
+ /**
+ * 设置边框类型
+ *
+ * @param borderType
+ * 边框类型,可选值:FULL_BORDER、OUTER_BORDER、INNER_BORDER、NO_BORDER、LEFT_BORDER、RIGHT_BORDER、TOP_BORDER、BOTTOM_BORDER
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder borderType(String borderType) {
+ style.setBorderType(borderType);
+ return this;
+ }
+
+ /**
+ * 设置边框颜色
+ *
+ * @param borderColor 边框颜色,十六进制颜色代码
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder borderColor(String borderColor) {
+ style.setBorderColor(borderColor);
+ return this;
+ }
+
+ /**
+ * 设置是否清除所有格式
+ *
+ * @param clean 是否清除所有格式
+ * @return 当前构建器
+ */
+ public StyleCellsBatchBuilder clean(Boolean clean) {
+ style.setClean(clean);
+ return this;
+ }
+
+ /**
+ * 构建批量设置单元格样式请求
+ *
+ * @return 单元格操作请求
+ */
+ public CellRequest build() {
+ return request;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/service/CustomDataValidationService.java b/src/main/java/cn/isliu/core/service/CustomDataValidationService.java
new file mode 100644
index 0000000..d86fc9f
--- /dev/null
+++ b/src/main/java/cn/isliu/core/service/CustomDataValidationService.java
@@ -0,0 +1,1094 @@
+package cn.isliu.core.service;
+
+
+import okhttp3.Request;
+import okhttp3.RequestBody;
+
+import cn.isliu.core.client.FeishuApiClient;
+import cn.isliu.core.client.FeishuClient;
+import cn.isliu.core.pojo.ApiResponse;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 自定义数据验证服务 提供官方SDK未覆盖的数据验证API
+ */
+public class CustomDataValidationService extends FeishuApiClient {
+
+ /**
+ * 构造函数
+ *
+ * @param feishuClient 飞书客户端
+ */
+ public CustomDataValidationService(FeishuClient feishuClient) {
+ super(feishuClient);
+ }
+
+ /**
+ * 批量处理数据验证请求
+ *
+ * @param spreadsheetToken 电子表格Token
+ * @param request 批量处理请求
+ * @return 批量处理响应
+ * @throws IOException 请求异常
+ */
+ public ApiResponse dataValidationBatchUpdate(String spreadsheetToken, DataValidationBatchUpdateRequest request)
+ throws IOException {
+ List requests = request.getRequests();
+ ApiResponse response = null;
+
+ // 如果没有请求,返回空响应
+ if (requests == null || requests.isEmpty()) {
+ ApiResponse emptyResponse = new ApiResponse();
+ emptyResponse.setCode(400);
+ emptyResponse.setMsg("No data validation operations found");
+ return emptyResponse;
+ }
+
+ // 依次处理每个请求
+ for (DataValidationRequest validationRequest : requests) {
+ // 处理查询下拉列表请求
+ if (validationRequest.getQueryValidation() != null) {
+ QueryValidationRequest queryValidation = validationRequest.getQueryValidation();
+
+ // 验证请求参数
+ if (queryValidation.getRange() == null || queryValidation.getRange().isEmpty()) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("Range cannot be empty for data validation query");
+ return errorResponse;
+ }
+
+ // 构建基本URL
+ String baseUrl = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/dataValidation";
+
+ // 构建查询参数
+ StringBuilder urlBuilder = new StringBuilder(baseUrl);
+ urlBuilder.append("?range=")
+ .append(URLEncoder.encode(queryValidation.getRange(), StandardCharsets.UTF_8.toString()));
+
+ // 添加dataValidationType参数
+ urlBuilder.append("&dataValidationType=list");
+
+ String url = urlBuilder.toString();
+ Request httpRequest = createAuthenticatedRequest(url, "GET", null).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理删除下拉列表请求
+ else if (validationRequest.getDeleteValidation() != null) {
+ DeleteValidationRequest deleteValidation = validationRequest.getDeleteValidation();
+
+ // 验证请求参数
+ if (deleteValidation.getRange() == null || deleteValidation.getRange().isEmpty()) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("Range cannot be empty for data validation delete");
+ return errorResponse;
+ }
+
+ if (deleteValidation.getDataValidationIds() == null
+ || deleteValidation.getDataValidationIds().isEmpty()) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("DataValidationIds cannot be empty for data validation delete");
+ return errorResponse;
+ }
+
+ // 构建基本URL
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/dataValidation";
+
+ // 构建删除请求体
+ DeleteValidationRequestBody requestBody = new DeleteValidationRequestBody();
+ DeleteValidationRange validationRange = new DeleteValidationRange();
+ validationRange.setRange(deleteValidation.getRange());
+ validationRange.setDataValidationIds(deleteValidation.getDataValidationIds());
+ requestBody.getDataValidationRanges().add(validationRange);
+
+ RequestBody body = RequestBody.create(gson.toJson(requestBody), JSON_MEDIA_TYPE);
+ Request httpRequest = createAuthenticatedRequest(url, "DELETE", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理设置下拉列表请求
+ else if (validationRequest.getRange() != null && "list".equals(validationRequest.getDataValidationType())) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/dataValidation";
+
+ RequestBody body = RequestBody.create(gson.toJson(validationRequest), JSON_MEDIA_TYPE);
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理更新下拉列表请求
+ else if (validationRequest.getSheetId() != null && validationRequest.getDataValidationId() != null
+ && "list".equals(validationRequest.getDataValidationType())) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/dataValidation/"
+ + validationRequest.getSheetId() + "/" + validationRequest.getDataValidationId();
+
+ // 创建新的请求体,不包含sheetId和dataValidationId字段
+ DataValidationRequest requestBody = new DataValidationRequest();
+ requestBody.setDataValidationType(validationRequest.getDataValidationType());
+ requestBody.setDataValidation(validationRequest.getDataValidation());
+
+ RequestBody body = RequestBody.create(gson.toJson(requestBody), JSON_MEDIA_TYPE);
+ Request httpRequest = createAuthenticatedRequest(url, "PUT", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 这里可以添加其他数据验证类型的处理
+ }
+
+ // 如果所有请求都成功处理,返回最后一个成功的响应
+ // 如果没有处理任何请求(没有有效的操作类型),返回错误响应
+ if (response == null) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("No valid data validation operation found");
+ return errorResponse;
+ }
+
+ return response;
+ }
+
+ /**
+ * 删除下拉列表设置请求体
+ */
+ private static class DeleteValidationRequestBody {
+ private List dataValidationRanges;
+
+ public DeleteValidationRequestBody() {
+ this.dataValidationRanges = new ArrayList<>();
+ }
+
+ public List getDataValidationRanges() {
+ return dataValidationRanges;
+ }
+
+ public void setDataValidationRanges(List dataValidationRanges) {
+ this.dataValidationRanges = dataValidationRanges;
+ }
+ }
+
+ /**
+ * 删除下拉列表设置范围
+ */
+ private static class DeleteValidationRange {
+ private String range;
+ private List dataValidationIds;
+
+ public String getRange() {
+ return range;
+ }
+
+ public void setRange(String range) {
+ this.range = range;
+ }
+
+ public List getDataValidationIds() {
+ return dataValidationIds;
+ }
+
+ public void setDataValidationIds(List dataValidationIds) {
+ this.dataValidationIds = dataValidationIds;
+ }
+ }
+
+ /**
+ * 批量处理数据验证请求
+ */
+ public static class DataValidationBatchUpdateRequest {
+ private List requests;
+
+ public DataValidationBatchUpdateRequest() {
+ this.requests = new ArrayList<>();
+ }
+
+ public List getRequests() {
+ return requests;
+ }
+
+ public void setRequests(List requests) {
+ this.requests = requests;
+ }
+
+ /**
+ * 创建批量处理数据验证请求的构建器
+ *
+ * @return 批量处理数据验证请求的构建器
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * 批量处理数据验证请求的构建器
+ */
+ public static class Builder {
+ private final DataValidationBatchUpdateRequest request;
+
+ public Builder() {
+ request = new DataValidationBatchUpdateRequest();
+ }
+
+ /**
+ * 添加一个数据验证请求
+ *
+ * @param validationRequest 数据验证请求
+ * @return 当前构建器
+ */
+ public Builder addRequest(DataValidationRequest validationRequest) {
+ request.requests.add(validationRequest);
+ return this;
+ }
+
+ /**
+ * 构建批量处理数据验证请求
+ *
+ * @return 批量处理数据验证请求
+ */
+ public DataValidationBatchUpdateRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 数据验证请求
+ */
+ public static class DataValidationRequest {
+ private String range;
+ private String dataValidationType;
+ private DataValidation dataValidation;
+ private String sheetId;
+ private Integer dataValidationId;
+ private QueryValidationRequest queryValidation;
+ private DeleteValidationRequest deleteValidation;
+
+ /**
+ * 获取单元格范围
+ *
+ * @return 单元格范围
+ */
+ public String getRange() {
+ return range;
+ }
+
+ /**
+ * 设置单元格范围
+ *
+ * @param range 单元格范围,格式为 !<开始位置>:<结束位置>
+ */
+ public void setRange(String range) {
+ this.range = range;
+ }
+
+ /**
+ * 获取数据验证类型
+ *
+ * @return 数据验证类型
+ */
+ public String getDataValidationType() {
+ return dataValidationType;
+ }
+
+ /**
+ * 设置数据验证类型
+ *
+ * @param dataValidationType 数据验证类型
+ */
+ public void setDataValidationType(String dataValidationType) {
+ this.dataValidationType = dataValidationType;
+ }
+
+ /**
+ * 获取数据验证规则
+ *
+ * @return 数据验证规则
+ */
+ public DataValidation getDataValidation() {
+ return dataValidation;
+ }
+
+ /**
+ * 设置数据验证规则
+ *
+ * @param dataValidation 数据验证规则
+ */
+ public void setDataValidation(DataValidation dataValidation) {
+ this.dataValidation = dataValidation;
+ }
+
+ /**
+ * 获取工作表ID
+ *
+ * @return 工作表ID
+ */
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ */
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ /**
+ * 获取下拉列表ID
+ *
+ * @return 下拉列表ID
+ */
+ public Integer getDataValidationId() {
+ return dataValidationId;
+ }
+
+ /**
+ * 设置下拉列表ID
+ *
+ * @param dataValidationId 下拉列表ID
+ */
+ public void setDataValidationId(Integer dataValidationId) {
+ this.dataValidationId = dataValidationId;
+ }
+
+ /**
+ * 获取查询下拉列表设置请求
+ *
+ * @return 查询下拉列表设置请求
+ */
+ public QueryValidationRequest getQueryValidation() {
+ return queryValidation;
+ }
+
+ /**
+ * 设置查询下拉列表设置请求
+ *
+ * @param queryValidation 查询下拉列表设置请求
+ */
+ public void setQueryValidation(QueryValidationRequest queryValidation) {
+ this.queryValidation = queryValidation;
+ }
+
+ /**
+ * 获取删除下拉列表设置请求
+ *
+ * @return 删除下拉列表设置请求
+ */
+ public DeleteValidationRequest getDeleteValidation() {
+ return deleteValidation;
+ }
+
+ /**
+ * 设置删除下拉列表设置请求
+ *
+ * @param deleteValidation 删除下拉列表设置请求
+ */
+ public void setDeleteValidation(DeleteValidationRequest deleteValidation) {
+ this.deleteValidation = deleteValidation;
+ }
+
+ /**
+ * 创建设置下拉列表的请求构建器
+ *
+ * @return 设置下拉列表的构建器
+ */
+ public static ListDataValidationBuilder listValidation() {
+ return new ListDataValidationBuilder();
+ }
+
+ /**
+ * 创建更新下拉列表的请求构建器
+ *
+ * @return 更新下拉列表的构建器
+ */
+ public static UpdateListDataValidationBuilder updateListValidation() {
+ return new UpdateListDataValidationBuilder();
+ }
+
+ /**
+ * 创建查询下拉列表的请求构建器
+ *
+ * @return 查询下拉列表的构建器
+ */
+ public static QueryListDataValidationBuilder queryListValidation() {
+ return new QueryListDataValidationBuilder();
+ }
+
+ /**
+ * 创建删除下拉列表的请求构建器
+ *
+ * @return 删除下拉列表的构建器
+ */
+ public static DeleteListDataValidationBuilder deleteListValidation() {
+ return new DeleteListDataValidationBuilder();
+ }
+
+ /**
+ * 设置下拉列表的构建器
+ */
+ public static class ListDataValidationBuilder {
+ private final DataValidationRequest request;
+ private final DataValidation dataValidation;
+ private final DataValidationOptions options;
+
+ public ListDataValidationBuilder() {
+ request = new DataValidationRequest();
+ dataValidation = new DataValidation();
+ options = new DataValidationOptions();
+
+ request.setDataValidationType("list");
+ dataValidation.setOptions(options);
+ request.setDataValidation(dataValidation);
+ }
+
+ /**
+ * 设置单元格范围
+ *
+ * @param range 单元格范围,格式为 !<开始位置>:<结束位置>
+ * @return 当前构建器
+ */
+ public ListDataValidationBuilder range(String range) {
+ request.setRange(range);
+ return this;
+ }
+
+ /**
+ * 设置单元格范围
+ *
+ * @param sheetId 工作表ID
+ * @param startPosition 开始位置
+ * @param endPosition 结束位置
+ * @return 当前构建器
+ */
+ public ListDataValidationBuilder range(String sheetId, String startPosition, String endPosition) {
+ request.setRange(sheetId + "!" + startPosition + ":" + endPosition);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项值
+ *
+ * @param value 选项值
+ * @return 当前构建器
+ */
+ public ListDataValidationBuilder addValue(String value) {
+ dataValidation.getConditionValues().add(value);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项值
+ *
+ * @param values 选项值列表
+ * @return 当前构建器
+ */
+ public ListDataValidationBuilder addValues(List values) {
+ dataValidation.getConditionValues().addAll(values);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项值
+ *
+ * @param values 选项值数组
+ * @return 当前构建器
+ */
+ public ListDataValidationBuilder addValues(String... values) {
+ for (String value : values) {
+ dataValidation.getConditionValues().add(value);
+ }
+ return this;
+ }
+
+ /**
+ * 设置是否支持多选
+ *
+ * @param multipleValues 是否支持多选
+ * @return 当前构建器
+ */
+ public ListDataValidationBuilder multipleValues(boolean multipleValues) {
+ options.setMultipleValues(multipleValues);
+ return this;
+ }
+
+ /**
+ * 设置是否为下拉选项设置颜色
+ *
+ * @param highlightValidData 是否为下拉选项设置颜色
+ * @return 当前构建器
+ */
+ public ListDataValidationBuilder highlightValidData(boolean highlightValidData) {
+ options.setHighlightValidData(highlightValidData);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项颜色
+ *
+ * @param color 颜色,格式为RGB 16进制,如"#fffd00"
+ * @return 当前构建器
+ */
+ public ListDataValidationBuilder addColor(String color) {
+ options.getColors().add(color);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项颜色
+ *
+ * @param colors 颜色列表
+ * @return 当前构建器
+ */
+ public ListDataValidationBuilder addColors(List colors) {
+ options.getColors().addAll(colors);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项颜色
+ *
+ * @param colors 颜色数组
+ * @return 当前构建器
+ */
+ public ListDataValidationBuilder addColors(String... colors) {
+ for (String color : colors) {
+ options.getColors().add(color);
+ }
+ return this;
+ }
+
+ /**
+ * 构建设置下拉列表请求
+ *
+ * @return 数据验证请求
+ */
+ public DataValidationRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 更新下拉列表的构建器
+ */
+ public static class UpdateListDataValidationBuilder {
+ private final DataValidationRequest request;
+ private final DataValidation dataValidation;
+ private final DataValidationOptions options;
+
+ public UpdateListDataValidationBuilder() {
+ request = new DataValidationRequest();
+ dataValidation = new DataValidation();
+ options = new DataValidationOptions();
+
+ request.setDataValidationType("list");
+ dataValidation.setOptions(options);
+ request.setDataValidation(dataValidation);
+ }
+
+ /**
+ * 设置工作表ID和下拉列表ID
+ *
+ * @param sheetId 工作表ID
+ * @param dataValidationId 下拉列表ID
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder target(String sheetId, int dataValidationId) {
+ request.setSheetId(sheetId);
+ request.setDataValidationId(dataValidationId);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项值
+ *
+ * @param value 选项值
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder addValue(String value) {
+ dataValidation.getConditionValues().add(value);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项值
+ *
+ * @param values 选项值列表
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder addValues(List values) {
+ dataValidation.getConditionValues().addAll(values);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项值
+ *
+ * @param values 选项值数组
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder addValues(String... values) {
+ for (String value : values) {
+ dataValidation.getConditionValues().add(value);
+ }
+ return this;
+ }
+
+ /**
+ * 设置下拉选项值(替换现有值)
+ *
+ * @param values 选项值列表
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder setValues(List values) {
+ dataValidation.setConditionValues(new ArrayList<>(values));
+ return this;
+ }
+
+ /**
+ * 设置下拉选项值(替换现有值)
+ *
+ * @param values 选项值数组
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder setValues(String... values) {
+ List valueList = new ArrayList<>();
+ for (String value : values) {
+ valueList.add(value);
+ }
+ dataValidation.setConditionValues(valueList);
+ return this;
+ }
+
+ /**
+ * 设置是否支持多选
+ *
+ * @param multipleValues 是否支持多选
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder multipleValues(boolean multipleValues) {
+ options.setMultipleValues(multipleValues);
+ return this;
+ }
+
+ /**
+ * 设置是否为下拉选项设置颜色
+ *
+ * @param highlightValidData 是否为下拉选项设置颜色
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder highlightValidData(boolean highlightValidData) {
+ options.setHighlightValidData(highlightValidData);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项颜色
+ *
+ * @param color 颜色,格式为RGB 16进制,如"#fffd00"
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder addColor(String color) {
+ options.getColors().add(color);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项颜色
+ *
+ * @param colors 颜色列表
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder addColors(List colors) {
+ options.getColors().addAll(colors);
+ return this;
+ }
+
+ /**
+ * 添加下拉选项颜色
+ *
+ * @param colors 颜色数组
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder addColors(String... colors) {
+ for (String color : colors) {
+ options.getColors().add(color);
+ }
+ return this;
+ }
+
+ /**
+ * 设置下拉选项颜色(替换现有颜色)
+ *
+ * @param colors 颜色列表
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder setColors(List colors) {
+ options.setColors(new ArrayList<>(colors));
+ return this;
+ }
+
+ /**
+ * 设置下拉选项颜色(替换现有颜色)
+ *
+ * @param colors 颜色数组
+ * @return 当前构建器
+ */
+ public UpdateListDataValidationBuilder setColors(String... colors) {
+ List colorList = new ArrayList<>();
+ for (String color : colors) {
+ colorList.add(color);
+ }
+ options.setColors(colorList);
+ return this;
+ }
+
+ /**
+ * 构建更新下拉列表请求
+ *
+ * @return 数据验证请求
+ */
+ public DataValidationRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 查询下拉列表的构建器
+ */
+ public static class QueryListDataValidationBuilder {
+ private final DataValidationRequest request;
+ private final QueryValidationRequest queryValidation;
+
+ public QueryListDataValidationBuilder() {
+ request = new DataValidationRequest();
+ queryValidation = new QueryValidationRequest();
+ request.setQueryValidation(queryValidation);
+ }
+
+ /**
+ * 设置单元格范围
+ *
+ * @param range 单元格范围,格式为 !<开始位置>:<结束位置>
+ * @return 当前构建器
+ */
+ public QueryListDataValidationBuilder range(String range) {
+ queryValidation.setRange(range);
+ return this;
+ }
+
+ /**
+ * 设置单元格范围
+ *
+ * @param sheetId 工作表ID
+ * @param startPosition 开始位置
+ * @param endPosition 结束位置
+ * @return 当前构建器
+ */
+ public QueryListDataValidationBuilder range(String sheetId, String startPosition, String endPosition) {
+ queryValidation.setRange(sheetId + "!" + startPosition + ":" + endPosition);
+ return this;
+ }
+
+ /**
+ * 构建查询下拉列表请求
+ *
+ * @return 数据验证请求
+ */
+ public DataValidationRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 删除下拉列表的构建器
+ */
+ public static class DeleteListDataValidationBuilder {
+ private final DataValidationRequest request;
+ private final DeleteValidationRequest deleteValidation;
+
+ public DeleteListDataValidationBuilder() {
+ request = new DataValidationRequest();
+ deleteValidation = new DeleteValidationRequest();
+ request.setDeleteValidation(deleteValidation);
+ }
+
+ /**
+ * 设置单元格范围
+ *
+ * @param range 单元格范围,格式为 !<开始位置>:<结束位置>
+ * @return 当前构建器
+ */
+ public DeleteListDataValidationBuilder range(String range) {
+ deleteValidation.setRange(range);
+ return this;
+ }
+
+ /**
+ * 设置单元格范围
+ *
+ * @param sheetId 工作表ID
+ * @param startPosition 开始位置
+ * @param endPosition 结束位置
+ * @return 当前构建器
+ */
+ public DeleteListDataValidationBuilder range(String sheetId, String startPosition, String endPosition) {
+ deleteValidation.setRange(sheetId + "!" + startPosition + ":" + endPosition);
+ return this;
+ }
+
+ /**
+ * 添加要删除的下拉列表ID
+ *
+ * @param dataValidationId 下拉列表ID
+ * @return 当前构建器
+ */
+ public DeleteListDataValidationBuilder addDataValidationId(int dataValidationId) {
+ deleteValidation.getDataValidationIds().add(dataValidationId);
+ return this;
+ }
+
+ /**
+ * 添加要删除的下拉列表ID列表
+ *
+ * @param dataValidationIds 下拉列表ID列表
+ * @return 当前构建器
+ */
+ public DeleteListDataValidationBuilder addDataValidationIds(List dataValidationIds) {
+ deleteValidation.getDataValidationIds().addAll(dataValidationIds);
+ return this;
+ }
+
+ /**
+ * 添加要删除的下拉列表ID数组
+ *
+ * @param dataValidationIds 下拉列表ID数组
+ * @return 当前构建器
+ */
+ public DeleteListDataValidationBuilder addDataValidationIds(Integer... dataValidationIds) {
+ for (Integer id : dataValidationIds) {
+ deleteValidation.getDataValidationIds().add(id);
+ }
+ return this;
+ }
+
+ /**
+ * 构建删除下拉列表请求
+ *
+ * @return 数据验证请求
+ */
+ public DataValidationRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 查询下拉列表设置请求
+ */
+ public static class QueryValidationRequest {
+ private String range;
+
+ /**
+ * 获取单元格范围
+ *
+ * @return 单元格范围
+ */
+ public String getRange() {
+ return range;
+ }
+
+ /**
+ * 设置单元格范围
+ *
+ * @param range 单元格范围,格式为 !<开始位置>:<结束位置>
+ */
+ public void setRange(String range) {
+ this.range = range;
+ }
+ }
+
+ /**
+ * 删除下拉列表设置请求
+ */
+ public static class DeleteValidationRequest {
+ private String range;
+ private List dataValidationIds;
+
+ public DeleteValidationRequest() {
+ this.dataValidationIds = new ArrayList<>();
+ }
+
+ /**
+ * 获取单元格范围
+ *
+ * @return 单元格范围
+ */
+ public String getRange() {
+ return range;
+ }
+
+ /**
+ * 设置单元格范围
+ *
+ * @param range 单元格范围,格式为 !<开始位置>:<结束位置>
+ */
+ public void setRange(String range) {
+ this.range = range;
+ }
+
+ /**
+ * 获取要删除的下拉列表ID列表
+ *
+ * @return 下拉列表ID列表
+ */
+ public List getDataValidationIds() {
+ return dataValidationIds;
+ }
+
+ /**
+ * 设置要删除的下拉列表ID列表
+ *
+ * @param dataValidationIds 下拉列表ID列表
+ */
+ public void setDataValidationIds(List dataValidationIds) {
+ this.dataValidationIds = dataValidationIds;
+ }
+ }
+
+ /**
+ * 数据验证规则
+ */
+ public static class DataValidation {
+ private List conditionValues;
+ private DataValidationOptions options;
+
+ public DataValidation() {
+ this.conditionValues = new ArrayList<>();
+ }
+
+ /**
+ * 获取条件值列表
+ *
+ * @return 条件值列表
+ */
+ public List getConditionValues() {
+ return conditionValues;
+ }
+
+ /**
+ * 设置条件值列表
+ *
+ * @param conditionValues 条件值列表
+ */
+ public void setConditionValues(List conditionValues) {
+ this.conditionValues = conditionValues;
+ }
+
+ /**
+ * 获取选项配置
+ *
+ * @return 选项配置
+ */
+ public DataValidationOptions getOptions() {
+ return options;
+ }
+
+ /**
+ * 设置选项配置
+ *
+ * @param options 选项配置
+ */
+ public void setOptions(DataValidationOptions options) {
+ this.options = options;
+ }
+ }
+
+ /**
+ * 数据验证选项配置
+ */
+ public static class DataValidationOptions {
+ private Boolean multipleValues;
+ private Boolean highlightValidData;
+ private List colors;
+
+ public DataValidationOptions() {
+ this.colors = new ArrayList<>();
+ }
+
+ /**
+ * 获取是否支持多选
+ *
+ * @return 是否支持多选
+ */
+ public Boolean getMultipleValues() {
+ return multipleValues;
+ }
+
+ /**
+ * 设置是否支持多选
+ *
+ * @param multipleValues 是否支持多选
+ */
+ public void setMultipleValues(Boolean multipleValues) {
+ this.multipleValues = multipleValues;
+ }
+
+ /**
+ * 获取是否为下拉选项设置颜色
+ *
+ * @return 是否为下拉选项设置颜色
+ */
+ public Boolean getHighlightValidData() {
+ return highlightValidData;
+ }
+
+ /**
+ * 设置是否为下拉选项设置颜色
+ *
+ * @param highlightValidData 是否为下拉选项设置颜色
+ */
+ public void setHighlightValidData(Boolean highlightValidData) {
+ this.highlightValidData = highlightValidData;
+ }
+
+ /**
+ * 获取颜色列表
+ *
+ * @return 颜色列表
+ */
+ public List getColors() {
+ return colors;
+ }
+
+ /**
+ * 设置颜色列表
+ *
+ * @param colors 颜色列表
+ */
+ public void setColors(List colors) {
+ this.colors = colors;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/service/CustomDimensionService.java b/src/main/java/cn/isliu/core/service/CustomDimensionService.java
new file mode 100644
index 0000000..419262d
--- /dev/null
+++ b/src/main/java/cn/isliu/core/service/CustomDimensionService.java
@@ -0,0 +1,1083 @@
+package cn.isliu.core.service;
+
+import cn.isliu.core.client.FeishuApiClient;
+import cn.isliu.core.client.FeishuClient;
+import cn.isliu.core.pojo.ApiResponse;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 自定义维度服务 提供官方SDK未覆盖的行列操作API
+ */
+public class CustomDimensionService extends FeishuApiClient {
+
+ /**
+ * 构造函数
+ *
+ * @param feishuClient 飞书客户端
+ */
+ public CustomDimensionService(FeishuClient feishuClient) {
+ super(feishuClient);
+ }
+
+ /**
+ * 批量操作行列 支持添加、插入等操作 支持处理多个请求,如果有请求失败则中断后续请求
+ *
+ * @param spreadsheetToken 电子表格Token
+ * @param request 批量操作请求
+ * @return 批量操作响应
+ * @throws IOException 请求异常
+ */
+ public ApiResponse dimensionsBatchUpdate(String spreadsheetToken,
+ DimensionBatchUpdateRequest request) throws IOException {
+ List requests = request.getRequests();
+ ApiResponse response = null;
+
+ // 如果没有请求,返回空响应
+ if (requests == null || requests.isEmpty()) {
+ ApiResponse emptyResponse = new ApiResponse();
+ emptyResponse.setCode(400);
+ emptyResponse.setMsg("No dimension operations found");
+ return emptyResponse;
+ }
+
+ // 依次处理每个请求
+ for (DimensionRequest dimensionRequest : requests) {
+ // 处理添加行列请求
+ if (dimensionRequest.getAddDimension() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/dimension_range";
+
+ // 构建添加行列请求体
+ RequestBody body = RequestBody.create(
+ gson.toJson(new AddDimensionRequestBody(dimensionRequest.getAddDimension())), JSON_MEDIA_TYPE);
+
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理插入行列请求
+ else if (dimensionRequest.getInsertDimension() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/insert_dimension_range";
+
+ // 构建插入行列请求体
+ RequestBody body =
+ RequestBody.create(gson.toJson(new InsertDimensionRequestBody(dimensionRequest.getInsertDimension(),
+ dimensionRequest.getInheritStyle())), JSON_MEDIA_TYPE);
+
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理更新行列请求
+ else if (dimensionRequest.getUpdateDimension() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/dimension_range";
+
+ // 构建更新行列请求体
+ RequestBody body =
+ RequestBody.create(gson.toJson(new UpdateDimensionRequestBody(dimensionRequest.getUpdateDimension(),
+ dimensionRequest.getDimensionProperties())), JSON_MEDIA_TYPE);
+
+ // 使用PUT方法
+ Request httpRequest = createAuthenticatedRequest(url, "PUT", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理删除行列请求
+ else if (dimensionRequest.getDeleteDimension() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/dimension_range";
+
+ // 构建删除行列请求体
+ RequestBody body = RequestBody.create(
+ gson.toJson(new DeleteDimensionRequestBody(dimensionRequest.getDeleteDimension())),
+ JSON_MEDIA_TYPE);
+
+ // 使用DELETE方法
+ Request httpRequest = createAuthenticatedRequest(url, "DELETE", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ }
+
+ // 如果所有请求都成功处理,返回最后一个成功的响应
+ // 如果没有处理任何请求(没有有效的操作类型),返回错误响应
+ if (response == null) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("No valid dimension operation found");
+ return errorResponse;
+ }
+
+ return response;
+ }
+
+ /**
+ * 批量操作行列请求
+ */
+ public static class DimensionBatchUpdateRequest {
+ private List requests;
+
+ public DimensionBatchUpdateRequest() {
+ this.requests = new ArrayList<>();
+ }
+
+ public List getRequests() {
+ return requests;
+ }
+
+ public void setRequests(List requests) {
+ this.requests = requests;
+ }
+
+ /**
+ * 创建批量操作行列请求的构建器
+ *
+ * @return 批量操作行列请求的构建器
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * 批量操作行列请求的构建器
+ */
+ public static class Builder {
+ private final DimensionBatchUpdateRequest request;
+
+ public Builder() {
+ request = new DimensionBatchUpdateRequest();
+ }
+
+ /**
+ * 添加一个维度操作请求
+ *
+ * @param dimensionRequest 维度操作请求,如添加行列或插入行列
+ * @return 当前构建器
+ */
+ public Builder addRequest(DimensionRequest dimensionRequest) {
+ request.requests.add(dimensionRequest);
+ return this;
+ }
+
+ /**
+ * 构建批量操作行列请求
+ *
+ * @return 批量操作行列请求
+ */
+ public DimensionBatchUpdateRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 行列操作请求
+ */
+ public static class DimensionRequest {
+ private DimensionRange addDimension;
+ private InsertDimensionRange insertDimension;
+ private UpdateDimensionRange updateDimension;
+ private UpdateDimensionRange deleteDimension;
+ private DimensionProperties dimensionProperties;
+ private String inheritStyle;
+
+ /**
+ * 获取添加行列的维度范围
+ *
+ * @return 添加行列的维度范围
+ */
+ public DimensionRange getAddDimension() {
+ return addDimension;
+ }
+
+ /**
+ * 设置添加行列的维度范围
+ *
+ * @param addDimension 添加行列的维度范围
+ */
+ public void setAddDimension(DimensionRange addDimension) {
+ this.addDimension = addDimension;
+ }
+
+ /**
+ * 获取插入行列的维度范围
+ *
+ * @return 插入行列的维度范围
+ */
+ public InsertDimensionRange getInsertDimension() {
+ return insertDimension;
+ }
+
+ /**
+ * 设置插入行列的维度范围
+ *
+ * @param insertDimension 插入行列的维度范围
+ */
+ public void setInsertDimension(InsertDimensionRange insertDimension) {
+ this.insertDimension = insertDimension;
+ }
+
+ /**
+ * 获取更新行列的维度范围
+ *
+ * @return 更新行列的维度范围
+ */
+ public UpdateDimensionRange getUpdateDimension() {
+ return updateDimension;
+ }
+
+ /**
+ * 设置更新行列的维度范围
+ *
+ * @param updateDimension 更新行列的维度范围
+ */
+ public void setUpdateDimension(UpdateDimensionRange updateDimension) {
+ this.updateDimension = updateDimension;
+ }
+
+ /**
+ * 获取删除行列的维度范围
+ *
+ * @return 删除行列的维度范围
+ */
+ public UpdateDimensionRange getDeleteDimension() {
+ return deleteDimension;
+ }
+
+ /**
+ * 设置删除行列的维度范围
+ *
+ * @param deleteDimension 删除行列的维度范围
+ */
+ public void setDeleteDimension(UpdateDimensionRange deleteDimension) {
+ this.deleteDimension = deleteDimension;
+ }
+
+ /**
+ * 获取维度属性
+ *
+ * @return 维度属性
+ */
+ public DimensionProperties getDimensionProperties() {
+ return dimensionProperties;
+ }
+
+ /**
+ * 设置维度属性
+ *
+ * @param dimensionProperties 维度属性
+ */
+ public void setDimensionProperties(DimensionProperties dimensionProperties) {
+ this.dimensionProperties = dimensionProperties;
+ }
+
+ /**
+ * 获取继承样式方式
+ *
+ * @return 继承样式方式,可选值:BEFORE(继承前一行/列样式)、AFTER(继承后一行/列样式)
+ */
+ public String getInheritStyle() {
+ return inheritStyle;
+ }
+
+ /**
+ * 设置继承样式方式
+ *
+ * @param inheritStyle 继承样式方式,可选值:BEFORE(继承前一行/列样式)、AFTER(继承后一行/列样式)
+ */
+ public void setInheritStyle(String inheritStyle) {
+ this.inheritStyle = inheritStyle;
+ }
+
+ /**
+ * 创建添加行列的维度请求构建器 用于在工作表末尾增加指定数量的行或列
+ *
+ * @return 添加行列的构建器
+ */
+ public static AddDimensionBuilder addDimension() {
+ return new AddDimensionBuilder();
+ }
+
+ /**
+ * 创建插入行列的维度请求构建器 用于在工作表指定位置插入行或列
+ *
+ * @return 插入行列的构建器
+ */
+ public static InsertDimensionBuilder insertDimension() {
+ return new InsertDimensionBuilder();
+ }
+
+ /**
+ * 创建更新行列的维度请求构建器 用于更新行或列的属性(如可见性、大小等)
+ *
+ * @return 更新行列的构建器
+ */
+ public static UpdateDimensionBuilder updateDimension() {
+ return new UpdateDimensionBuilder();
+ }
+
+ /**
+ * 创建删除行列的维度请求构建器 用于构建删除指定范围行列的请求
+ *
+ * @return 删除行列的构建器
+ */
+ public static DeleteDimensionBuilder deleteDimension() {
+ return new DeleteDimensionBuilder();
+ }
+
+ /**
+ * 添加行列的构建器 用于构建添加行列的请求
+ */
+ public static class AddDimensionBuilder {
+ private final DimensionRequest request;
+ private final DimensionRange dimension;
+
+ public AddDimensionBuilder() {
+ request = new DimensionRequest();
+ dimension = new DimensionRange();
+ request.setAddDimension(dimension);
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ * @return 当前构建器
+ */
+ public AddDimensionBuilder sheetId(String sheetId) {
+ dimension.sheetId = sheetId;
+ return this;
+ }
+
+ /**
+ * 设置操作的维度类型
+ *
+ * @param majorDimension 维度类型,可选值:ROWS(行)、COLUMNS(列)
+ * @return 当前构建器
+ */
+ public AddDimensionBuilder majorDimension(String majorDimension) {
+ dimension.majorDimension = majorDimension;
+ return this;
+ }
+
+ /**
+ * 设置要添加的行数或列数
+ *
+ * @param length 要添加的数量,取值范围(0,5000]
+ * @return 当前构建器
+ */
+ public AddDimensionBuilder length(Integer length) {
+ dimension.length = length;
+ return this;
+ }
+
+ /**
+ * 构建添加行列请求
+ *
+ * @return 维度操作请求
+ */
+ public DimensionRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 插入行列的构建器 用于构建在指定位置插入行列的请求
+ */
+ public static class InsertDimensionBuilder {
+ private final DimensionRequest request;
+ private final InsertDimensionRange dimension;
+
+ public InsertDimensionBuilder() {
+ request = new DimensionRequest();
+ dimension = new InsertDimensionRange();
+ request.setInsertDimension(dimension);
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ * @return 当前构建器
+ */
+ public InsertDimensionBuilder sheetId(String sheetId) {
+ dimension.sheetId = sheetId;
+ return this;
+ }
+
+ /**
+ * 设置操作的维度类型
+ *
+ * @param majorDimension 维度类型,可选值:ROWS(行)、COLUMNS(列)
+ * @return 当前构建器
+ */
+ public InsertDimensionBuilder majorDimension(String majorDimension) {
+ dimension.majorDimension = majorDimension;
+ return this;
+ }
+
+ /**
+ * 设置插入的起始位置
+ *
+ * @param startIndex 起始位置索引,从0开始计数
+ * @return 当前构建器
+ */
+ public InsertDimensionBuilder startIndex(Integer startIndex) {
+ dimension.startIndex = startIndex;
+ return this;
+ }
+
+ /**
+ * 设置插入的结束位置
+ *
+ * @param endIndex 结束位置索引,从0开始计数
+ * @return 当前构建器
+ */
+ public InsertDimensionBuilder endIndex(Integer endIndex) {
+ dimension.endIndex = endIndex;
+ return this;
+ }
+
+ /**
+ * 设置是否继承样式
+ *
+ * @param inheritStyle 继承样式方式,可选值:BEFORE(继承前一行/列样式)、AFTER(继承后一行/列样式)
+ * @return 当前构建器
+ */
+ public InsertDimensionBuilder inheritStyle(String inheritStyle) {
+ request.inheritStyle = inheritStyle;
+ return this;
+ }
+
+ /**
+ * 构建插入行列请求
+ *
+ * @return 维度操作请求
+ */
+ public DimensionRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 更新行列的构建器 用于构建更新行列属性的请求
+ */
+ public static class UpdateDimensionBuilder {
+ private final DimensionRequest request;
+ private final UpdateDimensionRange dimension;
+ private final DimensionProperties properties;
+
+ public UpdateDimensionBuilder() {
+ request = new DimensionRequest();
+ dimension = new UpdateDimensionRange();
+ properties = new DimensionProperties();
+ request.setUpdateDimension(dimension);
+ request.setDimensionProperties(properties);
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ * @return 当前构建器
+ */
+ public UpdateDimensionBuilder sheetId(String sheetId) {
+ dimension.sheetId = sheetId;
+ return this;
+ }
+
+ /**
+ * 设置操作的维度类型
+ *
+ * @param majorDimension 维度类型,可选值:ROWS(行)、COLUMNS(列)
+ * @return 当前构建器
+ */
+ public UpdateDimensionBuilder majorDimension(String majorDimension) {
+ dimension.majorDimension = majorDimension;
+ return this;
+ }
+
+ /**
+ * 设置更新的起始位置
+ *
+ * @param startIndex 起始位置索引,从1开始计数
+ * @return 当前构建器
+ */
+ public UpdateDimensionBuilder startIndex(Integer startIndex) {
+ dimension.startIndex = startIndex;
+ return this;
+ }
+
+ /**
+ * 设置更新的结束位置
+ *
+ * @param endIndex 结束位置索引,从1开始计数
+ * @return 当前构建器
+ */
+ public UpdateDimensionBuilder endIndex(Integer endIndex) {
+ dimension.endIndex = endIndex;
+ return this;
+ }
+
+ /**
+ * 设置是否显示行或列
+ *
+ * @param visible true表示显示,false表示隐藏
+ * @return 当前构建器
+ */
+ public UpdateDimensionBuilder visible(Boolean visible) {
+ properties.visible = visible;
+ return this;
+ }
+
+ /**
+ * 设置行高或列宽
+ *
+ * @param fixedSize 行高或列宽,单位为像素,0表示隐藏
+ * @return 当前构建器
+ */
+ public UpdateDimensionBuilder fixedSize(Integer fixedSize) {
+ properties.fixedSize = fixedSize;
+ return this;
+ }
+
+ /**
+ * 构建更新行列请求
+ *
+ * @return 维度操作请求
+ */
+ public DimensionRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 删除行列的构建器 用于构建删除指定范围行列的请求
+ */
+ public static class DeleteDimensionBuilder {
+ private final DimensionRequest request;
+ private final UpdateDimensionRange dimension;
+
+ public DeleteDimensionBuilder() {
+ request = new DimensionRequest();
+ dimension = new UpdateDimensionRange();
+ request.setDeleteDimension(dimension);
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ * @return 当前构建器
+ */
+ public DeleteDimensionBuilder sheetId(String sheetId) {
+ dimension.sheetId = sheetId;
+ return this;
+ }
+
+ /**
+ * 设置操作的维度类型
+ *
+ * @param majorDimension 维度类型,可选值:ROWS(行)、COLUMNS(列)
+ * @return 当前构建器
+ */
+ public DeleteDimensionBuilder majorDimension(String majorDimension) {
+ dimension.majorDimension = majorDimension;
+ return this;
+ }
+
+ /**
+ * 设置删除的起始位置
+ *
+ * @param startIndex 起始位置索引,从1开始计数
+ * @return 当前构建器
+ */
+ public DeleteDimensionBuilder startIndex(Integer startIndex) {
+ dimension.startIndex = startIndex;
+ return this;
+ }
+
+ /**
+ * 设置删除的结束位置
+ *
+ * @param endIndex 结束位置索引,从1开始计数
+ * @return 当前构建器
+ */
+ public DeleteDimensionBuilder endIndex(Integer endIndex) {
+ dimension.endIndex = endIndex;
+ return this;
+ }
+
+ /**
+ * 构建删除行列请求
+ *
+ * @return 维度操作请求
+ */
+ public DimensionRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 添加行列维度范围
+ */
+ public static class DimensionRange {
+ /**
+ * 电子表格工作表的ID 必填字段
+ */
+ private String sheetId;
+
+ /**
+ * 更新的维度 必填字段 可选值: ROWS:行 COLUMNS:列
+ */
+ private String majorDimension;
+
+ /**
+ * 要增加的行数或列数 必填字段 取值范围为(0,5000]
+ */
+ private Integer length;
+
+ /**
+ * 获取工作表ID
+ *
+ * @return 工作表ID
+ */
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ */
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ /**
+ * 获取维度类型
+ *
+ * @return 维度类型,ROWS表示行,COLUMNS表示列
+ */
+ public String getMajorDimension() {
+ return majorDimension;
+ }
+
+ /**
+ * 设置维度类型
+ *
+ * @param majorDimension 维度类型,ROWS表示行,COLUMNS表示列
+ */
+ public void setMajorDimension(String majorDimension) {
+ this.majorDimension = majorDimension;
+ }
+
+ /**
+ * 获取要增加的行数或列数
+ *
+ * @return 行数或列数
+ */
+ public Integer getLength() {
+ return length;
+ }
+
+ /**
+ * 设置要增加的行数或列数
+ *
+ * @param length 行数或列数,取值范围(0,5000]
+ */
+ public void setLength(Integer length) {
+ this.length = length;
+ }
+ }
+
+ /**
+ * 插入维度范围
+ */
+ public static class InsertDimensionRange {
+ /**
+ * 电子表格工作表的ID 必填字段
+ */
+ private String sheetId;
+
+ /**
+ * 要更新的维度 必填字段 可选值: ROWS:行 COLUMNS:列
+ */
+ private String majorDimension;
+
+ /**
+ * 插入的行或列的起始位置 必填字段 从0开始计数 若startIndex为3,则从第4行或列开始插入空行或列 包含第4行或列
+ */
+ private Integer startIndex;
+
+ /**
+ * 插入的行或列结束的位置 必填字段 从0开始计数 若endIndex为7,则从第8行结束插入行 第8行不再插入空行
+ */
+ private Integer endIndex;
+
+ /**
+ * 获取工作表ID
+ *
+ * @return 工作表ID
+ */
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ */
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ /**
+ * 获取维度类型
+ *
+ * @return 维度类型,ROWS表示行,COLUMNS表示列
+ */
+ public String getMajorDimension() {
+ return majorDimension;
+ }
+
+ /**
+ * 设置维度类型
+ *
+ * @param majorDimension 维度类型,ROWS表示行,COLUMNS表示列
+ */
+ public void setMajorDimension(String majorDimension) {
+ this.majorDimension = majorDimension;
+ }
+
+ /**
+ * 获取插入的起始位置
+ *
+ * @return 起始位置索引
+ */
+ public Integer getStartIndex() {
+ return startIndex;
+ }
+
+ /**
+ * 设置插入的起始位置
+ *
+ * @param startIndex 起始位置索引,从0开始计数
+ */
+ public void setStartIndex(Integer startIndex) {
+ this.startIndex = startIndex;
+ }
+
+ /**
+ * 获取插入的结束位置
+ *
+ * @return 结束位置索引
+ */
+ public Integer getEndIndex() {
+ return endIndex;
+ }
+
+ /**
+ * 设置插入的结束位置
+ *
+ * @param endIndex 结束位置索引,从0开始计数
+ */
+ public void setEndIndex(Integer endIndex) {
+ this.endIndex = endIndex;
+ }
+ }
+
+ /**
+ * 更新维度范围
+ */
+ public static class UpdateDimensionRange {
+ /**
+ * 电子表格工作表的ID 必填字段
+ */
+ private String sheetId;
+
+ /**
+ * 要更新的维度 必填字段 可选值: ROWS:行 COLUMNS:列
+ */
+ private String majorDimension;
+
+ /**
+ * 要更新的行或列的起始位置 必填字段 从1开始计数 若startIndex为3,则从第3行或列开始更新属性 包含第3行或列
+ */
+ private Integer startIndex;
+
+ /**
+ * 要更新的行或列结束的位置 必填字段 从1开始计数 若endIndex为7,则更新至第7行结束 包含第7行
+ */
+ private Integer endIndex;
+
+ /**
+ * 获取工作表ID
+ *
+ * @return 工作表ID
+ */
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ */
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ /**
+ * 获取维度类型
+ *
+ * @return 维度类型,ROWS表示行,COLUMNS表示列
+ */
+ public String getMajorDimension() {
+ return majorDimension;
+ }
+
+ /**
+ * 设置维度类型
+ *
+ * @param majorDimension 维度类型,ROWS表示行,COLUMNS表示列
+ */
+ public void setMajorDimension(String majorDimension) {
+ this.majorDimension = majorDimension;
+ }
+
+ /**
+ * 获取更新的起始位置
+ *
+ * @return 起始位置索引
+ */
+ public Integer getStartIndex() {
+ return startIndex;
+ }
+
+ /**
+ * 设置更新的起始位置
+ *
+ * @param startIndex 起始位置索引,从1开始计数
+ */
+ public void setStartIndex(Integer startIndex) {
+ this.startIndex = startIndex;
+ }
+
+ /**
+ * 获取更新的结束位置
+ *
+ * @return 结束位置索引
+ */
+ public Integer getEndIndex() {
+ return endIndex;
+ }
+
+ /**
+ * 设置更新的结束位置
+ *
+ * @param endIndex 结束位置索引,从1开始计数
+ */
+ public void setEndIndex(Integer endIndex) {
+ this.endIndex = endIndex;
+ }
+ }
+
+ /**
+ * 维度属性
+ */
+ public static class DimensionProperties {
+ /**
+ * 是否显示行或列 可选值: true:显示行或列 false:隐藏行或列
+ */
+ private Boolean visible;
+
+ /**
+ * 行高或列宽 单位为像素 fixedSize为0时,等价于隐藏行或列
+ */
+ private Integer fixedSize;
+
+ /**
+ * 获取是否显示
+ *
+ * @return true表示显示,false表示隐藏
+ */
+ public Boolean getVisible() {
+ return visible;
+ }
+
+ /**
+ * 设置是否显示
+ *
+ * @param visible true表示显示,false表示隐藏
+ */
+ public void setVisible(Boolean visible) {
+ this.visible = visible;
+ }
+
+ /**
+ * 获取行高或列宽
+ *
+ * @return 行高或列宽,单位为像素
+ */
+ public Integer getFixedSize() {
+ return fixedSize;
+ }
+
+ /**
+ * 设置行高或列宽
+ *
+ * @param fixedSize 行高或列宽,单位为像素,0表示隐藏
+ */
+ public void setFixedSize(Integer fixedSize) {
+ this.fixedSize = fixedSize;
+ }
+ }
+
+ /**
+ * 添加行列请求体(用于API请求)
+ */
+ private static class AddDimensionRequestBody {
+ private final DimensionRange dimension;
+
+ /**
+ * 构造函数
+ *
+ * @param dimension 维度范围
+ */
+ public AddDimensionRequestBody(DimensionRange dimension) {
+ this.dimension = dimension;
+ }
+
+ /**
+ * 获取维度范围
+ *
+ * @return 维度范围
+ */
+ public DimensionRange getDimension() {
+ return dimension;
+ }
+ }
+
+ /**
+ * 插入行列请求体(用于API请求)
+ */
+ private static class InsertDimensionRequestBody {
+ private final InsertDimensionRange dimension;
+ private final String inheritStyle;
+
+ /**
+ * 构造函数
+ *
+ * @param dimension 维度范围
+ * @param inheritStyle 继承样式方式
+ */
+ public InsertDimensionRequestBody(InsertDimensionRange dimension, String inheritStyle) {
+ this.dimension = dimension;
+ this.inheritStyle = inheritStyle;
+ }
+
+ /**
+ * 获取维度范围
+ *
+ * @return 维度范围
+ */
+ public InsertDimensionRange getDimension() {
+ return dimension;
+ }
+
+ /**
+ * 获取继承样式方式
+ *
+ * @return 继承样式方式
+ */
+ public String getInheritStyle() {
+ return inheritStyle;
+ }
+ }
+
+ /**
+ * 更新行列请求体(用于API请求)
+ */
+ private static class UpdateDimensionRequestBody {
+ private final UpdateDimensionRange dimension;
+ private final DimensionProperties dimensionProperties;
+
+ /**
+ * 构造函数
+ *
+ * @param dimension 维度范围
+ * @param dimensionProperties 维度属性
+ */
+ public UpdateDimensionRequestBody(UpdateDimensionRange dimension, DimensionProperties dimensionProperties) {
+ this.dimension = dimension;
+ this.dimensionProperties = dimensionProperties;
+ }
+
+ /**
+ * 获取维度范围
+ *
+ * @return 维度范围
+ */
+ public UpdateDimensionRange getDimension() {
+ return dimension;
+ }
+
+ /**
+ * 获取维度属性
+ *
+ * @return 维度属性
+ */
+ public DimensionProperties getDimensionProperties() {
+ return dimensionProperties;
+ }
+ }
+
+ /**
+ * 删除行列请求体(用于API请求)
+ */
+ private static class DeleteDimensionRequestBody {
+ private final UpdateDimensionRange dimension;
+
+ /**
+ * 构造函数
+ *
+ * @param dimension 维度范围
+ */
+ public DeleteDimensionRequestBody(UpdateDimensionRange dimension) {
+ this.dimension = dimension;
+ }
+
+ /**
+ * 获取维度范围
+ *
+ * @return 维度范围
+ */
+ public UpdateDimensionRange getDimension() {
+ return dimension;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/service/CustomProtectedDimensionService.java b/src/main/java/cn/isliu/core/service/CustomProtectedDimensionService.java
new file mode 100644
index 0000000..d389cc9
--- /dev/null
+++ b/src/main/java/cn/isliu/core/service/CustomProtectedDimensionService.java
@@ -0,0 +1,453 @@
+package cn.isliu.core.service;
+
+import cn.isliu.core.client.FeishuApiClient;
+import cn.isliu.core.client.FeishuClient;
+import cn.isliu.core.pojo.ApiResponse;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 自定义保护范围服务 提供保护行列的API
+ */
+public class CustomProtectedDimensionService extends FeishuApiClient {
+
+ /**
+ * 构造函数
+ *
+ * @param feishuClient 飞书客户端
+ */
+ public CustomProtectedDimensionService(FeishuClient feishuClient) {
+ super(feishuClient);
+ }
+
+ /**
+ * 批量操作保护范围 支持添加保护范围 支持处理多个请求,如果有请求失败则中断后续请求
+ *
+ * @param spreadsheetToken 电子表格Token
+ * @param request 批量操作请求
+ * @return 批量操作响应
+ * @throws IOException 请求异常
+ */
+ public ApiResponse protectedDimensionBatchUpdate(String spreadsheetToken,
+ ProtectedDimensionBatchUpdateRequest request) throws IOException {
+ List requests = request.getRequests();
+ ApiResponse response = null;
+
+ // 如果没有请求,返回空响应
+ if (requests == null || requests.isEmpty()) {
+ ApiResponse emptyResponse = new ApiResponse();
+ emptyResponse.setCode(400);
+ emptyResponse.setMsg("No protected dimension operations found");
+ return emptyResponse;
+ }
+
+ // 依次处理每个请求
+ for (ProtectedDimensionRequest protectedDimensionRequest : requests) {
+ // 处理添加保护范围请求
+ if (protectedDimensionRequest.getAddProtectedDimension() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/protected_dimension";
+
+ // 构建添加保护范围请求体
+ RequestBody body = RequestBody.create(
+ gson.toJson(
+ new AddProtectedDimensionRequestBody(protectedDimensionRequest.getAddProtectedDimension())),
+ JSON_MEDIA_TYPE);
+
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 这里可以添加其他保护范围操作类型
+ }
+
+ // 如果所有请求都成功处理,返回最后一个成功的响应
+ // 如果没有处理任何请求(没有有效的操作类型),返回错误响应
+ if (response == null) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("No valid protected dimension operation found");
+ return errorResponse;
+ }
+
+ return response;
+ }
+
+ /**
+ * 批量操作保护范围请求
+ */
+ public static class ProtectedDimensionBatchUpdateRequest {
+ private List requests;
+
+ public ProtectedDimensionBatchUpdateRequest() {
+ this.requests = new ArrayList<>();
+ }
+
+ public List getRequests() {
+ return requests;
+ }
+
+ public void setRequests(List requests) {
+ this.requests = requests;
+ }
+
+ /**
+ * 创建批量操作保护范围请求的构建器
+ *
+ * @return 批量操作保护范围请求的构建器
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * 批量操作保护范围请求的构建器
+ */
+ public static class Builder {
+ private final ProtectedDimensionBatchUpdateRequest request;
+
+ public Builder() {
+ request = new ProtectedDimensionBatchUpdateRequest();
+ }
+
+ /**
+ * 添加一个保护范围操作请求
+ *
+ * @param protectedDimensionRequest 保护范围操作请求
+ * @return 当前构建器
+ */
+ public Builder addRequest(ProtectedDimensionRequest protectedDimensionRequest) {
+ request.requests.add(protectedDimensionRequest);
+ return this;
+ }
+
+ /**
+ * 构建批量操作保护范围请求
+ *
+ * @return 批量操作保护范围请求
+ */
+ public ProtectedDimensionBatchUpdateRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 保护范围操作请求
+ */
+ public static class ProtectedDimensionRequest {
+ private List addProtectedDimension;
+
+ /**
+ * 获取添加保护范围的信息
+ *
+ * @return 添加保护范围的信息
+ */
+ public List getAddProtectedDimension() {
+ return addProtectedDimension;
+ }
+
+ /**
+ * 设置添加保护范围的信息
+ *
+ * @param addProtectedDimension 添加保护范围的信息
+ */
+ public void setAddProtectedDimension(List addProtectedDimension) {
+ this.addProtectedDimension = addProtectedDimension;
+ }
+
+ /**
+ * 创建添加保护范围构建器
+ *
+ * @return 添加保护范围构建器
+ */
+ public static AddProtectedDimensionBuilder addProtectedDimension() {
+ return new AddProtectedDimensionBuilder();
+ }
+
+ /**
+ * 添加保护范围构建器
+ */
+ public static class AddProtectedDimensionBuilder {
+ private final ProtectedDimensionRequest request;
+ private final AddProtectedDimensionRange protectedDimension;
+
+ public AddProtectedDimensionBuilder() {
+ request = new ProtectedDimensionRequest();
+ protectedDimension = new AddProtectedDimensionRange();
+
+ List list = new ArrayList<>();
+ list.add(protectedDimension);
+ request.setAddProtectedDimension(list);
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ * @return 当前构建器
+ */
+ public AddProtectedDimensionBuilder sheetId(String sheetId) {
+ protectedDimension.getDimension().setSheetId(sheetId);
+ return this;
+ }
+
+ /**
+ * 设置维度方向
+ *
+ * @param majorDimension 维度方向,可选值:ROWS(行)、COLUMNS(列)
+ * @return 当前构建器
+ */
+ public AddProtectedDimensionBuilder majorDimension(String majorDimension) {
+ protectedDimension.getDimension().setMajorDimension(majorDimension);
+ return this;
+ }
+
+ /**
+ * 设置开始索引
+ *
+ * @param startIndex 开始索引,从1开始计数
+ * @return 当前构建器
+ */
+ public AddProtectedDimensionBuilder startIndex(Integer startIndex) {
+ protectedDimension.getDimension().setStartIndex(startIndex);
+ return this;
+ }
+
+ /**
+ * 设置结束索引
+ *
+ * @param endIndex 结束索引,从1开始计数
+ * @return 当前构建器
+ */
+ public AddProtectedDimensionBuilder endIndex(Integer endIndex) {
+ protectedDimension.getDimension().setEndIndex(endIndex);
+ return this;
+ }
+
+ /**
+ * 添加一个允许编辑的用户ID
+ *
+ * @param userId 用户ID
+ * @return 当前构建器
+ */
+ public AddProtectedDimensionBuilder addUser(String userId) {
+ protectedDimension.getUsers().add(userId);
+ return this;
+ }
+
+ /**
+ * 设置多个允许编辑的用户ID
+ *
+ * @param userIds 用户ID列表
+ * @return 当前构建器
+ */
+ public AddProtectedDimensionBuilder users(List userIds) {
+ protectedDimension.setUsers(userIds);
+ return this;
+ }
+
+ /**
+ * 设置保护范围的备注信息
+ *
+ * @param lockInfo 备注信息
+ * @return 当前构建器
+ */
+ public AddProtectedDimensionBuilder lockInfo(String lockInfo) {
+ protectedDimension.setLockInfo(lockInfo);
+ return this;
+ }
+
+ /**
+ * 构建保护范围请求
+ *
+ * @return 保护范围请求
+ */
+ public ProtectedDimensionRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 添加保护范围信息
+ */
+ public static class AddProtectedDimensionRange {
+ private DimensionRange dimension;
+ private List users;
+ private String lockInfo;
+
+ public AddProtectedDimensionRange() {
+ this.dimension = new DimensionRange();
+ this.users = new ArrayList<>();
+ }
+
+ /**
+ * 获取维度范围
+ *
+ * @return 维度范围
+ */
+ public DimensionRange getDimension() {
+ return dimension;
+ }
+
+ /**
+ * 设置维度范围
+ *
+ * @param dimension 维度范围
+ */
+ public void setDimension(DimensionRange dimension) {
+ this.dimension = dimension;
+ }
+
+ /**
+ * 获取允许编辑的用户ID列表
+ *
+ * @return 用户ID列表
+ */
+ public List getUsers() {
+ return users;
+ }
+
+ /**
+ * 设置允许编辑的用户ID列表
+ *
+ * @param users 用户ID列表
+ */
+ public void setUsers(List users) {
+ this.users = users;
+ }
+
+ /**
+ * 获取保护范围的备注信息
+ *
+ * @return 备注信息
+ */
+ public String getLockInfo() {
+ return lockInfo;
+ }
+
+ /**
+ * 设置保护范围的备注信息
+ *
+ * @param lockInfo 备注信息
+ */
+ public void setLockInfo(String lockInfo) {
+ this.lockInfo = lockInfo;
+ }
+ }
+
+ /**
+ * 维度范围
+ */
+ public static class DimensionRange {
+ private String sheetId;
+ private String majorDimension;
+ private Integer startIndex;
+ private Integer endIndex;
+
+ /**
+ * 获取工作表ID
+ *
+ * @return 工作表ID
+ */
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ /**
+ * 设置工作表ID
+ *
+ * @param sheetId 工作表ID
+ */
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ /**
+ * 获取维度方向
+ *
+ * @return 维度方向,ROWS(行)或COLUMNS(列)
+ */
+ public String getMajorDimension() {
+ return majorDimension;
+ }
+
+ /**
+ * 设置维度方向
+ *
+ * @param majorDimension 维度方向,ROWS(行)或COLUMNS(列)
+ */
+ public void setMajorDimension(String majorDimension) {
+ this.majorDimension = majorDimension;
+ }
+
+ /**
+ * 获取开始索引
+ *
+ * @return 开始索引,从1开始计数
+ */
+ public Integer getStartIndex() {
+ return startIndex;
+ }
+
+ /**
+ * 设置开始索引
+ *
+ * @param startIndex 开始索引,从1开始计数
+ */
+ public void setStartIndex(Integer startIndex) {
+ this.startIndex = startIndex;
+ }
+
+ /**
+ * 获取结束索引
+ *
+ * @return 结束索引,从1开始计数
+ */
+ public Integer getEndIndex() {
+ return endIndex;
+ }
+
+ /**
+ * 设置结束索引
+ *
+ * @param endIndex 结束索引,从1开始计数
+ */
+ public void setEndIndex(Integer endIndex) {
+ this.endIndex = endIndex;
+ }
+ }
+
+ /**
+ * 添加保护范围请求体
+ */
+ private static class AddProtectedDimensionRequestBody {
+ private final List addProtectedDimension;
+
+ /**
+ * 构造函数
+ *
+ * @param addProtectedDimension 添加保护范围信息列表
+ */
+ public AddProtectedDimensionRequestBody(List addProtectedDimension) {
+ this.addProtectedDimension = addProtectedDimension;
+ }
+
+ /**
+ * 获取添加保护范围信息列表
+ *
+ * @return 添加保护范围信息列表
+ */
+ public List getAddProtectedDimension() {
+ return addProtectedDimension;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/service/CustomSheetService.java b/src/main/java/cn/isliu/core/service/CustomSheetService.java
new file mode 100644
index 0000000..33d8c8c
--- /dev/null
+++ b/src/main/java/cn/isliu/core/service/CustomSheetService.java
@@ -0,0 +1,870 @@
+package cn.isliu.core.service;
+
+import cn.isliu.core.client.FeishuApiClient;
+import cn.isliu.core.client.FeishuClient;
+import cn.isliu.core.pojo.ApiResponse;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 自定义表格服务 提供官方SDK未覆盖的表格API
+ */
+public class CustomSheetService extends FeishuApiClient {
+
+ /**
+ * 构造函数
+ *
+ * @param feishuClient 飞书客户端
+ */
+ public CustomSheetService(FeishuClient feishuClient) {
+ super(feishuClient);
+ }
+
+ /**
+ * 批量更新工作表 支持添加、复制、删除等操作
+ *
+ * @param spreadsheetToken 电子表格Token
+ * @param request 批量更新请求
+ * @return 批量更新响应
+ * @throws IOException 请求异常
+ */
+ public ApiResponse sheetsBatchUpdate(String spreadsheetToken, SheetBatchUpdateRequest request)
+ throws IOException {
+ List requests = request.getRequests();
+ // 更新工作表特殊字段兼容
+ String userIdType = null;
+ for (SheetRequest sheetRequest : requests) {
+ UpdateSheetRequest updateSheet = sheetRequest.getUpdateSheet();
+ if (updateSheet != null) {
+ SheetPropertiesUpdate properties = updateSheet.getProperties();
+ userIdType = properties.getUserIdType();
+ break;
+ }
+ }
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/sheets_batch_update";
+ if (userIdType != null && !userIdType.isEmpty()) {
+ url += "?user_id_type=" + userIdType;
+ }
+
+ RequestBody body = RequestBody.create(gson.toJson(request), JSON_MEDIA_TYPE);
+
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ return executeRequest(httpRequest, ApiResponse.class);
+ }
+
+ /**
+ * 批量更新工作表请求
+ */
+ public static class SheetBatchUpdateRequest {
+ /**
+ * 支持增加、复制、删除和更新工作表 一次请求可以同时进行多个操作
+ */
+ private List requests;
+
+ public SheetBatchUpdateRequest() {
+ this.requests = new ArrayList<>();
+ }
+
+ public List getRequests() {
+ return requests;
+ }
+
+ public void setRequests(List requests) {
+ this.requests = requests;
+ }
+
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private final SheetBatchUpdateRequest request;
+
+ public Builder() {
+ request = new SheetBatchUpdateRequest();
+ }
+
+ public Builder addRequest(SheetRequest sheetRequest) {
+ request.requests.add(sheetRequest);
+ return this;
+ }
+
+ public SheetBatchUpdateRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 工作表请求
+ */
+ public static class SheetRequest {
+ /**
+ * 增加工作表操作
+ */
+ private AddSheetRequest addSheet;
+
+ /**
+ * 复制工作表操作
+ */
+ private CopySheetRequest copySheet;
+
+ /**
+ * 删除工作表操作
+ */
+ private DeleteSheetRequest deleteSheet;
+
+ /**
+ * 更新工作表操作
+ */
+ private UpdateSheetRequest updateSheet;
+
+ public AddSheetRequest getAddSheet() {
+ return addSheet;
+ }
+
+ public void setAddSheet(AddSheetRequest addSheet) {
+ this.addSheet = addSheet;
+ }
+
+ public CopySheetRequest getCopySheet() {
+ return copySheet;
+ }
+
+ public void setCopySheet(CopySheetRequest copySheet) {
+ this.copySheet = copySheet;
+ }
+
+ public DeleteSheetRequest getDeleteSheet() {
+ return deleteSheet;
+ }
+
+ public void setDeleteSheet(DeleteSheetRequest deleteSheet) {
+ this.deleteSheet = deleteSheet;
+ }
+
+ public UpdateSheetRequest getUpdateSheet() {
+ return updateSheet;
+ }
+
+ public void setUpdateSheet(UpdateSheetRequest updateSheet) {
+ this.updateSheet = updateSheet;
+ }
+
+ /**
+ * 创建添加工作表的请求构建器 用于在电子表格中添加新的工作表
+ *
+ * @return 添加工作表的构建器
+ */
+ public static AddSheetBuilder addSheet() {
+ return new AddSheetBuilder();
+ }
+
+ /**
+ * 创建复制工作表的请求构建器 用于复制已有的工作表到同一电子表格中
+ *
+ * @return 复制工作表的构建器
+ */
+ public static CopySheetBuilder copySheet() {
+ return new CopySheetBuilder();
+ }
+
+ /**
+ * 创建删除工作表的请求构建器 用于删除电子表格中的指定工作表
+ *
+ * @return 删除工作表的构建器
+ */
+ public static DeleteSheetBuilder deleteSheet() {
+ return new DeleteSheetBuilder();
+ }
+
+ /**
+ * 创建更新工作表的请求构建器 用于更新工作表的标题、位置、显示状态、冻结行列、保护设置等属性
+ *
+ * @return 更新工作表的构建器
+ */
+ public static UpdateSheetBuilder updateSheet() {
+ return new UpdateSheetBuilder();
+ }
+
+ /**
+ * 添加工作表的构建器 用于构建添加新工作表的请求
+ */
+ public static class AddSheetBuilder {
+ private final SheetRequest request;
+ private final AddSheetRequest addSheet;
+
+ public AddSheetBuilder() {
+ request = new SheetRequest();
+ addSheet = new AddSheetRequest();
+ request.setAddSheet(addSheet);
+ }
+
+ /**
+ * 获取或初始化properties对象
+ *
+ * @return properties对象
+ */
+ private SheetProperties getProperties() {
+ if (addSheet.properties == null) {
+ addSheet.properties = new SheetProperties();
+ }
+ return addSheet.properties;
+ }
+
+ /**
+ * 设置工作表标题
+ *
+ * @param title 工作表标题,不能包含特殊字符:/ \ ? * [ ] :
+ * @return 当前构建器
+ */
+ public AddSheetBuilder title(String title) {
+ getProperties().title = title;
+ return this;
+ }
+
+ /**
+ * 设置工作表在电子表格中的位置索引
+ *
+ * @param index 位置索引,从0开始计数,不填默认在第0位置添加
+ * @return 当前构建器
+ */
+ public AddSheetBuilder index(Integer index) {
+ getProperties().index = index;
+ return this;
+ }
+
+ /**
+ * 构建添加工作表请求
+ *
+ * @return 工作表操作请求
+ */
+ public SheetRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 复制工作表的构建器 用于构建复制现有工作表的请求
+ */
+ public static class CopySheetBuilder {
+ private final SheetRequest request;
+ private final CopySheetRequest copySheet;
+
+ public CopySheetBuilder() {
+ request = new SheetRequest();
+ copySheet = new CopySheetRequest();
+ request.setCopySheet(copySheet);
+ }
+
+ /**
+ * 获取或初始化source对象
+ *
+ * @return source对象
+ */
+ private SheetSource getSource() {
+ if (copySheet.source == null) {
+ copySheet.source = new SheetSource();
+ }
+ return copySheet.source;
+ }
+
+ /**
+ * 获取或初始化destination对象
+ *
+ * @return destination对象
+ */
+ private SheetDestination getDestination() {
+ if (copySheet.destination == null) {
+ copySheet.destination = new SheetDestination();
+ }
+ return copySheet.destination;
+ }
+
+ /**
+ * 设置源工作表ID
+ *
+ * @param sheetId 要复制的源工作表ID
+ * @return 当前构建器
+ */
+ public CopySheetBuilder sourceSheetId(String sheetId) {
+ getSource().sheetId = sheetId;
+ return this;
+ }
+
+ /**
+ * 设置目标工作表标题
+ *
+ * @param title 复制后的工作表标题,不填则默认为"源工作表名称(副本_源工作表的index值)"
+ * @return 当前构建器
+ */
+ public CopySheetBuilder destinationTitle(String title) {
+ getDestination().title = title;
+ return this;
+ }
+
+ /**
+ * 构建复制工作表请求
+ *
+ * @return 工作表操作请求
+ */
+ public SheetRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 删除工作表的构建器 用于构建删除工作表的请求
+ */
+ public static class DeleteSheetBuilder {
+ private final SheetRequest request;
+ private final DeleteSheetRequest deleteSheet;
+
+ public DeleteSheetBuilder() {
+ request = new SheetRequest();
+ deleteSheet = new DeleteSheetRequest();
+ request.setDeleteSheet(deleteSheet);
+ }
+
+ /**
+ * 设置要删除的工作表ID
+ *
+ * @param sheetId 要删除的工作表ID
+ * @return 当前构建器
+ */
+ public DeleteSheetBuilder sheetId(String sheetId) {
+ deleteSheet.sheetId = sheetId;
+ return this;
+ }
+
+ /**
+ * 构建删除工作表请求
+ *
+ * @return 工作表操作请求
+ */
+ public SheetRequest build() {
+ return request;
+ }
+ }
+
+ /**
+ * 更新工作表的构建器 用于构建更新工作表属性的请求
+ */
+ public static class UpdateSheetBuilder {
+ private final SheetRequest request;
+ private final UpdateSheetRequest updateSheet;
+
+ public UpdateSheetBuilder() {
+ request = new SheetRequest();
+ updateSheet = new UpdateSheetRequest();
+ request.setUpdateSheet(updateSheet);
+ }
+
+ /**
+ * 获取或初始化properties对象
+ *
+ * @return properties对象
+ */
+ private SheetPropertiesUpdate getProperties() {
+ if (updateSheet.properties == null) {
+ updateSheet.properties = new SheetPropertiesUpdate();
+ }
+ return updateSheet.properties;
+ }
+
+ /**
+ * 设置要更新的工作表ID
+ *
+ * @param sheetId 工作表ID
+ * @return 当前构建器
+ */
+ public UpdateSheetBuilder sheetId(String sheetId) {
+ getProperties().sheetId = sheetId;
+ return this;
+ }
+
+ /**
+ * 设置工作表标题
+ *
+ * @param title 工作表标题,不能包含特殊字符:/ \ ? * [ ] :
+ * @return 当前构建器
+ */
+ public UpdateSheetBuilder title(String title) {
+ getProperties().title = title;
+ return this;
+ }
+
+ /**
+ * 设置工作表在电子表格中的位置索引
+ *
+ * @param index 位置索引,从0开始计数
+ * @return 当前构建器
+ */
+ public UpdateSheetBuilder index(Integer index) {
+ getProperties().index = index;
+ return this;
+ }
+
+ /**
+ * 设置工作表是否隐藏
+ *
+ * @param hidden true表示隐藏,false表示显示
+ * @return 当前构建器
+ */
+ public UpdateSheetBuilder hidden(Boolean hidden) {
+ getProperties().hidden = hidden;
+ return this;
+ }
+
+ /**
+ * 设置冻结行数
+ *
+ * @param frozenRowCount 冻结的行数,0表示取消冻结
+ * @return 当前构建器
+ */
+ public UpdateSheetBuilder frozenRowCount(Integer frozenRowCount) {
+ getProperties().frozenRowCount = frozenRowCount;
+ return this;
+ }
+
+ /**
+ * 设置冻结列数
+ *
+ * @param frozenColCount 冻结的列数,0表示取消冻结
+ * @return 当前构建器
+ */
+ public UpdateSheetBuilder frozenColCount(Integer frozenColCount) {
+ getProperties().frozenColCount = frozenColCount;
+ return this;
+ }
+
+ /**
+ * 设置用户ID类型
+ *
+ * @param userIdType 用户ID类型,建议使用open_id或union_id,可选值:open_id、union_id
+ * @return 当前构建器
+ */
+ public UpdateSheetBuilder userIdType(String userIdType) {
+ getProperties().userIdType = userIdType;
+ return this;
+ }
+
+ /**
+ * 设置工作表保护
+ *
+ * @param lock 是否要保护该工作表,可选值:LOCK(保护)、UNLOCK(取消保护)
+ * @param lockInfo 保护工作表的备注信息
+ * @param userIDs 有编辑权限的用户ID列表
+ * @return 当前构建器
+ */
+ public UpdateSheetBuilder protect(String lock, String lockInfo, List userIDs) {
+ SheetPropertiesUpdate properties = getProperties();
+ if (properties.protect == null) {
+ properties.protect = new SheetProtect();
+ }
+ properties.protect.lock = lock;
+ properties.protect.lockInfo = lockInfo;
+ properties.protect.userIDs = userIDs;
+ return this;
+ }
+
+ /**
+ * 构建更新工作表请求
+ *
+ * @return 工作表操作请求
+ */
+ public SheetRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 添加工作表请求
+ */
+ public static class AddSheetRequest {
+ /**
+ * 工作表属性
+ */
+ private SheetProperties properties;
+
+ public SheetProperties getProperties() {
+ return properties;
+ }
+
+ public void setProperties(SheetProperties properties) {
+ this.properties = properties;
+ }
+ }
+
+ /**
+ * 工作表属性
+ */
+ public static class SheetProperties {
+ /**
+ * 新增工作表的标题 必填字段
+ */
+ private String title;
+
+ /**
+ * 新增工作表的位置 不填默认在工作表的第0索引位置增加工作表
+ */
+ private Integer index;
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public Integer getIndex() {
+ return index;
+ }
+
+ public void setIndex(Integer index) {
+ this.index = index;
+ }
+ }
+
+ /**
+ * 复制工作表请求
+ */
+ public static class CopySheetRequest {
+ /**
+ * 需要复制的工作表资源
+ */
+ private SheetSource source;
+
+ /**
+ * 新工作表的属性
+ */
+ private SheetDestination destination;
+
+ public SheetSource getSource() {
+ return source;
+ }
+
+ public void setSource(SheetSource source) {
+ this.source = source;
+ }
+
+ public SheetDestination getDestination() {
+ return destination;
+ }
+
+ public void setDestination(SheetDestination destination) {
+ this.destination = destination;
+ }
+ }
+
+ /**
+ * 工作表源
+ */
+ public static class SheetSource {
+ /**
+ * 源工作表的ID 必填字段
+ */
+ private String sheetId;
+
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+ }
+
+ /**
+ * 工作表目标
+ */
+ public static class SheetDestination {
+ /**
+ * 新工作表名称 不填默认为"源工作表名称"+"(副本_源工作表的index值)",如"Sheet1(副本_0)"
+ */
+ private String title;
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+ }
+
+ /**
+ * 删除工作表请求
+ */
+ public static class DeleteSheetRequest {
+ /**
+ * 要删除的工作表的ID 必填字段
+ */
+ private String sheetId;
+
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+ }
+
+ /**
+ * 更新工作表请求
+ */
+ public static class UpdateSheetRequest {
+ /**
+ * 工作表属性
+ */
+ private SheetPropertiesUpdate properties;
+
+ public SheetPropertiesUpdate getProperties() {
+ return properties;
+ }
+
+ public void setProperties(SheetPropertiesUpdate properties) {
+ this.properties = properties;
+ }
+ }
+
+ /**
+ * 工作表属性更新
+ */
+ public static class SheetPropertiesUpdate {
+ /**
+ * 要更新的工作表的ID 必填字段
+ */
+ private String sheetId;
+
+ /**
+ * 工作表的标题 更新的标题需符合以下规则: 长度不超过100个字符 不包含这些特殊字符:/ \ ? * [ ] :
+ */
+ private String title;
+
+ /**
+ * 工作表的位置 从0开始计数
+ */
+ private Integer index;
+
+ /**
+ * 是否要隐藏表格 默认值为false
+ */
+ private Boolean hidden;
+
+ /**
+ * 要冻结至指定行的行索引 若填3,表示从第一行冻结至第三行 小于或等于工作表的最大行数,0表示取消冻结行
+ */
+ private Integer frozenRowCount;
+
+ /**
+ * 要冻结至指定列的列索引 若填3,表示从第一列冻结至第三列 小于等于工作表的最大列数,0表示取消冻结列
+ */
+ private Integer frozenColCount;
+
+ /**
+ * 工作表保护设置
+ */
+ private SheetProtect protect;
+
+ /**
+ * 用户ID类型 影响protect.userIDs字段的ID类型 用户 ID 类型。默认为 lark_id,建议选择 open_id 或 union_id。了解更多,参考用户身份概述。可选值:
+ * open_id:标识一个用户在某个应用中的身份。同一个用户在不同应用中的 Open ID 不同。 union_id:标识一个用户在某个应用开发商下的身份。同一用户在同一开发商下的应用中的 Union ID
+ * 是相同的,在不同开发商下的应用中的 Union ID 是不同的。通过 Union ID,应用开发商可以把同个用户在多个应用中的身份关联起来。
+ */
+ private String userIdType;
+
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public Integer getIndex() {
+ return index;
+ }
+
+ public void setIndex(Integer index) {
+ this.index = index;
+ }
+
+ public Boolean getHidden() {
+ return hidden;
+ }
+
+ public void setHidden(Boolean hidden) {
+ this.hidden = hidden;
+ }
+
+ public Integer getFrozenRowCount() {
+ return frozenRowCount;
+ }
+
+ public void setFrozenRowCount(Integer frozenRowCount) {
+ this.frozenRowCount = frozenRowCount;
+ }
+
+ public Integer getFrozenColCount() {
+ return frozenColCount;
+ }
+
+ public void setFrozenColCount(Integer frozenColCount) {
+ this.frozenColCount = frozenColCount;
+ }
+
+ public SheetProtect getProtect() {
+ return protect;
+ }
+
+ public void setProtect(SheetProtect protect) {
+ this.protect = protect;
+ }
+
+ public String getUserIdType() {
+ return userIdType;
+ }
+
+ public void setUserIdType(String userIdType) {
+ this.userIdType = userIdType;
+ }
+ }
+
+ /**
+ * 工作表保护设置
+ */
+ public static class SheetProtect {
+ /**
+ * 是否要保护该工作表 必填字段 可选值: LOCK:保护 UNLOCK:取消保护
+ */
+ private String lock;
+
+ /**
+ * 保护工作表的备注信息
+ */
+ private String lockInfo;
+
+ /**
+ * 添加除操作用户与所有者外其他用户的ID 为其开通保护范围的编辑权限 ID类型由查询参数user_id_type决定 user_id_type不为空时,该字段生效
+ */
+ private List userIDs;
+
+ public String getLock() {
+ return lock;
+ }
+
+ public void setLock(String lock) {
+ this.lock = lock;
+ }
+
+ public String getLockInfo() {
+ return lockInfo;
+ }
+
+ public void setLockInfo(String lockInfo) {
+ this.lockInfo = lockInfo;
+ }
+
+ public List getUserIDs() {
+ return userIDs;
+ }
+
+ public void setUserIDs(List userIDs) {
+ this.userIDs = userIDs;
+ }
+ }
+
+ /**
+ * 工作表
+ */
+ public static class Sheet {
+ private String sheetId;
+ private String title;
+ private Integer index;
+ private Integer rowCount;
+ private Integer columnCount;
+ private Boolean hidden;
+ private Integer frozenRowCount;
+ private Integer frozenColCount;
+
+ public String getSheetId() {
+ return sheetId;
+ }
+
+ public void setSheetId(String sheetId) {
+ this.sheetId = sheetId;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public Integer getIndex() {
+ return index;
+ }
+
+ public void setIndex(Integer index) {
+ this.index = index;
+ }
+
+ public Integer getRowCount() {
+ return rowCount;
+ }
+
+ public void setRowCount(Integer rowCount) {
+ this.rowCount = rowCount;
+ }
+
+ public Integer getColumnCount() {
+ return columnCount;
+ }
+
+ public void setColumnCount(Integer columnCount) {
+ this.columnCount = columnCount;
+ }
+
+ public Boolean getHidden() {
+ return hidden;
+ }
+
+ public void setHidden(Boolean hidden) {
+ this.hidden = hidden;
+ }
+
+ public Integer getFrozenRowCount() {
+ return frozenRowCount;
+ }
+
+ public void setFrozenRowCount(Integer frozenRowCount) {
+ this.frozenRowCount = frozenRowCount;
+ }
+
+ public Integer getFrozenColCount() {
+ return frozenColCount;
+ }
+
+ public void setFrozenColCount(Integer frozenColCount) {
+ this.frozenColCount = frozenColCount;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/isliu/core/service/CustomValueService.java b/src/main/java/cn/isliu/core/service/CustomValueService.java
new file mode 100644
index 0000000..5f9ea05
--- /dev/null
+++ b/src/main/java/cn/isliu/core/service/CustomValueService.java
@@ -0,0 +1,1672 @@
+package cn.isliu.core.service;
+
+import cn.isliu.core.client.FeishuApiClient;
+import cn.isliu.core.client.FeishuClient;
+import cn.isliu.core.pojo.ApiResponse;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 自定义数据值服务 提供官方SDK未覆盖的数据操作API
+ */
+public class CustomValueService extends FeishuApiClient {
+
+ /**
+ * 构造函数
+ *
+ * @param feishuClient 飞书客户端
+ */
+ public CustomValueService(FeishuClient feishuClient) {
+ super(feishuClient);
+ }
+
+ /**
+ * 批量操作数据值 支持在指定范围前插入数据、在指定范围后追加数据等操作
+ *
+ * @param spreadsheetToken 电子表格Token
+ * @param request 批量操作请求
+ * @return 批量操作响应
+ * @throws IOException 请求异常
+ */
+ public ApiResponse valueBatchUpdate(String spreadsheetToken, ValueBatchUpdateRequest request) throws IOException {
+ List requests = request.getRequests();
+ ApiResponse response = null;
+
+ // 如果没有请求,返回空响应
+ if (requests == null || requests.isEmpty()) {
+ ApiResponse emptyResponse = new ApiResponse();
+ emptyResponse.setCode(400);
+ emptyResponse.setMsg("No value operations found");
+ return emptyResponse;
+ }
+
+ // 依次处理每个请求
+ for (ValueRequest valueRequest : requests) {
+ // 处理在指定范围前插入数据请求
+ if (valueRequest.getPrependValues() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/values_prepend";
+
+ RequestBody body = RequestBody.create(gson.toJson(valueRequest.getPrependValues()), JSON_MEDIA_TYPE);
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理在指定范围后追加数据请求
+ else if (valueRequest.getAppendValues() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/values_append";
+
+ // 添加insertDataOption参数
+ String insertDataOption = valueRequest.getAppendValues().getInsertDataOption();
+ if (insertDataOption != null && !insertDataOption.isEmpty()) {
+ url += "?insertDataOption=" + insertDataOption;
+ }
+
+ RequestBody body = RequestBody.create(gson.toJson(valueRequest.getAppendValues()), JSON_MEDIA_TYPE);
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理写入图片请求
+ else if (valueRequest.getImageValues() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/values_image";
+
+ RequestBody body = RequestBody.create(gson.toJson(valueRequest.getImageValues()), JSON_MEDIA_TYPE);
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理获取单个范围请求
+ else if (valueRequest.getGetValues() != null) {
+ ValueGetRequest getValues = valueRequest.getGetValues();
+ String baseUrl =
+ BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/values/" + getValues.getRange();
+
+ // 构建查询参数
+ StringBuilder urlBuilder = new StringBuilder(baseUrl);
+ boolean hasParam = false;
+
+ // 添加valueRenderOption参数
+ if (getValues.getValueRenderOption() != null && !getValues.getValueRenderOption().isEmpty()) {
+ urlBuilder.append(hasParam ? "&" : "?").append("valueRenderOption=")
+ .append(URLEncoder.encode(getValues.getValueRenderOption(), StandardCharsets.UTF_8.toString()));
+ hasParam = true;
+ }
+
+ // 添加dateTimeRenderOption参数
+ if (getValues.getDateTimeRenderOption() != null && !getValues.getDateTimeRenderOption().isEmpty()) {
+ urlBuilder.append(hasParam ? "&" : "?").append("dateTimeRenderOption=").append(
+ URLEncoder.encode(getValues.getDateTimeRenderOption(), StandardCharsets.UTF_8.toString()));
+ hasParam = true;
+ }
+
+ // 添加user_id_type参数
+ if (getValues.getUserIdType() != null && !getValues.getUserIdType().isEmpty()) {
+ urlBuilder.append(hasParam ? "&" : "?").append("user_id_type=")
+ .append(URLEncoder.encode(getValues.getUserIdType(), StandardCharsets.UTF_8.toString()));
+ }
+
+ String url = urlBuilder.toString();
+ Request httpRequest = createAuthenticatedRequest(url, "GET", null).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理批量获取多个范围请求
+ else if (valueRequest.getBatchGetValues() != null) {
+ ValueBatchGetRequest batchGetValues = valueRequest.getBatchGetValues();
+
+ // 检查ranges是否为空
+ if (batchGetValues.getRanges() == null || batchGetValues.getRanges().isEmpty()) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("Ranges cannot be empty for batch get values");
+ return errorResponse;
+ }
+
+ // 构建ranges参数,使用逗号分隔
+ StringBuilder rangesBuilder = new StringBuilder();
+ for (int i = 0; i < batchGetValues.getRanges().size(); i++) {
+ if (i > 0) {
+ rangesBuilder.append(",");
+ }
+ rangesBuilder.append(batchGetValues.getRanges().get(i));
+ }
+
+ // 构建基本URL
+ String baseUrl = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/values_batch_get";
+
+ // 构建查询参数
+ StringBuilder urlBuilder = new StringBuilder(baseUrl);
+ urlBuilder.append("?ranges=")
+ .append(URLEncoder.encode(rangesBuilder.toString(), StandardCharsets.UTF_8.toString()));
+
+ // 添加valueRenderOption参数
+ if (batchGetValues.getValueRenderOption() != null && !batchGetValues.getValueRenderOption().isEmpty()) {
+ urlBuilder.append("&valueRenderOption=").append(
+ URLEncoder.encode(batchGetValues.getValueRenderOption(), StandardCharsets.UTF_8.toString()));
+ }
+
+ // 添加dateTimeRenderOption参数
+ if (batchGetValues.getDateTimeRenderOption() != null
+ && !batchGetValues.getDateTimeRenderOption().isEmpty()) {
+ urlBuilder.append("&dateTimeRenderOption=").append(
+ URLEncoder.encode(batchGetValues.getDateTimeRenderOption(), StandardCharsets.UTF_8.toString()));
+ }
+
+ // 添加user_id_type参数
+ if (batchGetValues.getUserIdType() != null && !batchGetValues.getUserIdType().isEmpty()) {
+ urlBuilder.append("&user_id_type=")
+ .append(URLEncoder.encode(batchGetValues.getUserIdType(), StandardCharsets.UTF_8.toString()));
+ }
+
+ String url = urlBuilder.toString();
+ Request httpRequest = createAuthenticatedRequest(url, "GET", null).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理向单个范围写入数据请求
+ else if (valueRequest.getPutValues() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/values";
+
+ RequestBody body = RequestBody.create(gson.toJson(valueRequest.getPutValues()), JSON_MEDIA_TYPE);
+ Request httpRequest = createAuthenticatedRequest(url, "PUT", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 处理向多个范围写入数据请求
+ else if (valueRequest.getBatchPutValues() != null) {
+ String url = BASE_URL + "/sheets/v2/spreadsheets/" + spreadsheetToken + "/values_batch_update";
+ String params = gson.toJson(valueRequest.getBatchPutValues());
+ RequestBody body = RequestBody.create(params, JSON_MEDIA_TYPE);
+ Request httpRequest = createAuthenticatedRequest(url, "POST", body).build();
+ response = executeRequest(httpRequest, ApiResponse.class);
+
+ // 如果请求失败,中断后续请求
+ if (!response.success()) {
+ return response;
+ }
+ }
+ // 这里可以添加其他数据操作类型
+ }
+
+ // 如果所有请求都成功处理,返回最后一个成功的响应
+ // 如果没有处理任何请求(没有有效的操作类型),返回错误响应
+ if (response == null) {
+ ApiResponse errorResponse = new ApiResponse();
+ errorResponse.setCode(400);
+ errorResponse.setMsg("No valid value operation found");
+ return errorResponse;
+ }
+
+ return response;
+ }
+
+ /**
+ * 批量操作数据值请求
+ */
+ public static class ValueBatchUpdateRequest {
+ private List requests;
+
+ public ValueBatchUpdateRequest() {
+ this.requests = new ArrayList<>();
+ }
+
+ public List getRequests() {
+ return requests;
+ }
+
+ public void setRequests(List requests) {
+ this.requests = requests;
+ }
+
+ /**
+ * 创建批量操作数据值请求的构建器
+ *
+ * @return 批量操作数据值请求的构建器
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * 批量操作数据值请求的构建器
+ */
+ public static class Builder {
+ private final ValueBatchUpdateRequest request;
+
+ public Builder() {
+ request = new ValueBatchUpdateRequest();
+ }
+
+ /**
+ * 添加一个数据值操作请求
+ *
+ * @param valueRequest 数据值操作请求
+ * @return 当前构建器
+ */
+ public Builder addRequest(ValueRequest valueRequest) {
+ request.requests.add(valueRequest);
+ return this;
+ }
+
+ /**
+ * 构建批量操作数据值请求
+ *
+ * @return 批量操作数据值请求
+ */
+ public ValueBatchUpdateRequest build() {
+ return request;
+ }
+ }
+ }
+
+ /**
+ * 数据值操作请求
+ */
+ public static class ValueRequest {
+ private ValuePrependRequest prependValues;
+ private ValueAppendRequest appendValues;
+ private ValueImageRequest imageValues;
+ private ValueGetRequest getValues;
+ private ValueBatchGetRequest batchGetValues;
+ private ValuePutRequest putValues;
+ private ValueBatchUpdatePutRequest batchPutValues;
+
+ /**
+ * 获取在指定范围前插入数据请求
+ *
+ * @return 在指定范围前插入数据请求
+ */
+ public ValuePrependRequest getPrependValues() {
+ return prependValues;
+ }
+
+ /**
+ * 设置在指定范围前插入数据请求
+ *
+ * @param prependValues 在指定范围前插入数据请求
+ */
+ public void setPrependValues(ValuePrependRequest prependValues) {
+ this.prependValues = prependValues;
+ }
+
+ /**
+ * 获取在指定范围后追加数据请求
+ *
+ * @return 在指定范围后追加数据请求
+ */
+ public ValueAppendRequest getAppendValues() {
+ return appendValues;
+ }
+
+ /**
+ * 设置在指定范围后追加数据请求
+ *
+ * @param appendValues 在指定范围后追加数据请求
+ */
+ public void setAppendValues(ValueAppendRequest appendValues) {
+ this.appendValues = appendValues;
+ }
+
+ /**
+ * 获取写入图片请求
+ *
+ * @return 写入图片请求
+ */
+ public ValueImageRequest getImageValues() {
+ return imageValues;
+ }
+
+ /**
+ * 设置写入图片请求
+ *
+ * @param imageValues 写入图片请求
+ */
+ public void setImageValues(ValueImageRequest imageValues) {
+ this.imageValues = imageValues;
+ }
+
+ /**
+ * 获取单个范围数据请求
+ *
+ * @return 获取单个范围数据请求
+ */
+ public ValueGetRequest getGetValues() {
+ return getValues;
+ }
+
+ /**
+ * 设置获取单个范围数据请求
+ *
+ * @param getValues 获取单个范围数据请求
+ */
+ public void setGetValues(ValueGetRequest getValues) {
+ this.getValues = getValues;
+ }
+
+ /**
+ * 获取批量获取多个范围数据请求
+ *
+ * @return 批量获取多个范围数据请求
+ */
+ public ValueBatchGetRequest getBatchGetValues() {
+ return batchGetValues;
+ }
+
+ /**
+ * 设置批量获取多个范围数据请求
+ *
+ * @param batchGetValues 批量获取多个范围数据请求
+ */
+ public void setBatchGetValues(ValueBatchGetRequest batchGetValues) {
+ this.batchGetValues = batchGetValues;
+ }
+
+ /**
+ * 获取向单个范围写入数据请求
+ *
+ * @return 向单个范围写入数据请求
+ */
+ public ValuePutRequest getPutValues() {
+ return putValues;
+ }
+
+ /**
+ * 设置向单个范围写入数据请求
+ *
+ * @param putValues 向单个范围写入数据请求
+ */
+ public void setPutValues(ValuePutRequest putValues) {
+ this.putValues = putValues;
+ }
+
+ /**
+ * 获取向多个范围写入数据请求
+ *
+ * @return 向多个范围写入数据请求
+ */
+ public ValueBatchUpdatePutRequest getBatchPutValues() {
+ return batchPutValues;
+ }
+
+ /**
+ * 设置向多个范围写入数据请求
+ *
+ * @param batchPutValues 向多个范围写入数据请求
+ */
+ public void setBatchPutValues(ValueBatchUpdatePutRequest batchPutValues) {
+ this.batchPutValues = batchPutValues;
+ }
+
+ /**
+ * 创建在指定范围前插入数据的请求构建器
+ *
+ * @return 在指定范围前插入数据的构建器
+ */
+ public static PrependValuesBuilder prependValues() {
+ return new PrependValuesBuilder();
+ }
+
+ /**
+ * 创建在指定范围后追加数据的请求构建器
+ *
+ * @return 在指定范围后追加数据的构建器
+ */
+ public static AppendValuesBuilder appendValues() {
+ return new AppendValuesBuilder();
+ }
+
+ /**
+ * 创建写入图片的请求构建器
+ *
+ * @return 写入图片的构建器
+ */
+ public static ImageValuesBuilder imageValues() {
+ return new ImageValuesBuilder();
+ }
+
+ /**
+ * 创建获取单个范围数据的请求构建器
+ *
+ * @return 获取单个范围数据的构建器
+ */
+ public static GetValuesBuilder getValues() {
+ return new GetValuesBuilder();
+ }
+
+ /**
+ * 创建批量获取多个范围数据的请求构建器
+ *
+ * @return 批量获取多个范围数据的构建器
+ */
+ public static BatchGetValuesBuilder batchGetValues() {
+ return new BatchGetValuesBuilder();
+ }
+
+ /**
+ * 创建向单个范围写入数据的请求构建器
+ *
+ * @return 向单个范围写入数据的构建器
+ */
+ public static PutValuesBuilder putValues() {
+ return new PutValuesBuilder();
+ }
+
+ /**
+ * 创建向多个范围写入数据的请求构建器
+ *
+ * @return 向多个范围写入数据的构建器
+ */
+ public static BatchPutValuesBuilder batchPutValues() {
+ return new BatchPutValuesBuilder();
+ }
+
+ /**
+ * 在指定范围前插入数据的构建器
+ */
+ public static class PrependValuesBuilder {
+ private final ValueRequest request;
+ private final ValuePrependRequest prependValues;
+ private final ValueRange valueRange;
+
+ public PrependValuesBuilder() {
+ request = new ValueRequest();
+ prependValues = new ValuePrependRequest();
+ valueRange = new ValueRange();
+ prependValues.setValueRange(valueRange);
+ request.setPrependValues(prependValues);
+ }
+
+ /**
+ * 设置要插入数据的单元格范围
+ *
+ * @param range 单元格范围,格式为 !<开始位置>:<结束位置>
+ * @return 当前构建器
+ */
+ public PrependValuesBuilder range(String range) {
+ valueRange.setRange(range);
+ return this;
+ }
+
+ /**
+ * 设置要插入数据的单元格范围
+ *
+ * @param sheetId 工作表ID
+ * @param startPosition 开始位置
+ * @param endPosition 结束位置
+ * @return 当前构建器
+ */
+ public PrependValuesBuilder range(String sheetId, String startPosition, String endPosition) {
+ valueRange.setRange(sheetId + "!" + startPosition + ":" + endPosition);
+ return this;
+ }
+
+ /**
+ * 添加一行数据
+ *
+ * @param rowData 行数据
+ * @return 当前构建器
+ */
+ public PrependValuesBuilder addRow(List | | | |