Skip to content

Commit ac2ac31

Browse files
feat(UniverSheet): add UniverSheet component (#5463)
* feat: 增加 UniverSheet 菜单 * doc: 增加示例组件 * doc: 增加多语言支持 * doc: 增加插件示例 * chore: 增加源码映射 * chore: 增加 UniverSheet 工程 * feat: 交互测试 * refactor: 增加测试逻辑 * refactor: 更改方法名 * refactor: 数据服务名称参数化 * refactor: 修改案例 * refactor: 更改 report 目录为 univer-sheet * refactor: 精简代码 * refactor: 增加数据服务模块 * refactor: 更改方法名称 * chore: 更新示例 * refactor: 增加测试数据 * doc: 增加多语言资源文件 * doc: 更新推送数据示例 * doc: 更新示例 * doc: 增加多语言资源文件 * chore: 更新依赖 --------- Co-authored-by: zhaijunlei <[email protected]>
1 parent 82d4186 commit ac2ac31

File tree

11 files changed

+310
-6
lines changed

11 files changed

+310
-6
lines changed

src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@
3838
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.0.2" />
3939
<PackageReference Include="BootstrapBlazor.Gantt" Version="9.0.2" />
4040
<PackageReference Include="BootstrapBlazor.Holiday" Version="9.0.1" />
41-
<PackageReference Include="BootstrapBlazor.Html2Image" Version="9.0.0-beta02" />
41+
<PackageReference Include="BootstrapBlazor.Html2Image" Version="9.0.0" />
4242
<PackageReference Include="BootstrapBlazor.Html2Pdf" Version="9.0.2" />
4343
<PackageReference Include="BootstrapBlazor.IconPark" Version="9.0.2" />
4444
<PackageReference Include="BootstrapBlazor.ImageCropper" Version="9.0.0" />
4545
<PackageReference Include="BootstrapBlazor.IP2Region" Version="9.0.1" />
46-
<PackageReference Include="BootstrapBlazor.JuHeIpLocatorProvider" Version="9.0.0-beta01" />
46+
<PackageReference Include="BootstrapBlazor.JuHeIpLocatorProvider" Version="9.0.0" />
4747
<PackageReference Include="BootstrapBlazor.Live2DDisplay" Version="9.0.1" />
4848
<PackageReference Include="BootstrapBlazor.Markdown" Version="9.0.1" />
4949
<PackageReference Include="BootstrapBlazor.MaterialDesign" Version="9.0.1" />
@@ -64,6 +64,7 @@
6464
<PackageReference Include="BootstrapBlazor.SummerNote" Version="9.0.3" />
6565
<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.1" />
6666
<PackageReference Include="BootstrapBlazor.Topology" Version="9.0.0" />
67+
<PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.0-beta01" />
6768
<PackageReference Include="BootstrapBlazor.VideoPlayer" Version="9.0.3" />
6869
<PackageReference Include="BootstrapBlazor.WinBox" Version="9.0.7" />
6970
</ItemGroup>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
@page "/univer-sheet"
2+
@inherits WebSiteModuleComponentBase
3+
@attribute [JSModuleAutoLoader("Samples/UniverSheets.razor.js")]
4+
5+
<h3>@Localizer["UniverSheetTitle"]</h3>
6+
7+
<h4>@Localizer["UniverSheetIntro"]</h4>
8+
9+
<PackageTips Name="BootstrapBlazor.UniverSheet" />
10+
11+
<DemoBlock Title="@Localizer["NormalTitle"]"
12+
Introduction="@Localizer["NormalIntro"]"
13+
Name="Normal">
14+
<section ignore>
15+
<p>@((MarkupString)Localizer["NormalDesc1"].Value)</p>
16+
<Button OnClickWithoutRender="OnPushExcelData" Text="@Localizer["PushButtonText"]"></Button>
17+
</section>
18+
<div class="bb-sheet-demo">
19+
<UniverSheet @ref="_sheetExcel" OnReadyAsync="OnReadyAsync"></UniverSheet>
20+
</div>
21+
</DemoBlock>
22+
23+
<DemoBlock Title="@Localizer["PluginTitle"]"
24+
Introduction="@Localizer["PluginIntro"]"
25+
Name="Plugin">
26+
<section ignore>
27+
<p>@((MarkupString)Localizer["NormalDesc2"].Value)</p>
28+
<Button OnClickWithoutRender="OnPushPluginData" Text="@Localizer["PushButtonText"]"></Button>
29+
</section>
30+
<div class="bb-sheet-demo">
31+
<UniverSheet @ref="_sheetPlugin" Plugins="Plugins" OnPostDataAsync="OnPostDataAsync"></UniverSheet>
32+
</div>
33+
</DemoBlock>
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License
3+
// See the LICENSE file in the project root for more information.
4+
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
5+
6+
namespace BootstrapBlazor.Server.Components.Samples;
7+
8+
/// <summary>
9+
/// UniverSheet 组件示例代码
10+
/// </summary>
11+
public partial class UniverSheets
12+
{
13+
[Inject, NotNull]
14+
private ToastService? ToastService { get; set; }
15+
16+
[Inject, NotNull]
17+
private IStringLocalizer<UniverSheets>? Localizer { get; set; }
18+
19+
private readonly Dictionary<string, string> Plugins = new()
20+
{
21+
{ "ReportPlugin", "univer-sheet/plugin.js" }
22+
};
23+
24+
private UniverSheet _sheetExcel = default!;
25+
26+
private UniverSheet _sheetPlugin = default!;
27+
28+
private async Task OnReadyAsync() => await ToastService.Information(Localizer["ToastOnReadyTitle"], Localizer["ToastOnReadyContent"]);
29+
30+
private static Task<UniverSheetData?> OnPostDataAsync(UniverSheetData data)
31+
{
32+
// 这里可以根据 data 的内容进行处理然后返回处理后的数据
33+
// 本例返回与时间相关的数据
34+
var result = new UniverSheetData()
35+
{
36+
MessageName = data.MessageName,
37+
CommandName = data.CommandName,
38+
Data = new
39+
{
40+
key = "datetime",
41+
Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
42+
}
43+
};
44+
return Task.FromResult<UniverSheetData?>(result);
45+
}
46+
47+
private async Task OnPushExcelData()
48+
{
49+
await _sheetExcel.PushDataAsync(new UniverSheetData()
50+
{
51+
MessageName = "MessageName",
52+
CommandName = "CommandName",
53+
Data = new object[]
54+
{
55+
new object[] { "1", "2", "3", "4", "5" },
56+
new object[] { "1", "2", "3", "4", "5" },
57+
}
58+
});
59+
}
60+
61+
private async Task OnPushPluginData()
62+
{
63+
await _sheetPlugin.PushDataAsync(new UniverSheetData()
64+
{
65+
MessageName = "MessageName",
66+
CommandName = "CommandName",
67+
Data = new
68+
{
69+
Id = "1",
70+
Name = "Test",
71+
Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
72+
}
73+
});
74+
}
75+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.bb-sheet-demo {
2+
height: 290px;
3+
width: 100%;
4+
border: 1px solid var(--bs-border-color);
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function init(id) {
2+
3+
}
4+
5+
export function dispose(id) {
6+
7+
}

src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,12 @@ void AddData(DemoMenuItem item)
766766
Url = "typed"
767767
},
768768
new()
769+
{
770+
IsNew = true,
771+
Text = Localizer["UniverSheet"],
772+
Url = "univer-sheet"
773+
},
774+
new()
769775
{
770776
Text = Localizer["VideoPlayer"],
771777
Url = "video-player"

src/BootstrapBlazor.Server/Locales/en-US.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4855,7 +4855,8 @@
48554855
"Affix": "Affix",
48564856
"Watermark": "Watermark",
48574857
"OctIcon": "Oct Icons",
4858-
"Typed": "Typed"
4858+
"Typed": "Typed",
4859+
"UniverSheet": "UniverSheet"
48594860
},
48604861
"BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
48614862
"TablesHeaderTitle": "Header grouping function",
@@ -7002,5 +7003,18 @@
70027003
"Html2ImageElementIntro": "Get the <b>base64-encoded</b> image by calling the <code>GetDataAsync</code> method",
70037004
"Html2ImageButtonText": "Image",
70047005
"Html2ImageDesc": "Since the underlying library is <a href=\"https://github.com/bubkoo/html-to-image?wt.mc_id=DT-MVP-5004174\" target=\"_blank\">html-to-image</a>, if you encounter any problems during actual use, please refer to the project <a href=\"https://github.com/bubkoo/html-to-image/issues?wt.mc_id=DT-MVP-5004174\" target=\"_blank\">Issue</a>"
7006+
},
7007+
"BootstrapBlazor.Server.Components.Samples.UniverSheets": {
7008+
"UniverSheetTitle": "UniverSheet",
7009+
"UniverSheetIntro": "Encapsulates the core spreadsheet component of the open source office suite ​Univer​, providing a high-performance, scalable online spreadsheet solution",
7010+
"NormalTitle": "Basic usage",
7011+
"NormalIntro": "Set your own plugins by setting the <code>Plugins</code> parameter",
7012+
"NormalDesc1": "Push data to the spreadsheet by calling the instance method <code>PushDataAsync</code>",
7013+
"NormalDesc2": "Click the <b>Push Data</b> button to push data to the table, and click the first icon on the <b>Toolbar</b> to get data from the server.",
7014+
"PushButtonText": "Push",
7015+
"ToastOnReadyTitle": "Notification",
7016+
"ToastOnReadyContent": "The sheet is ready for push data.",
7017+
"PluginTitle": "Plugins",
7018+
"PluginIntro": "Set custom plugins by setting the <code>Plugins</code> parameter"
70057019
}
70067020
}

src/BootstrapBlazor.Server/Locales/zh-CN.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4855,7 +4855,8 @@
48554855
"Affix": "固钉组件 Affix",
48564856
"Watermark": "水印组件 Watermark",
48574857
"OctIcon": "Oct Icons",
4858-
"Typed": "打字机效果 Typed"
4858+
"Typed": "打字机效果 Typed",
4859+
"UniverSheet": "表格组件 UniverSheet"
48594860
},
48604861
"BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
48614862
"TablesHeaderTitle": "表头分组功能",
@@ -6990,7 +6991,7 @@
69906991
"BootstrapBlazor.Server.Components.Samples.Typeds": {
69916992
"TypedTitle": "Typed 打字机效果",
69926993
"TypedIntro": "输入任意字符串,它会按照你设置的速度输入,输入的内容会退格,然后根据你设置的字符串数量开始一个新句子。",
6993-
"NormalTitle": "Text",
6994+
"NormalTitle": "基础用法",
69946995
"NormalIntro": "通过设置 <code>Text</code> 参数设置要显示的文本",
69956996
"TypedOptionsTitle": "TypedOptions",
69966997
"TypedOptionsIntro": "通过设置 <code>TypedOptions</code> 参数的属性自定义打字速度、延时等设定"
@@ -7002,5 +7003,18 @@
70027003
"Html2ImageElementIntro": "通过调用 <code>GetDataAsync</code> 方法获得 <b>base64-encoded</b> 图片",
70037004
"Html2ImageButtonText": "Image",
70047005
"Html2ImageDesc": "由于底层使用的是 <a href=\"https://github.com/bubkoo/html-to-image?wt.mc_id=DT-MVP-5004174\" target=\"_blank\">html-to-image</a> 实际使用过程中遇到问题请参考项目 <a href=\"https://github.com/bubkoo/html-to-image/issues?wt.mc_id=DT-MVP-5004174\" target=\"_blank\">Issue</a>"
7006+
},
7007+
"BootstrapBlazor.Server.Components.Samples.UniverSheets": {
7008+
"UniverSheetTitle": "UniverSheet 电子表格组件",
7009+
"UniverSheetIntro": "封装开源办公套件 ​Univer​ 的核心电子表格组件,提供高性能、可扩展的在线表格解决方案",
7010+
"NormalTitle": "基础用法",
7011+
"NormalIntro": "通过调用实例方法 <code>PushDataAsync</code> 推送数据到电子表格",
7012+
"NormalDesc1": "点击 <b>推送数据</b> 按钮主动将数据推送给表格",
7013+
"NormalDesc2": "点击 <b>推送数据</b> 按钮主动将数据推送给表格,点击 <b>工具栏</b> 第一个小按钮主动从服务器端获取数据",
7014+
"PushButtonText": "推送数据",
7015+
"ToastOnReadyTitle": "组件通知",
7016+
"ToastOnReadyContent": "表格组件已就绪,可进行后续数据推送等操作",
7017+
"PluginTitle": "自定义插件",
7018+
"PluginIntro": "通过设置 <code>Plugins</code> 参数设置自己的插件"
70057019
}
70067020
}

src/BootstrapBlazor.Server/docs.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@
226226
"smiles-drawer": "SmilesDrawers",
227227
"affix": "Affixs",
228228
"watermark": "Watermarks",
229-
"typed": "Typeds"
229+
"typed": "Typeds",
230+
"univer-sheet": "UniverSheets"
230231
},
231232
"video": {
232233
"table": "BV1ap4y1x7Qn?p=1",
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import DataService from '../_content/BootstrapBlazor.UniverSheet/data-service.js'
2+
3+
const { Disposable, setDependencies, Injector, ICommandService, CommandType, UniverInstanceType } = UniverCore;
4+
const { ContextMenuGroup, ContextMenuPosition, RibbonStartGroup, ComponentManager, IMenuManagerService, MenuItemType, getMenuHiddenObservable } = UniverUi;
5+
6+
const GetDataOperation = {
7+
id: 'report.operation.add-table',
8+
type: CommandType.OPERATION,
9+
handler: async (accessor) => {
10+
const dataService = accessor.get(DataService.name);
11+
const data = await dataService.getDataAsync({
12+
messageName: "getDataMessage",
13+
commandName: "getDataCommand"
14+
});
15+
if (data) {
16+
const univerAPI = dataService.getUniverSheet().univerAPI;
17+
const range = univerAPI.getActiveWorkbook().getActiveSheet().getRange(0, 0, 2, 1)
18+
const defaultData = [
19+
[{ v: data.data.key }],
20+
[{ v: data.data.value }]
21+
]
22+
range.setValues(defaultData);
23+
}
24+
}
25+
};
26+
27+
function GetDataIcon() {
28+
return React.createElement(
29+
'svg',
30+
{ xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24" },
31+
React.createElement(
32+
'path',
33+
{ fill: "currentColor", d: "M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m.16 14a6.981 6.981 0 0 0-5.147 2.256A7.966 7.966 0 0 0 12 20a7.97 7.97 0 0 0 5.167-1.892A6.979 6.979 0 0 0 12.16 16M12 4a8 8 0 0 0-6.384 12.821A8.975 8.975 0 0 1 12.16 14a8.972 8.972 0 0 1 6.362 2.634A8 8 0 0 0 12 4m0 1a4 4 0 1 1 0 8a4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4a2 2 0 0 0 0-4" }
34+
)
35+
);
36+
}
37+
38+
function ReportGetDataFactory(accessor) {
39+
return {
40+
id: GetDataOperation.id,
41+
type: MenuItemType.BUTTON,
42+
icon: 'GetDataIcon',
43+
tooltip: '获取数据',
44+
title: '获取数据',
45+
hidden$: getMenuHiddenObservable(accessor, UniverInstanceType.UNIVER_SHEET)
46+
};
47+
}
48+
49+
export class ReportController extends Disposable {
50+
constructor(_injector, _commandService, _menuManagerService, _componentManager) {
51+
super();
52+
53+
this._injector = _injector;
54+
this._commandService = _commandService;
55+
this._menuManagerService = _menuManagerService;
56+
this._componentManager = _componentManager;
57+
58+
this._initCommands();
59+
this._registerComponents();
60+
this._initMenus();
61+
this._registerReceiveDataCallback();
62+
}
63+
64+
_registerReceiveDataCallback() {
65+
const dataService = this._injector.get(DataService.name);
66+
dataService.registerReceiveDataCallback(data => {
67+
this.receiveData(data, dataService.getUniverSheet());
68+
});
69+
}
70+
71+
_initCommands() {
72+
[GetDataOperation].forEach((c) => {
73+
this.disposeWithMe(this._commandService.registerCommand(c));
74+
});
75+
}
76+
77+
_registerComponents() {
78+
const componentMap = {
79+
GetDataIcon,
80+
}
81+
Object.entries(componentMap).forEach((item) => {
82+
this.disposeWithMe(this._componentManager.register(...item));
83+
});
84+
85+
}
86+
87+
_initMenus() {
88+
this._menuManagerService.mergeMenu({
89+
[RibbonStartGroup.HISTORY]: {
90+
[GetDataOperation.id]: {
91+
order: -1,
92+
menuItemFactory: ReportGetDataFactory
93+
},
94+
},
95+
[ContextMenuPosition.MAIN_AREA]: {
96+
[ContextMenuGroup.DATA]: {
97+
[GetDataOperation.id]: {
98+
order: 0,
99+
menuItemFactory: ReportGetDataFactory
100+
}
101+
}
102+
}
103+
});
104+
}
105+
106+
receiveData(data, sheet) {
107+
const { univerAPI } = sheet;
108+
const range = univerAPI.getActiveWorkbook().getActiveSheet().getRange(0, 0, 2, 3)
109+
const defaultData = [
110+
[{ v: 'Id' }, { v: 'Name' }, { v: 'Value' }],
111+
[{ v: data.data.id }, { v: data.data.name }, { v: data.data.value }]
112+
]
113+
range.setValues(defaultData);
114+
}
115+
}
116+
117+
setDependencies(ReportController, [Injector, ICommandService, IMenuManagerService, ComponentManager]);

0 commit comments

Comments
 (0)