【Power Platform系列】如何在画布应用中调用工作流上传附件
在Power Apps画布应用中上传附件,比如到SharePoint文档库最典型的方式非常简单,插入一个编辑窗体,将窗体和背后的文档库绑定起来即可以快速实现。不过窗体内部的显示格式很难控制,如果要实现更为灵活的控制,就需要采用其他方式。本文实现的是在自定义界面的画布应用中选好文件点击上传按钮调用Power Automate工作流来实现附件上传,当然也可以在Patch()里直接进行上传,示例代码如下:
Patch(
YourSharePointLibrary,
Defaults(YourSharePointLibrary),
{ Title: "New Document",
YourColumnName: YourValue,
// 添加其他需要的列和值
},
{ File: FilePicker.SelectedFile }
)
不过如果使用Power Automate可以实现更多的功能,比如将上传的文件内容通过AI识别后存储在单独的字段等则无法在Patch()里实现。
1. 构建一个简单的上传文档界面,界面如下图所示,panBulkUpload是顶层容器,下面的panNewDocument容器存储包含了上传文件的控件FileUploader(如何在画布应用里使用该控件可以参考【Power Apps系列】如何在画布应用里添加附件控件-CSDN博客)以及提示信息标签控件label1
2. 标签显示的内容为“Supported Document Type: PDF, Image; Maximal document number: 10; Allowed maximal document size: 100MB”,10和100MB来自FileUploader控件的配置,设置label1的Text属性如下即可实现
$"Supported Document Types: PDF, Image; Maximal document number: {FileUploader.MaxAttachments}; Allowed maximal document size: {FileUploader.MaxAttachmentSize}MB"
3. panBulkUpload控件的配置可以参看其代码,这里不一个个解释,留意其中的关键是garBulkUpload的Items属性设置为FileUploader.Attachments,实现了将用户上传附件的内容绑在在garBulkUpload容器
- panBulkUpload:
Control: GroupContainer
Variant: verticalAutoLayoutContainer
Properties:
DropShadow: =DropShadow.None
Fill: =RGBA(250, 250, 250, 0.8)
Height: =App.Height
LayoutAlignItems: =LayoutAlignItems.Stretch
LayoutDirection: =LayoutDirection.Vertical
LayoutJustifyContent: =LayoutJustifyContent.Center
LayoutMode: =LayoutMode.Auto
Width: =App.Width
Children:
- panNewDocument:
Control: GroupContainer
Variant: verticalAutoLayoutContainer
Properties:
AlignInContainer: =AlignInContainer.SetByContainer
DropShadow: =DropShadow.Bold
Fill: =RGBA(255, 255, 255, 1)
Height: =500
LayoutAlignItems: =LayoutAlignItems.Stretch
LayoutDirection: =LayoutDirection.Vertical
LayoutJustifyContent: =LayoutJustifyContent.SpaceBetween
LayoutMode: =LayoutMode.Auto
PaddingBottom: =10
PaddingLeft: =40
PaddingRight: =40
PaddingTop: =40
Width: =800
X: =(App.Width-Self.Width)/2
Y: =(App.Height-Self.Height)/2
Children:
- Label1:
Control: Label
Properties:
Text: |-
=$"Supported Document Types: PDF, Image; Maximal document number: {FileUploader.MaxAttachments}; Allowed maximal document size: {FileUploader.MaxAttachmentSize}MB"
- FileUploader:
Control: Attachments
Properties:
AddAttachmentText: ="Upload file"
Items: =[]
MaxAttachmentSize: =100
MaxAttachments: =10
MaxAttachmentsText: =""
NoAttachmentsText: ="There is no file."
Tooltip: ="Upload documents"
BorderColor: =Color.Red
BorderStyle: =BorderStyle.None
Color: =RGBA(51, 51, 51, 1)
DisabledBorderColor: =RGBA(0, 0, 0, 0)
FillPortions: =1
Font: =Font.'Segoe UI'
Height: =240
HoverColor: =RGBA(51, 51, 51, 1)
HoverFill: =RGBA(212, 212, 212, 1)
ItemColor: =RGBA(0, 0, 0, 1)
ItemFill: =RGBA(0, 120, 212, 1)
ItemHoverColor: =RGBA(51, 51, 51, 1)
ItemHoverFill: =RGBA(212, 212, 212, 1)
ItemSpacing: =12
LayoutMinHeight: =0
NoAttachmentsColor: =RGBA(166, 166, 166, 1)
PaddingBottom: =5
PaddingLeft: =If(Self.DisplayMode = DisplayMode.Edit, 5, 0)
PaddingRight: =5
PaddingTop: =5
PressedFill: =RGBA(0, 120, 212, 1)
Size: =10
Width: =Parent.Width - 60
X: =30
Y: =5
- garBulkUpload:
Control: Gallery
Variant: BrowseLayout_Horizontal_TwoTextOneImageVariant_ver5.0
Properties:
Items: =FileUploader.Attachments
BorderColor: =RGBA(166, 166, 166, 1)
DelayItemLoading: =true
FillPortions: =0
FocusedBorderColor: =RGBA(0, 120, 212, 1)
FocusedBorderThickness: =2
Height: =80
LoadingSpinner: =LoadingSpinner.Data
TemplatePadding: =0
TemplateSize: =80
Visible: =false
Children:
- Title2:
Control: Label
Properties:
OnSelect: =Select(Parent)
Text: =ThisItem.Name
FontWeight: =If(ThisItem.IsSelected, FontWeight.Semibold, FontWeight.Normal)
Height: =Self.Size * 1.8
PaddingBottom: =0
PaddingLeft: =0
PaddingRight: =0
PaddingTop: =0
VerticalAlign: =VerticalAlign.Top
Width: =Parent.TemplateWidth - 64
X: =32
Y: =Image2.Y + Image2.Height + 16
- Image2:
Control: Image
Properties:
OnSelect: =Select(Parent)
Image: =ThisItem.Value
Height: =296
ImagePosition: =ImagePosition.Fill
RadiusBottomLeft: =8
RadiusBottomRight: =8
RadiusTopLeft: =8
RadiusTopRight: =8
Width: =Parent.TemplateWidth - 32
X: =(Parent.TemplateWidth / 2) - (Self.Width / 2)
Y: =16
- Container4:
Control: GroupContainer
Variant: horizontalAutoLayoutContainer
Properties:
AlignInContainer: =AlignInContainer.SetByContainer
DropShadow: =DropShadow.None
FillPortions: =0
Height: =50
LayoutAlignItems: =LayoutAlignItems.Center
LayoutGap: =20
LayoutJustifyContent: =LayoutJustifyContent.Center
LayoutMode: =LayoutMode.Auto
PaddingLeft: =40
PaddingRight: =40
Width: =800
Children:
- btnSaveNewDocument:
Control: Classic/Button
Properties:
OnSelect: |-
=UpdateContext(
{
varShowDocumentDetailPanel: false,
varShowSpinner:true,
varSpinnerMsg:"Uploading files, please wait..."
}
);
ForAll(
garBulkUpload.AllItems,
'UploadFiletoSharePoint'.Run(
ThisRecord.Name,
Substitute(
JSON(
Image2.Image,
JSONFormat.IncludeBinaryData
),
"""",
""
)
)
);
Reset(FileUploader);
UpdateContext({varShowSpinner: false});
Notify("Successfully",NotificationType.Success,1000)
Text: ="Upload"
Width: =96
4. 设置Upload按钮的OnSelect的代码如下,实现文件的上传:
// 更新上下文变量的值
UpdateContext(
{
// 设置变量 varShowDocumentDetailPanel 为 false,隐藏文档详细信息面板
varShowDocumentDetailPanel: false,
// 设置变量 varShowSpinner 为 true,显示加载动画(即旋转图标)
varShowSpinner: true,
// 设置变量 varSpinnerMsg 为 "Uploading files, please wait...",显示加载动画时的提示信息
varSpinnerMsg: "Uploading files, please wait..."
}
);
// 遍历集合 garBulkUpload.AllItems 中的所有记录
ForAll(
garBulkUpload.AllItems, // 目标集合,包含需要上传的文件信息
// 调用自定义的流 'UploadFiletoSharePoint'
'UploadFiletoSharePoint'.Run(
// 传递当前记录的名称(ThisRecord.Name)作为参数
ThisRecord.Name,
// 将当前图片控件 Image2 的图像数据转换为 JSON 格式(包含二进制数据)
// 并用 Substitute 函数替换掉 JSON 中的所有双引号(为了符合格式要求)
Substitute(
JSON(
Image2.Image, // 从 Image2 控件获取图片
JSONFormat.IncludeBinaryData // 指定 JSON 格式,包含二进制数据
),
"""", // 查找双引号
"" // 替换为空字符串
)
)
);
// 重置文件上传控件 FileUploader,清空已选择的文件
Reset(FileUploader);
// 上传完成后,更新上下文变量
UpdateContext({
// 设置变量 varShowSpinner 为 false,隐藏加载动画
varShowSpinner: false
});
// 显示通知消息,提示用户操作成功
Notify(
"Successfully", // 通知消息内容
NotificationType.Success, // 通知类型(成功)
1000 // 通知显示时间(1000 毫秒,即 1 秒)
);
5. 上面步骤通过'UploadFiletoSharePoint'.Run来调用工作流,这个工作流要在画布应用里添加进来:
6. 工作流的配置如下:
7. 上方File Content的内容做了转码处理,triggerBody()
返回的是触发器的输入数据,通常以 JSON 对象的形式存在,triggerBody()?['text_1']
这个表达式从触发器的主体数据中提取名为 text_1
的属性,?
操作符用于安全地访问 JSON 对象中的属性,当属性不存在时不会抛出错误,而是返回 null
。dataUriToBinary()是一个 Power Automate 中的函数,用于将 Data URI(通常是以 data:image/png;base64,...
开头的字符串)转换为二进制数据,Base64 是一种将二进制数据编码为 ASCII 字符串的方法,通常用于在需要文本存储或传输二进制数据的情况下。
@{base64(dataUriToBinary(triggerBody()?['text_1']))}