我正在使用 MS Teams 中的这 2 个包,使用自适应卡的 HTML 渲染版本。
反应16
以前,我按原样使用自适应卡,并在 Teams 应用程序的帮助下将它们发布到 MS Teams 群聊或频道中。任何按钮单击事件都用于在我的任务模块微服务中捕获。
现在,当我将同一张自适应卡解析并渲染为 HTML 格式时,如何在单击 HTML 按钮时获得相同的结果?
这就是我将自适应卡解析为 HTML 的方式
Card.tsx
import { AdaptiveCardUsingHostConfigContext } from "adaptivecards-react";
import React, { useState, useEffect } from "react";
import * as AC from "adaptivecards";
import { SubmitAction } from "./SubmitAction";
import { ExecuteAction } from "./ExecuteAction";
AC.GlobalRegistry.actions.register(SubmitAction.JsonTypeName, SubmitAction);
AC.GlobalRegistry.actions.register(ExecuteAction.JsonTypeName, ExecuteAction);
const Card = (props: { card: any }) => {
const { card } = props;
const [isLoading, setIsLoading] = useState(false);
const [cardPayload, setCardPayload] = useState(card);
useEffect(() => {
// console.log("Card: ", JSON.stringify(cardPayload));
}, [cardPayload]);
const onActionSubmit = (e: any) => {
console.log("SUBMIT");
console.log("inputs", e.data, e.id);
};
const onExecuteAction = (e: any) => {
const actionType = e.getJsonTypeName();
const { verb } = e;
console.log(`executing action for ${verb}`);
let response;
if (actionType === "Action.Execute") {
setIsLoading(true);
response = cardPayload;
response.body = [
...cardPayload.body,
{
text: "This is a fresh dynamic detail!",
wrap: true,
type: "TextBlock",
},
];
// }
setCardPayload(response);
setIsLoading(false);
}
};
return (
<div className="Card">
<AdaptiveCardUsingHostConfigContext
payload={cardPayload}
onActionSubmit={onActionSubmit}
onExecuteAction={onExecuteAction}
/>
</div>
);
};
export default Card;
ExecuteAction.tsx
import React from "react";
import * as AC from "adaptivecards";
import Button from "../components/Button";
import { reactDomRender } from "./shared";
export class ExecuteAction extends AC.ExecuteAction {
private internalRenderedElement: any;
static readonly titleProperty = new AC.StringProperty(
AC.Versions.v1_0,
"title",
true
);
getTitle(): string | undefined {
return this.getValue(ExecuteAction.titleProperty);
}
get renderedElement(): HTMLElement | undefined {
return this.internalRenderedElement;
}
render() {
const element = reactDomRender(this.renderElement());
this.internalRenderedElement = element;
}
private renderElement = (): JSX.Element => {
return <Button label={this.getTitle()} onClick={() => this.execute()} />;
};
}
SubmitAction.tsx
import React from "react";
import * as AC from "adaptivecards";
import Button from "../components/Button";
import { reactDomRender } from "./shared";
export class SubmitAction extends AC.SubmitAction {
private internalRenderedElement: any;
static readonly textProperty = new AC.StringProperty(
AC.Versions.v1_3,
"text",
true
);
static readonly titleProperty = new AC.StringProperty(
AC.Versions.v1_3,
"title",
true
);
static readonly dataProperty = new AC.PropertyDefinition(
AC.Versions.v1_3,
"data"
);
getTitle(): string | undefined {
return this.getValue(SubmitAction.titleProperty);
}
getText(): string | undefined {
return this.getValue(SubmitAction.textProperty);
}
getData(): string | undefined {
return this.getValue(SubmitAction.dataProperty);
}
getInputs(): any {
return this.getValue(SubmitAction.associatedInputsProperty);
}
getInputValues(): any {
return this.parent?.getAllInputs().map((input) => {
return { id: input.id, value: input.value };
});
}
get renderedElement(): HTMLElement | undefined {
return this.internalRenderedElement;
}
render() {
const element = reactDomRender(this.renderElement());
this.internalRenderedElement = element;
}
execute() {
console.log("-->", this.getData());
const inputs = this.validateInputs();
console.log(inputs);
if (inputs.length === 0) {
console.log("inputs valid");
const inputValues = this.getInputValues();
console.log("input values", inputValues);
} else {
for (const input of inputs) {
console.log("input id", input.id);
console.log("isValid", input.isValid());
this.render();
}
}
}
onExecuteAction(action: any) {
console.log("onExecuteAction");
action();
}
private renderElement = (): JSX.Element => {
return <Button label={this.title} onClick={() => this.execute()} />;
};
}
shared.tsx
import React from "react";
import * as ReactDOM from "react-dom";
export const reactDomRender = (
reactElement: React.ReactElement
): HTMLElement | undefined => {
const div = document.createElement("div");
ReactDOM.render(reactElement, div);
return div;
};
RenderCard.tsx
/* eslint-disable react/prop-types */
import React from "react";
import Card from "./components/Card";
import { Loader } from "@fluentui/react-northstar";
const RenderCard = (props) => {
const { card } = props;
if (card) {
return (
<div className="App">
<div>
<Card card={card} />
</div>
</div>
);
} else {
return <Loader label="Please wait..." size="largest" />;
}
};
export default RenderCard;
hostConfig.tsx
const hostConfig = () => {
return {
spacing: {
small: 3,
default: 8,
medium: 20,
large: 30,
extraLarge: 40,
padding: 10,
},
separator: {
lineThickness: 1,
lineColor: "#EEEEEE",
},
supportsInteractivity: true,
fontTypes: {
default: {
fontFamily:
"'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
fontSizes: {
small: 12,
default: 14,
medium: 17,
large: 21,
extraLarge: 26,
},
fontWeights: {
lighter: 200,
default: 400,
bolder: 600,
},
},
monospace: {
fontFamily: "'Courier New', Courier, monospace",
fontSizes: {
small: 12,
default: 14,
medium: 17,
large: 21,
extraLarge: 26,
},
fontWeights: {
lighter: 200,
default: 400,
bolder: 600,
},
},
},
containerStyles: {
default: {
backgroundColor: "#FFFFFF",
foregroundColors: {
default: {
default: "#000000",
subtle: "#767676",
},
accent: {
default: "#0063B1",
subtle: "#0063B1",
},
attention: {
default: "#FF0000",
subtle: "#DDFF0000",
},
good: {
default: "#54a254",
subtle: "#DD54a254",
},
warning: {
default: "#c3ab23",
subtle: "#DDc3ab23",
},
},
},
emphasis: {
backgroundColor: "#F0F0F0",
foregroundColors: {
default: {
default: "#000000",
subtle: "#767676",
},
accent: {
default: "#2E89FC",
subtle: "#882E89FC",
},
attention: {
default: "#FF0000",
subtle: "#DDFF0000",
},
good: {
default: "#54a254",
subtle: "#DD54a254",
},
warning: {
default: "#c3ab23",
subtle: "#DDc3ab23",
},
},
},
accent: {
foregroundColors: {
default: {
default: "#333333",
subtle: "#EE333333",
},
dark: {
default: "#000000",
subtle: "#66000000",
},
light: {
default: "#FFFFFF",
subtle: "#33000000",
},
accent: {
default: "pink",
subtle: "#882E89FC",
},
attention: {
default: "#cc3300",
subtle: "#DDcc3300",
},
good: {
default: "#54a254",
subtle: "#DD54a254",
},
warning: {
default: "#e69500",
subtle: "#DDe69500",
},
},
},
good: {
backgroundColor: "#CCFFCC",
foregroundColors: {
default: {
default: "#333333",
subtle: "#EE333333",
},
dark: {
default: "#000000",
subtle: "#66000000",
},
light: {
default: "#FFFFFF",
subtle: "#33000000",
},
accent: {
default: "#2E89FC",
subtle: "#882E89FC",
},
attention: {
default: "#cc3300",
subtle: "#DDcc3300",
},
good: {
default: "#54a254",
subtle: "#DD54a254",
},
warning: {
default: "#e69500",
subtle: "#DDe69500",
},
},
},
},
imageSizes: {
small: 40,
medium: 80,
large: 160,
},
actions: {
maxActions: 6,
spacing: "default",
buttonSpacing: 10,
showCard: {
actionMode: "inline",
inlineTopMargin: 8,
},
actionsOrientation: "vertical",
actionAlignment: "stretch",
iconSize: 50,
},
adaptiveCard: {
allowCustomStyle: true,
},
imageSet: {
imageSize: "medium",
maxImageHeight: 100,
},
factSet: {
title: {
color: "default",
size: "default",
isSubtle: false,
weight: "bolder",
wrap: true,
maxWidth: 150,
},
value: {
color: "default",
size: "default",
isSubtle: false,
weight: "default",
wrap: true,
},
spacing: 8,
},
};
};
export default hostConfig;
这是我使用
RenderCard.tsx
组件的代码要点
import { ProvidesHostConfigContext } from "adaptivecards-react";
import hostConfig from "./hostConfig";
import RenderCard from "./rendercard";
<ProvidesHostConfigContext hostConfig={hostConfig}>
<RenderCard card={card} />
</ProvidesHostConfigContext>
任何帮助或推动正确的方向都会非常有帮助。
谢谢你
您可以在应用程序的 JavaScript 或 Typescript 代码中处理按钮单击事件,并使用 Teams JavaScript 客户端库调用任务模块。
TeamsJS V1 代码示例:
let taskInfo = {
title: null,
height: null,
width: null,
url: null,
card: null,
fallbackUrl: null,
completionBotId: null,
};
taskInfo.url = "https://contoso.com/teamsapp/customform";
taskInfo.title = "Custom Form";
taskInfo.height = 510;
taskInfo.width = 430;
submitHandler = (err, result) => {
console.log(`Submit handler - err: ${err}`);
console.log(`Submit handler - result\rName: ${result.name}\rEmail: ${result.email}\rFavorite book: ${result.favoriteBook}`);
};
microsoftTeams.tasks.startTask(taskInfo, submitHandler);
TeamsJS V2 示例代码:
let taskInfo = {
title: null,
height: null,
width: null,
url: null,
card: null,
fallbackUrl: null,
completionBotId: null,
};
taskInfo.url = "https://contoso.com/teamsapp/customform";
taskInfo.title = "Custom Form";
taskInfo.height = 510;
taskInfo.width = 430;
dialogResponse = (dialogResponse) => {
console.log(`Submit handler - err: ${dialogResponse.err}`);
alert("Result = " + JSON.stringify(dialogResponse.result) + "\nError = " + JSON.stringify(dialogResponse.err));
};
microsoftTeams.dialog.open(taskInfo, dialogResponse);
请参考以下示例: https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-task-module