feat(电子表格): init

This commit is contained in:
wisonic-s
2026-03-26 23:18:11 +08:00
committed by wisonic-s
parent 379fba7590
commit cca757c53b
15 changed files with 508 additions and 5 deletions

View File

@@ -113,6 +113,8 @@ public class MenuManage {
|| coreMenu.getId().equals(65L)
|| coreMenu.getId().equals(80L)
|| coreMenu.getId().equals(90L)
|| coreMenu.getPid().equals(70L);
|| coreMenu.getPid().equals(70L)
|| coreMenu.getId().equals(100L)
|| coreMenu.getId().equals(110L);
}
}

View File

@@ -36,6 +36,7 @@ i18n_menu.sysVariable=System Variables
i18n_menu.sysTypeface=Font Management
i18n_menu.font=Font Management
i18n_menu.msg-fill=Reporting Task
i18n_menu.spreadsheet=Spreadsheet
i18n_field_name_repeat=Duplicate field name:
i18n_pid_not_eq_id=The target for moving cannot be itself or its subdirectory
i18n_ds_name_exists=Name is duplicated under this group

View File

@@ -35,6 +35,7 @@ i18n_menu.sysVariable=\u7CFB\u7EDF\u53D8\u91CF
i18n_menu.sysTypeface=\u5B57\u4F53\u7BA1\u7406
i18n_menu.font=\u5B57\u4F53\u7BA1\u7406
i18n_menu.msg-fill=\u586B\u62A5\u4EFB\u52A1
i18n_menu.spreadsheet=\u7535\u5B50\u8868\u683C
i18n_field_name_repeat=\u6709\u91CD\u590D\u5B57\u6BB5\u540D\uFF1A
i18n_pid_not_eq_id=\u79FB\u52A8\u76EE\u6807\u4E0D\u80FD\u662F\u81EA\u5DF1\u6216\u5B50\u76EE\u5F55
i18n_ds_name_exists=\u8BE5\u5206\u7EC4\u4E0B\u540D\u79F0\u91CD\u590D

View File

@@ -35,6 +35,7 @@ i18n_menu.sysVariable=\u7CFB\u7D71\u8B8A\u91CF
i18n_menu.sysTypeface=\u5B57\u9AD4\u7BA1\u7406
i18n_menu.font=\u5B57\u9AD4\u7BA1\u7406
i18n_menu.msg-fill=\u586B\u5831\u4EFB\u52D9
i18n_menu.spreadsheet=\u96FB\u5B50\u8868\u683C
i18n_field_name_repeat=\u6709\u91CD\u5FA9\u5B57\u6BB5\u540D\uFF1A
i18n_pid_not_eq_id=\u79FB\u52D5\u76EE\u6A19\u4E0D\u80FD\u662F\u81EA\u5DF1\u6216\u5B50\u76EE\u9304
i18n_ds_name_exists=\u8A72\u5206\u7D44\u4E0B\u540D\u7A31\u91CD\u5FA9

View File

@@ -3234,7 +3234,7 @@ export default {
selected_view: 'Selected View',
used_dataset: 'Used Dataset',
to_select_view: 'Select View',
to_select_view: 'Select Field',
to_select_field: 'Select Field',
show_selected_only: 'Show Selected Only',
same_dataset: 'Same Dataset',
diff_dataset: 'Different Dataset',
@@ -4792,5 +4792,84 @@ export default {
content_type: 'Content Type',
del_confirm: 'Are you sure you want to delete this Webhook?',
batch_del_confirm: 'Are you sure you want to delete {0} Webhooks?'
},
spreadsheet: {
title: 'Spreadsheet',
new_folder: 'New Folder',
new_sheet: 'New Spreadsheet',
new_spreadsheet: 'New Spreadsheet',
edit_sheet: 'Edit Spreadsheet',
save: 'Save',
save_success: 'Saved successfully',
delete_success: 'Deleted successfully',
name_placeholder: 'Please enter name',
name_required: 'Name is required',
dataset_binding: 'Dataset Binding',
bind_dataset: 'Bind Dataset',
unbind_dataset: 'Unbind Dataset',
unbind_confirm: 'Are you sure to unbind this dataset?',
refresh_dataset: 'Refresh Data',
refresh_type: 'Refresh Type',
manual_refresh: 'Manual Refresh',
auto_refresh: 'Auto Refresh',
refresh_freq: 'Refresh Frequency',
range_config: 'Fill Range',
sheet_name: 'Sheet Name',
version_history: 'Version History',
publish: 'Publish',
unpublish: 'Unpublish',
published: 'Published',
unpublished: 'Unpublished',
preview: 'Preview',
export: 'Export',
share: 'Share',
copy: 'Copy',
move: 'Move',
rename: 'Rename',
delete: 'Delete',
delete_confirm: 'Are you sure to delete this spreadsheet?',
delete_folder_confirm:
'After deletion, all resources under this folder will be deleted, please proceed with caution.',
save_before_leave: 'Do you want to save before leaving?',
unsaved_changes: 'There are unsaved changes',
loading: 'Loading...',
no_data: 'No data',
save_first: 'Please save the spreadsheet first',
back: 'Back',
discard: 'Discard',
load_error: 'Failed to load',
save_error: 'Failed to save',
update_success: 'Updated successfully',
update_error: 'Failed to update',
select_required: 'Please select a dataset',
tips: 'Tips',
coming_soon: 'Feature coming soon',
toolbar: {
undo: 'Undo',
redo: 'Redo',
bold: 'Bold',
italic: 'Italic',
underline: 'Underline',
strikethrough: 'Strikethrough',
font_color: 'Font Color',
background_color: 'Background Color',
border: 'Border',
merge_cell: 'Merge Cells',
align_left: 'Align Left',
align_center: 'Center',
align_right: 'Align Right',
wrap_text: 'Wrap Text',
insert_row: 'Insert Row',
insert_column: 'Insert Column',
delete_row: 'Delete Row',
delete_column: 'Delete Column',
freeze: 'Freeze',
filter: 'Filter',
sort: 'Sort',
formula: 'Formula',
chart: 'Chart',
image: 'Image',
link: 'Link'
}
}
}

View File

@@ -4643,5 +4643,82 @@ export default {
content_type: '內容類型',
del_confirm: '確定刪除該 Webhook嗎',
batch_del_confirm: '確定刪除 {0} 個 Webhook嗎'
},
spreadsheet: {
title: '電子表格',
new_folder: '新建文件夾',
new_sheet: '新建表格',
new_spreadsheet: '新建電子表格',
edit_sheet: '編輯表格',
save: '保存',
save_success: '保存成功',
delete_success: '刪除成功',
name_placeholder: '請輸入名稱',
name_required: '名稱不能為空',
dataset_binding: '資料集綁定',
bind_dataset: '綁定資料集',
unbind_dataset: '解綁資料集',
refresh_dataset: '刷新資料',
refresh_type: '刷新方式',
manual_refresh: '手動刷新',
auto_refresh: '自動刷新',
refresh_freq: '刷新頻率',
range_config: '填充範圍',
sheet_name: '工作表名稱',
version_history: '版本歷史',
publish: '發布',
unpublish: '取消發布',
published: '已發布',
unpublished: '未發布',
preview: '預覽',
export: '匯出',
share: '分享',
copy: '複製',
move: '移動',
rename: '重命名',
delete: '刪除',
delete_confirm: '確定刪除該表格嗎?',
delete_folder_confirm: '刪除後,此文件夾下的所有資源都會被刪除,請謹慎操作。',
save_before_leave: '離開前是否保存?',
unsaved_changes: '有未保存的更改',
loading: '加載中...',
no_data: '暫無資料',
save_first: '請先保存表格',
back: '返回',
discard: '不保存',
load_error: '加載失敗',
save_error: '保存失敗',
update_success: '更新成功',
update_error: '更新失敗',
select_required: '請選擇資料集',
tips: '提示',
coming_soon: '功能開發中,敬請期待',
toolbar: {
undo: '撤銷',
redo: '重做',
bold: '加粗',
italic: '斜體',
underline: '下劃線',
strikethrough: '刪除線',
font_color: '字體顏色',
background_color: '背景顏色',
border: '邊框',
merge_cell: '合併儲存格',
align_left: '左對齊',
align_center: '居中',
align_right: '右對齊',
wrap_text: '自動換行',
insert_row: '插入行',
insert_column: '插入列',
delete_row: '刪除行',
delete_column: '刪除列',
freeze: '凍結',
filter: '篩選',
sort: '排序',
formula: '公式',
chart: '圖表',
image: '圖片',
link: '連結'
}
}
}

View File

@@ -4648,5 +4648,83 @@ export default {
content_type: '内容类型',
del_confirm: '确定删除该 Webhook吗',
batch_del_confirm: '确定删除 {0} 个 Webhook吗'
},
spreadsheet: {
title: '电子表格',
new_folder: '新建文件夹',
new_sheet: '新建表格',
new_spreadsheet: '新建电子表格',
edit_sheet: '编辑表格',
save: '保存',
save_success: '保存成功',
delete_success: '删除成功',
name_placeholder: '请输入名称',
name_required: '名称不能为空',
dataset_binding: '数据集绑定',
bind_dataset: '绑定数据集',
unbind_dataset: '解绑数据集',
unbind_confirm: '确定解绑该数据集吗?',
refresh_dataset: '刷新数据',
refresh_type: '刷新方式',
manual_refresh: '手动刷新',
auto_refresh: '自动刷新',
refresh_freq: '刷新频率',
range_config: '填充范围',
sheet_name: '工作表名称',
version_history: '版本历史',
publish: '发布',
unpublish: '取消发布',
published: '已发布',
unpublished: '未发布',
preview: '预览',
export: '导出',
share: '分享',
copy: '复制',
move: '移动',
rename: '重命名',
delete: '删除',
delete_confirm: '确定删除该表格吗?',
delete_folder_confirm: '删除后,此文件夹下的所有资源都会被删除,请谨慎操作。',
save_before_leave: '离开前是否保存?',
unsaved_changes: '有未保存的更改',
loading: '加载中...',
no_data: '暂无数据',
save_first: '请先保存表格',
back: '返回',
discard: '不保存',
load_error: '加载失败',
save_error: '保存失败',
update_success: '更新成功',
update_error: '更新失败',
select_required: '请选择数据集',
tips: '提示',
coming_soon: '功能开发中,敬请期待',
toolbar: {
undo: '撤销',
redo: '重做',
bold: '加粗',
italic: '斜体',
underline: '下划线',
strikethrough: '删除线',
font_color: '字体颜色',
background_color: '背景颜色',
border: '边框',
merge_cell: '合并单元格',
align_left: '左对齐',
align_center: '居中',
align_right: '右对齐',
wrap_text: '自动换行',
insert_row: '插入行',
insert_column: '插入列',
delete_row: '删除行',
delete_column: '删除列',
freeze: '冻结',
filter: '筛选',
sort: '排序',
formula: '公式',
chart: '图表',
image: '图片',
link: '链接'
}
}
}

View File

@@ -0,0 +1,66 @@
package io.dataease.api.spreadsheet;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.dataease.api.spreadsheet.dto.SpreadsheetCreator;
import io.dataease.api.spreadsheet.dto.SpreadsheetEditor;
import io.dataease.api.spreadsheet.vo.SpreadsheetTreeVO;
import io.dataease.api.spreadsheet.vo.SpreadsheetVO;
import io.dataease.auth.DeApiPath;
import io.dataease.auth.DePermit;
import io.dataease.model.BusiNodeRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
import static io.dataease.constant.AuthResourceEnum.SPREADSHEET;
@Tag(name = "电子表格管理")
@ApiSupport(order = 969)
@DeApiPath(value = "/spreadsheet", rt = SPREADSHEET)
public interface SpreadsheetApi {
@Operation(summary = "创建文件夹")
@DePermit({"#p0.pid+':create'"})
@PostMapping("/createFolder")
SpreadsheetVO createFolder(@RequestBody SpreadsheetCreator creator);
@Operation(summary = "保存电子表格(创建/编辑)")
@PostMapping("/save")
SpreadsheetVO save(@RequestBody SpreadsheetEditor editor);
@Operation(summary = "获取电子表格详情")
@PostMapping("/findById")
SpreadsheetVO findById(@RequestBody SpreadsheetEditor request);
@Operation(summary = "获取资源树")
@PostMapping("/tree")
List<SpreadsheetTreeVO> tree(@RequestBody BusiNodeRequest request);
@Operation(summary = "移动资源")
@DePermit({"#p0.id+':manage'", "#p0.pid+':create'"})
@PostMapping("/move")
void move(@RequestBody SpreadsheetEditor editor);
@Operation(summary = "重命名")
@DePermit({"#p0.id+':manage'"})
@PostMapping("/rename")
void rename(@RequestBody SpreadsheetEditor editor);
@Operation(summary = "删除资源")
@DePermit({"#p0+':delete'"})
@PostMapping("/delete/{id}")
void delete(@PathVariable("id") Long id);
@Operation(summary = "名称检查")
@PostMapping("/nameCheck")
boolean nameCheck(@RequestBody SpreadsheetEditor editor);
@Operation(summary = "更新发布状态")
@PostMapping("/updateStatus")
void updateStatus(@RequestBody SpreadsheetEditor editor);
}

View File

@@ -0,0 +1,30 @@
package io.dataease.api.spreadsheet.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Schema(description = "电子表格创建DTO")
@Data
public class SpreadsheetCreator implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "ID")
private Long id;
@Schema(description = "名称")
private String name;
@Schema(description = "父目录ID")
private Long pid;
@Schema(description = "节点类型: folder/sheet")
private String nodeType;
@Schema(description = "所属组织ID")
private Long orgId;
}

View File

@@ -0,0 +1,43 @@
package io.dataease.api.spreadsheet.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Schema(description = "电子表格编辑DTO")
@Data
public class SpreadsheetEditor implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "ID")
private Long id;
@Schema(description = "名称")
private String name;
@Schema(description = "父目录ID")
private Long pid;
@Schema(description = "节点类型: folder/sheet")
private String nodeType;
@Schema(description = "所属组织ID")
private Long orgId;
@Schema(description = "Univer数据模型JSON")
private String sheetData;
@Schema(description = "版本号")
private Integer version;
@Schema(description = "状态: 0-未发布, 1-已发布")
private Integer status;
@Schema(description = "备注")
private String remark;
}

View File

@@ -0,0 +1,52 @@
package io.dataease.api.spreadsheet.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.dataease.model.TreeResultModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Schema(description = "电子表格树节点VO")
@Data
public class SpreadsheetTreeVO implements Serializable, TreeResultModel<SpreadsheetTreeVO> {
@Serial
private static final long serialVersionUID = 1L;
@JsonSerialize(using = ToStringSerializer.class)
@Schema(description = "ID")
private Long id;
@Schema(description = "名称")
private String name;
@Schema(description = "父目录ID")
private Long pid;
@Schema(description = "节点类型: folder/sheet")
private String nodeType;
@Schema(description = "是否叶子节点")
private Boolean leaf;
@Schema(description = "层级")
private Integer level;
@Schema(description = "状态: 0-未发布, 1-已发布")
private Integer status;
@Schema(description = "创建时间")
private Long createTime;
@Schema(description = "子节点")
private List<SpreadsheetTreeVO> children;
@Override
public void setChildren(List<SpreadsheetTreeVO> children) {
this.children = children;
}
}

View File

@@ -0,0 +1,72 @@
package io.dataease.api.spreadsheet.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Schema(description = "电子表格VO")
@Data
public class SpreadsheetVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@JsonSerialize(using = ToStringSerializer.class)
@Schema(description = "ID")
private Long id;
@Schema(description = "名称")
private String name;
@Schema(description = "父目录ID")
private Long pid;
@Schema(description = "节点类型: folder/sheet")
private String nodeType;
@Schema(description = "所属组织ID")
private Long orgId;
@Schema(description = "层级")
private Integer level;
@Schema(description = "Univer数据模型JSON")
private String sheetData;
@Schema(description = "版本号")
private Integer version;
@Schema(description = "状态: 0-未发布, 1-已发布")
private Integer status;
@Schema(description = "排序")
private Integer sort;
@Schema(description = "创建时间")
private Long createTime;
@Schema(description = "创建人")
private String createBy;
@Schema(description = "创建人姓名")
private String creator;
@Schema(description = "更新时间")
private Long updateTime;
@Schema(description = "更新人")
private String updateBy;
@Schema(description = "更新人姓名")
private String updater;
@Schema(description = "备注")
private String remark;
@Schema(description = "是否收藏")
private Boolean favorite;
}

View File

@@ -2,7 +2,7 @@ package io.dataease.constant;
public enum AuthResourceEnum {
PANEL(2, 1), SCREEN(3, 2), DATASET(5, 3), DATASOURCE(6, 4), SYSTEM(7, 0), USER(8, 5), ROLE(8, 6), ORG(9, 7), SYNC_DATASOURCE(23, 9), TASK(24, 9), SUMMARY(22, 9), DATA_FILLING(60, 8);
PANEL(2, 1), SCREEN(3, 2), DATASET(5, 3), DATASOURCE(6, 4), SYSTEM(7, 0), USER(8, 5), ROLE(8, 6), ORG(9, 7), SYNC_DATASOURCE(23, 9), TASK(24, 9), SUMMARY(22, 9), DATA_FILLING(60, 8), SPREADSHEET(100L, 10);
private long menuId;

View File

@@ -2,7 +2,7 @@ package io.dataease.constant;
public enum BusiResourceEnum {
PANEL(1), SCREEN(2), DATASET(3), DATASOURCE(4), DATA_FILLING(8);
PANEL(1), SCREEN(2), DATASET(3), DATASOURCE(4), DATA_FILLING(8), SPREADSHEET(10);
private int flag;

View File

@@ -17,7 +17,8 @@ public enum LogST {
MENU(12, "SOURCE_TYPE_MENU"),
APIKEY(13, "SOURCE_TYPE_APIKEY"),
DATA_FILLING(14, "SOURCE_TYPE_DATAFILLING"),
DATA(15, "SOURCE_TYPE_DATA");
DATA(15, "SOURCE_TYPE_DATA"),
SPREADSHEET(16, "SOURCE_TYPE_SPREADSHEET");
private Integer value;
private String name;