Skip to content

Commit 4432f8e

Browse files
author
Vicente.Yu
committed
增加 多维表格的查询记录结果转为字符串值 的扩展方法
调整 异常状态 的消息序列化
1 parent 98d5e16 commit 4432f8e

14 files changed

+702
-1
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,36 @@ await tenantApi.PostImV1MessagesAsync("open_id", dto5);
286286

287287
```
288288

289+
**(6)多维表格 查询记录 响应体 将查询结果转换为字符串值(3.3.7+): SerializeFieldsToStringValue**
290+
```csharp
291+
var _app_token = "T2aFbYYOoxxxxxxxxxxxxxxxAbjn4g";
292+
var _table_id = "tbldE95HxxxxxxxxxxEVLCQ";
293+
//获取字段数据结构
294+
var fields = await tenantApi.GetBitableV1AppsByAppTokenTablesByTableIdFieldsAsync(_app_token, _table_id);
295+
//查询记录
296+
var response = await tenantApi.PostBitableV1AppsByAppTokenTablesByTableIdRecordsSearchAsync(_app_token, _table_id, new()
297+
{
298+
AutomaticFields = true,
299+
ViewId = "vewxxxxxxxxxxxx1u",
300+
});
301+
//对查询结果进行转换
302+
var serialize = response.Data?.Items?.Select(i => i.SerializeFieldsToStringValue(fields.Data?.Items, new BitableRecordSerializer("")));
303+
304+
```
305+
**说明:**
306+
307+
1. 可以指定`BitableRecordSerializer`参数为数组值分隔符,默认`;`
308+
1. 文本记录类型字段取值于`text`属性
309+
1. 人员类型字段取值于`name`属性
310+
1. 链接类型字段取值于`link`属性
311+
1. 附件类型字段取值于`file_token`属性
312+
1. 地理位置类型字段取值于`name`属性
313+
1. 群组类型字段取值于`name`属性
314+
1. 公式或查找引用类型也会根据对应类型按照上述属性取值
315+
1. 其余字段默认转换为`string`类型,其中 日期类型 为 Unix 时间戳,单位是毫秒,如有需要可自行转换为日期格式。
316+
1. 自定义序列化规则:继承 `BitableRecordSerializer` 分别重写 `xxxRecordToString` 方法。
317+
318+
289319

290320
### 文件上传示例
291321
参数类型 `FormDataFile` 支持 `filePath``FileInfo``byte[]``Stream`

src/Attributes/IgnoreStatusExceptionFilterAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public override async System.Threading.Tasks.Task OnResponseAsync(ApiResponseCon
5151
bool isJson = context.HttpContext.ResponseMessage.Content.Headers.IsJsonContent();
5252

5353
context.Result = JsonSerializer.Deserialize(
54-
isJson ? content : $"{{\"msg\":\"{statusException.Message} - {content}\"}}",
54+
isJson ? content : JsonSerializer.Serialize(new { msg = $"{statusException.Message} - {content}" }),
5555
context.ActionDescriptor.Return.DataType.Type);
5656
}
5757
}

src/Base/Dtos/AttachmentRecord.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace FeishuNetSdk.Base.Dtos;
2+
3+
/// <summary>
4+
/// 附件类型记录
5+
/// </summary>
6+
/// <param name="FileToken">附件的 token</param>
7+
/// <param name="Name">附件名称</param>
8+
/// <param name="Size">附件大小。单位:字节</param>
9+
/// <param name="TmpUrl">生成附件临时下载链接的 url 链接,需 access token 鉴权</param>
10+
/// <param name="Type">附件的 mime 类型, 如: image/png</param>
11+
/// <param name="Url">附件 url 链接,需 access token 鉴权</param>
12+
public record AttachmentRecord(
13+
[property: JsonPropertyName("file_token")] string FileToken,
14+
[property: JsonPropertyName("name")] string Name,
15+
[property: JsonPropertyName("size")] long Size,
16+
[property: JsonPropertyName("tmp_url")] string TmpUrl,
17+
[property: JsonPropertyName("type")] string Type,
18+
[property: JsonPropertyName("url")] string Url) : IBitableRecord;
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
#pragma warning disable IDE0130 // 命名空间与文件夹结构不匹配
2+
namespace FeishuNetSdk;
3+
#pragma warning restore IDE0130 // 命名空间与文件夹结构不匹配
4+
5+
/// <summary>
6+
/// 多维表格记录序列化规则
7+
/// </summary>
8+
public class BitableRecordSerializer(string? separator = ";") : IBitableRecordSerializer
9+
{
10+
/// <summary>
11+
/// 数组分隔符
12+
/// </summary>
13+
public string? Separator => separator;
14+
15+
/// <summary>
16+
/// 该方法用于将集合元素拼接成以分号分隔的字符串
17+
/// </summary>
18+
protected virtual string JoinCollection<T>(IEnumerable<T>? collection)
19+
{
20+
// 如果集合为空,则使用空集合,然后将集合元素拼接成以分号分隔的字符串
21+
return string.Join(Separator, collection ?? Enumerable.Empty<T>());
22+
}
23+
24+
/// <inheritdoc/>
25+
public virtual string AttachmentRecordToString(Base.Dtos.AttachmentRecord[]? record)
26+
{
27+
return JoinCollection(record?.Select(k => k.FileToken));
28+
}
29+
30+
/// <inheritdoc/>
31+
public virtual string AutoNumberRecordToString(string[]? record)
32+
{
33+
return JoinCollection(record ?? []);
34+
}
35+
36+
/// <inheritdoc/>
37+
public virtual string BarcodeRecordToString(Base.Dtos.TextRecord[]? record)
38+
{
39+
return JoinCollection(record?.Select(p => p.Text));
40+
}
41+
42+
/// <inheritdoc/>
43+
public virtual string ButtonRecordToString(object? record)
44+
{
45+
throw new NotImplementedException();
46+
}
47+
48+
/// <inheritdoc/>
49+
public virtual string CheckboxRecordToString(bool[]? record)
50+
{
51+
return JoinCollection(record ?? []);
52+
}
53+
54+
/// <inheritdoc/>
55+
public virtual string CreatedTimeRecordToString(ulong[]? record)
56+
{
57+
return JoinCollection(record ?? []);
58+
}
59+
60+
/// <inheritdoc/>
61+
public virtual string CreatedUserRecordToString(Base.Dtos.UserRecord[]? record)
62+
{
63+
return JoinCollection(record?.Select(p => p.Name));
64+
}
65+
66+
/// <inheritdoc/>
67+
public virtual string CurrencyRecordToString(decimal[]? record)
68+
{
69+
return JoinCollection(record ?? []);
70+
}
71+
72+
/// <inheritdoc/>
73+
public virtual string DateTimeRecordToString(ulong[]? record)
74+
{
75+
return JoinCollection(record ?? []);
76+
}
77+
78+
/// <inheritdoc/>
79+
public virtual string DuplexLinkRecordToString(Base.Dtos.LinkRecord? record)
80+
{
81+
return JoinCollection(record?.LinkRecordIds);
82+
}
83+
84+
/// <inheritdoc/>
85+
public virtual string GroupChatRecordToString(Base.Dtos.GroupChatRecord[]? record)
86+
{
87+
return JoinCollection(record?.Select(p => p.Name));
88+
}
89+
90+
/// <inheritdoc/>
91+
public virtual string LocationRecordToString(Base.Dtos.LocationRecord[]? record)
92+
{
93+
return JoinCollection(record?.Select(p => p.Name));
94+
}
95+
96+
/// <inheritdoc/>
97+
public virtual string ModifiedTimeRecordToString(ulong[]? record)
98+
{
99+
return JoinCollection(record ?? []);
100+
}
101+
102+
/// <inheritdoc/>
103+
public virtual string ModifiedUserRecordToString(Base.Dtos.UserRecord[]? record)
104+
{
105+
return JoinCollection(record?.Select(p => p.Name));
106+
}
107+
108+
/// <inheritdoc/>
109+
public virtual string MultiSelectRecordToString(string[]? record)
110+
{
111+
return JoinCollection(record ?? []);
112+
}
113+
114+
/// <inheritdoc/>
115+
public virtual string NumberRecordToString(decimal[]? record)
116+
{
117+
return JoinCollection(record ?? []);
118+
}
119+
120+
/// <inheritdoc/>
121+
public virtual string PhoneRecordToString(string[]? record)
122+
{
123+
return JoinCollection(record ?? []);
124+
}
125+
126+
/// <inheritdoc/>
127+
public virtual string ProgressRecordToString(decimal[]? record)
128+
{
129+
return JoinCollection(record ?? []);
130+
}
131+
132+
/// <inheritdoc/>
133+
public virtual string RatingRecordToString(decimal[]? record)
134+
{
135+
return JoinCollection(record ?? []);
136+
}
137+
138+
/// <inheritdoc/>
139+
public virtual string SingleLinkRecordToString(Base.Dtos.LinkRecord? record)
140+
{
141+
return JoinCollection(record?.LinkRecordIds);
142+
}
143+
144+
/// <inheritdoc/>
145+
public virtual string SingleSelectRecordToString(string[]? record)
146+
{
147+
return JoinCollection(record ?? []);
148+
}
149+
150+
/// <inheritdoc/>
151+
public virtual string StageRecordToString(object? record)
152+
{
153+
throw new NotImplementedException();
154+
}
155+
156+
/// <inheritdoc/>
157+
public virtual string TextRecordToString(Base.Dtos.TextRecord[]? record)
158+
{
159+
return JoinCollection(record?.Select(p => p.Text));
160+
}
161+
162+
/// <inheritdoc/>
163+
public virtual string UrlRecordToString(Base.Dtos.UrlRecord[]? record)
164+
{
165+
return JoinCollection(record?.Select(p => p.Link));
166+
}
167+
168+
/// <inheritdoc/>
169+
public virtual string UserRecordToString(Base.Dtos.UserRecord[]? record)
170+
{
171+
return JoinCollection(record?.Select(p => p.Name));
172+
}
173+
174+
/// <inheritdoc/>
175+
public virtual Dictionary<string, Type> TypePairs => new()
176+
{
177+
{ "Text", typeof(Base.Dtos.TextRecord[]) },
178+
{ "Email", typeof(Base.Dtos.TextRecord[]) },
179+
{ "Barcode", typeof(Base.Dtos.TextRecord[]) },
180+
{ "Number", typeof(decimal[]) },
181+
{ "Progress", typeof(decimal[]) },
182+
{ "Currency", typeof(decimal[]) },
183+
{ "Rating", typeof(decimal[]) },
184+
{ "SingleSelect", typeof(string[]) },
185+
{ "MultiSelect", typeof(string[]) },
186+
{ "DateTime", typeof(ulong[]) },
187+
{ "Checkbox", typeof(bool[]) },
188+
{ "User", typeof(Base.Dtos.UserRecord[]) },
189+
{ "GroupChat", typeof(Base.Dtos.GroupChatRecord[]) },
190+
{ "Stage", typeof(object) },
191+
{ "Phone", typeof(string[]) },
192+
{ "Url", typeof(Base.Dtos.UrlRecord[]) },
193+
{ "Attachment", typeof(Base.Dtos.AttachmentRecord[]) },
194+
{ "SingleLink", typeof(Base.Dtos.LinkRecord) },
195+
{ "Formula", typeof(Base.Dtos.FormulaRecord) },
196+
{ "Lookup", typeof(Base.Dtos.FormulaRecord) },
197+
{ "DuplexLink", typeof(Base.Dtos.LinkRecord) },
198+
{ "Location", typeof(Base.Dtos.LocationRecord[]) },
199+
{ "CreatedTime", typeof(ulong[]) },
200+
{ "ModifiedTime", typeof(ulong[]) },
201+
{ "CreatedUser", typeof(Base.Dtos.UserRecord[]) },
202+
{ "ModifiedUser", typeof(Base.Dtos.UserRecord[]) },
203+
{ "AutoNumber", typeof(string[]) },
204+
{ "Button", typeof(object) },
205+
{ "Type1", typeof(Base.Dtos.TextRecord[]) },
206+
{ "Type2", typeof(decimal[]) },
207+
{ "Type3", typeof(string[]) },
208+
{ "Type4", typeof(string[]) },
209+
{ "Type5", typeof(ulong[]) },
210+
{ "Type7", typeof(bool[]) },
211+
{ "Type11", typeof(Base.Dtos.UserRecord[]) },
212+
{ "Type13", typeof(string[]) },
213+
{ "Type15", typeof(Base.Dtos.UrlRecord[]) },
214+
{ "Type17", typeof(Base.Dtos.AttachmentRecord[]) },
215+
{ "Type19", typeof(Base.Dtos.FormulaRecord) },
216+
{ "Type20", typeof(Base.Dtos.FormulaRecord) },
217+
{ "Type22", typeof(Base.Dtos.LocationRecord[]) },
218+
{ "Type23", typeof(Base.Dtos.GroupChatRecord[]) },
219+
{ "Type1001", typeof(ulong[]) },
220+
{ "Type1002", typeof(ulong[]) },
221+
{ "Type1003", typeof(Base.Dtos.UserRecord[]) },
222+
{ "Type1004", typeof(Base.Dtos.UserRecord[]) },
223+
{ "Type1005", typeof(string[]) },
224+
{ "JsonValueKindTrue", typeof(bool[]) },
225+
{ "JsonValueKindFalse", typeof(bool[]) },
226+
{ "JsonValueKindNumber", typeof(decimal[]) },
227+
{ "JsonValueKindString", typeof(string[]) },
228+
{ "JsonValueKindArray", typeof(Base.Dtos.TextRecord[]) },
229+
{ "JsonValueKindObject", typeof(Base.Dtos.FormulaRecord) },
230+
};
231+
}

src/Base/Dtos/FormulaRecord.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace FeishuNetSdk.Base.Dtos;
2+
3+
/// <summary>
4+
/// 公式或查找引用类型的记录
5+
/// </summary>
6+
/// <param name="Type">用于指定 value 的数据类型</param>
7+
/// <param name="Value">type 字段决定 value 的数据结构,可参考本文档中 value 的结构。</param>
8+
public record FormulaRecord(
9+
[property: JsonPropertyName("type")] int Type,
10+
[property: JsonPropertyName("value")] object Value) : IBitableRecord;

src/Base/Dtos/GroupChatRecord.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace FeishuNetSdk.Base.Dtos;
2+
3+
/// <summary>
4+
/// 群组类型的记录
5+
/// </summary>
6+
/// <param name="AvatarUrl">群组头像链接</param>
7+
/// <param name="Id">群组的 ID</param>
8+
/// <param name="Name">群组名称</param>
9+
public record GroupChatRecord(
10+
[property: JsonPropertyName("avatar_url")] string AvatarUrl,
11+
[property: JsonPropertyName("id")] string Id,
12+
[property: JsonPropertyName("name")] string Name) : IBitableRecord;

src/Base/Dtos/IBitableRecord.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace FeishuNetSdk.Base.Dtos;
2+
3+
/// <summary>
4+
/// 多维表格记录数据结构
5+
/// </summary>
6+
public interface IBitableRecord { }

0 commit comments

Comments
 (0)