- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
有没有办法将 Onchange 事件添加到网络聊天(版本 V4)中呈现的自适应卡片输入字段中。在结帐屏幕中更改数量值(数字类型的自适应卡输入字段)的示例应更新总计值(自适应卡文本字段)
为了保持简单......在下图中,一旦我更改输入框中的数字,它应该在下面的文本框中更新。一切都应该发生在网络聊天 V4(React) 客户端
以下是我尝试过的选项,没有任何代码可以在此处提交:
选项1:尝试使用中间件将事件添加到来自机器人的卡中的数量输入字段,但无法找到唯一标识输入字段以添加事件的选项(可以根据数量查看多个输入字段)卡片中的项目)
选项2:根据来自机器人的卡片在前端创建一张新卡片,并将事件添加到该新卡片。是否可以中断发送给机器人的消息并从前端发送卡片?
选项3:在卡片上添加更新按钮,以便在后端计算总数并向用户提交更新卡片
下面是有效负载:
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0",
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": "Output",
"weight": "Bolder",
"horizontalAlignment": "Center",
"size": "Large",
"id": "output",
"color": "Good"
},
{
"type": "Container",
"items": [
{
"$data": "{items}",
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": " ",
"id": "line",
"spacing": "None"
},
{
"type": "Image",
"altText": "",
"id": "myimage",
"url": "{imgUrl}",
"spacing": "None",
"size": "Stretch",
"width": "1000px",
"height": "100px"
},
{
"type": "ColumnSet",
"id": "imgset",
"columns": [
{
"type": "Column",
"width": 50,
"id": "desc",
"items": [
{
"type": "TextBlock",
"text": "{description}",
"weight": "Bolder",
"spacing": "None",
"id": "desc",
"wrap": true,
"maxLines": 4
}
],
"spacing": "None"
}
],
"spacing": "None"
},
{
"type": "ColumnSet",
"spacing": "None",
"columns": [
{
"type": "Column",
"width": 50,
"id": "qty",
"items": [
{
"type": "Input.Number",
"placeholder": "Quantity",
"id": "myquantity",
"min": 0,
"max": 100,
"value": "{quantity}",
"spacing": "None"
}
],
"horizontalAlignment": "Left",
"verticalContentAlignment": "Center",
"spacing": "None"
},
{
"type": "Column",
"id": "pricec",
"items": [
{
"type": "TextBlock",
"text": "{price}",
"id": "pricet",
"horizontalAlignment": "Right",
"spacing": "None"
}
],
"verticalContentAlignment": "Center",
"horizontalAlignment": "Right",
"width": 50,
"spacing": "None"
}
],
"id": "qtypset"
},
{
"type": "ColumnSet",
"spacing": "None",
"columns": [
{
"type": "Column",
"width": 1,
"items": [
{
"type": "TextBlock",
"text": "Sub Total",
"size": "Medium",
"id": "subtotal00",
"weight": "Bolder",
"spacing": "None"
}
],
"id": "subtotal1",
"spacing": "None"
},
{
"type": "Column",
"width": 1,
"items": [
{
"type": "TextBlock",
"horizontalAlignment": "Right",
"text": "{subtotal}",
"size": "Medium",
"weight": "Bolder",
"id": "subtotalt0",
"color": "Accent",
"spacing": "None"
}
],
"id": "subtotal200",
"spacing": "None"
}
],
"id": "colsetsubtot00"
}
],
"id": "itemcontainer",
"style": "emphasis",
"spacing": "None"
}
],
"id": "rootcontainer",
"style": "accent"
},
{
"type": "ColumnSet",
"id": "totalset",
"columns": [
{
"type": "Column",
"width": 50,
"id": "totalcolumn",
"items": [
{
"type": "TextBlock",
"text": "Total",
"size": "Medium",
"isSubtle": true,
"weight": "Bolder",
"id": "total",
"color": "Dark"
}
]
},
{
"type": "Column",
"width": 50,
"items": [
{
"type": "TextBlock",
"text": "{total}",
"size": "Medium",
"id": "totaltext",
"horizontalAlignment": "Right",
"weight": "Bolder",
"color": "Accent"
}
],
"id": "totalcol2"
}
]
}
],
"id": "final"
}
我使用下面的示例作为起点 https://github.com/microsoft/BotFramework-WebChat/tree/master/samples/04.api/e.piping-to-redux
webchat.js:
import React from 'react';
import ReactWebChat, { createDirectLine, createStore } from 'botframework-webchat';
import directLineDisconnect from 'botframework-webchat-core/lib/actions/disconnect';
import dispatchIncomingActivityMiddleware from './dispatchIncomingActivityMiddleware';
import uuid from 'uuid';
export default class extends React.Component {
constructor(props) {
super(props);
this.store = createStore({}, dispatchIncomingActivityMiddleware(props.appDispatch, this));
this.activityMiddleware = this.setActivityMiddleware();
this.attachmentMiddleware = this.setAttachmentMiddleware();
this.state = {};
}
componentDidMount() {
this.fetchToken();
this.setSendBox();
}
componentWillUnmount(){
}
async fetchToken() {
const myHeaders = new Headers();
const userDetails = uuid.v4();
myHeaders.append('Authorization', 'Bearer ' + 'mytoken');
myHeaders.append('Content-type', 'application/json');
const res = await fetch('https://directline.botframework.com/v3/directline/tokens/generate', {
body: JSON.stringify({ user: { id: userDetails, name: userDetails }}),
method: 'POST', headers: myHeaders });
const { token } = await res.json();
console.log("My Token: " + token);
this.setState(() => ({
directLine: createDirectLine({ token })
}));
}
setActivityMiddleware(){
return () => next => card => {
return children => (
<div
className={card.activity.attachments && (card.activity.attachments[0].content.id === "output") ? card.activity.attachments && card.activity.attachments[0].content.id : ''}
>
{next(card)(children)}
</div>
);
};
}
setAttachmentMiddleware(){
return () => next => ({ card, activity, attachment: baseAttachment }) => {
let attachment = baseAttachment;
if (baseAttachment.content.body){
switch (baseAttachment.content.body[0].id) {
case 'review':
for (let i = 0; i < attachment.content.body[1].items.length; i++) {
attachment.content.body[1].items[i].items[3].columns[0].items[0].value = baseAttachment.content.body[1].items[i].items[3].columns[0].items[0].value.toString();
} //for loop
break;
default:
break;
}
}
return next({ card, activity, attachment });
};
}
setSendBox() {
this.store.dispatch({
type: 'WEB_CHAT/SET_SEND_BOX',
payload: { text: 'sample:redux-middleware' }
});
/*
this.store.dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: { name: 'membersAdded',
value: { language: window.navigator.language }
}
}); */
}
render() {
return this.state.directLine ? (
<ReactWebChat
activityMiddleware={this.activityMiddleware}
attachmentMiddleware={this.attachmentMiddleware}
directLine={this.state.directLine}
store={this.store}
styleOptions={{
backgroundColor: 'Transparent',
hideUploadButton: true
}}
/>
) : (
<div>Connecting to bot…</div>
);
}
}
dispatchIncomingActivityMiddleware.js:
export default function(dispatch, thisvariable) {
return () => next => action => {
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
const { activity } = action.payload;
if (activity.from.role === 'bot'){
var inputBox=document.getElementsByClassName("css-eycyw2");
if (inputBox.length > 0){
inputBox[inputBox.length - 1].style.display='block';
}
}
}
if ((action.type === 'WEB_CHAT/SEND_POST_BACK') || (action.type === 'WEB_CHAT/SEND_MESSAGE')) {
var inputBox=document.getElementsByClassName("css-eycyw2");
if (inputBox.length > 0){
inputBox[inputBox.length - 1].style.display='none';
dispatch(setInputVisibility(true));
}
}
return next(action);
};
}
最佳答案
首先要了解的是,网络聊天使用 Adaptive Cards JavaScript SDK ,作为 npm 包提供。 Web Chat 主要使用 SDK 的开箱即用渲染功能,但它改变的一件重要事情是操作的处理方式。没有提供customized handler ,提交操作不会发送到机器人。
adaptiveCard.onExecuteAction = handleExecuteAction;
这就是应用程序使用自适应卡的方式。虽然大多数功能是在 SDK 端处理的,但应用程序需要执行一些操作才能使自适应卡适用于该特定应用程序。虽然您可以看到 Web Chat 将一个函数分配给特定自适应卡实例的 onExecuteAction
“事件”属性,但还有一个 onExecuteAction
的静态对应项,可以像这样访问这个:
AdaptiveCard.onExecuteAction = handleExecuteAction;
使用静态事件将为所有自适应卡应用一个处理程序,而不仅仅是一个,但它会被应用于特定实例的任何处理程序覆盖。我之所以告诉你这是因为有 many more static events ,其中有一些特别适合您的情况:
static onAnchorClicked: (element: CardElement, anchor: HTMLAnchorElement) => boolean = null;
static onExecuteAction: (action: Action) => void = null;
static onElementVisibilityChanged: (element: CardElement) => void = null;
static onImageLoaded: (image: Image) => void = null;
static onInlineCardExpanded: (action: ShowCardAction, isExpanded: boolean) => void = null;
static onInputValueChanged: (input: Input) => void = null;
static onParseElement: (element: CardElement, json: any, errors?: Array<HostConfig.IValidationError>) => void = null;
static onParseAction: (element: Action, json: any, errors?: Array<HostConfig.IValidationError>) => void = null;
static onParseError: (error: HostConfig.IValidationError) => void = null;
static onProcessMarkdown: (text: string, result: IMarkdownProcessingResult) => void = null;
您可以想出一个使用 onInputValueChanged
事件的解决方案,每次卡中的任何输入发生更改时都会触发该事件。您的处理程序可以在卡中搜索需要用作计算操作数的其他元素,并且还需要在卡中搜索将显示结果的元素。我不喜欢每次键入字符时都执行所有这些工作,而是更喜欢在开始时仅在卡片中搜索一次以查找将在计算中使用的元素的解决方案。监听自适应卡类或自适应卡实例上的事件的另一种方法是监听特定元素(例如输入)上的事件。因此,我的示例将使用静态 onParseElement
事件来获取所需的元素,然后使用 onValueChanged
事件来获取它找到的特定输入实例。
在为处理程序编写代码之前,我们需要想出一种方法,让代码知道哪些元素用于操作数和计算结果。例如,您可以让代码组合卡(或容器)中的每个输入,并将结果放入找到的最后一个文本 block 中。对于我的示例,我提出了代码可以使用的命名模式。有两个关键字“total”和“price”,代码在每个元素 ID 中查找它们。我想澄清的是,这个模式是完全任意的,如果你愿意,你可以做不同的事情。这是我的示例卡:
{
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "$10.00",
"id": "foo_a_price"
},
{
"type": "Input.Text",
"id": "foo_a"
},
{
"type": "TextBlock",
"text": "$2.00",
"id": "foo_b_price"
},
{
"type": "Input.Text",
"id": "foo_b"
},
{
"type": "TextBlock",
"text": "total",
"id": "total_foo"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Submit"
}
]
}
通过查看此内容,您可能会猜测,这个想法是让一个文本 block 拥有一个以“total_”开头的 ID,并在其后包含一些标识符。您要相加的数量以相同的标识符开始,您要与每个数量相乘的价格具有与数量相同的 ID,但带有后缀“_price”。我建议使用数字输入而不是文本输入,但此示例表明文本仍然有效。这是我的示例应用程序读取架构的代码:
import * as adaptiveCardsPackage from 'adaptivecards';
adaptiveCardsPackage.AdaptiveCard.onParseElement = element => {
const PREFIX_TOTAL = 'total_';
const SUFFIX_PRICE = '_price';
if (element.id && element.id.startsWith(PREFIX_TOTAL)) {
const itemPrefix = element.id.slice(PREFIX_TOTAL.length);
const card = element.getRootElement();
const inputs = card.getAllInputs().filter(input => input.id.startsWith(itemPrefix));
const products = {};
for (const input of inputs) {
const priceElement = card.getElementById(input.id + SUFFIX_PRICE);
const price = Number(priceElement.text.replace(/[^0-9.-]+/g, '')) || 0;
// `sender` will be the same as `input`.
// You could capture the input const instead of using the argument,
// but I'm demonstrating that you don't need to.
input.onValueChanged = sender => {
const quantity = Number(sender.value) || 0;
products[sender.id] = price * quantity;
const sum = Object.values(products).reduce((a, b) => a + b);
element.setText("$" + sum.toFixed(2));
element.renderedElement.replaceWith(element.render());
};
}
}
};
我有理由相信对 AdaptiveCard
类的更改将自动应用于 Web Chat 导入的包中的 AdaptiveCard
类,因为它是同一个类在同一个包中。但是,Web 聊天现在允许您提供自己的自适应卡包作为属性,因此您可以确保 Web 聊天将该包与您的特殊事件处理程序一起使用:
<ReactWebChat
directLine={createDirectLine({secretOrToken})}
adaptiveCardsPackage={adaptiveCardsPackage}
/>
关于json - BotFramework-WebChat - 自适应卡片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60877533/
让我们开始吧,3 个类(Card、Start、Deckofcards) 1° 卡: public class Card { private String type; private i
我要创建一个二十一点游戏,我正在尝试弄清楚如何发牌并让它显示值和名称。我选择两个属性的原因纯粹是基于逻辑,当涉及到将 A 视为 1 或 11 时。还没有达到这一点,只是想如果有人想知道的话我会包括在内
我正在尝试使用 twitter 元标记(以及 Facebook 等其他网站的 Open Graph)创建 Twitter 卡片。当我看到来自其他人(例如 NPR 新闻)的推特提要时,卡片会默认展开。
我正在开发一个玩基本扑克游戏的程序,但这并不重要。我有一组 52 张牌,包含花色和等级。我想打印 4 行 13 行的值(花色和等级)。这可能是一个简单的问题,但我整天都在努力解决这个问题。因此,我非常
我开发了一个包含三列(两列相等,一列较小)的网格。我的问题是我无法在卡片上设置高度,我在 px 中使用了它们并且它起作用了,但这不是最好的方法。我希望这三列具有相同的高度(页面的 100%)并且一些卡
我在 4 个不同的列中开发了 4 个 Bootstrap 卡。在每张卡片中,我创建了一张包含某种类型信息的新卡片。 我的问题是,当我缩小屏幕尺寸(响应测试)时,文本会从卡片中溢出。我的问题是什么,我该
我怎样才能达到 固定高度 具有垂直可滚动 的 bootstrap 4 卡卡片文字部分? Card title This portion and
在我的程序中,我有一个大 Canvas ,我在其中提取多个选定区域并将这些区域绘制到单独的新小 Canvas 上。 我想使用此 API 将新创建的 Canvas 作为附件发布到 trello POST
我想在卡片 View 中显示联系信息,如果需要,应该调整卡片 View 的大小以包含所有信息。 这是布局部分: 但是 an
这是我的card_view。我已经提到了 card_view:cardElevation。但是仍然没有显示阴影。 我搜索了很多链接。他们在任何地方都提到要使用 card_view:cardElevat
我正在使用此处的框架 - cardsui 如何在卡片顶部添加分享按钮。我已经使用点击方法在 xml 中实现了它,但是当我按下它时应用程序崩溃并说该方法不存在(是的,我将该方法添加到主 java 文件中
我正在将 cardview 与 recycler view 一起使用。但早些时候我使用相同的代码来做事没有任何问题。但现在我正在使用 fragment 。现在我得到卡片 View 之间的距离更大。我的
我的卡片 View 设置如下: android:layout_marginTop="2dp" android:layout_marginLeft="6dp" android:layout_margin
我正在制作一个二十一点游戏,并创建了一个数组来充当用户发牌的手牌。我希望能够对其进行排序,以便手按数字顺序排序,这样可以更简单地确定用户的手的类型。这是我的卡片结构: struct ACard{
我希望在一个运行在 Wordpress 上的网站上实现 Twitter Cards(关于 Twitter Cards 的文档在这里:https://dev.twitter.com/docs/cards
我需要帮助解决这个难题。在 bootstrap 4.1 中使用卡片列和卡片时,当我不想这样做时,行会中断。我将列数设置为 4,当有 4 张卡片时,它看起来很完美。当添加第五张牌时,它会将行分成顶部的
我有一个 android ListView ,它显示类似卡片的 View ,正如您在这张图片中看到的,我的卡片之间有一条灰色细线: 我怎样才能摆脱灰线? 我实现这个卡片 View 的xml是这样的:
我正在尝试添加带有回收站 View 的卡片 View 。但它没有显示任何内容,只是一个空白 View 。 我在这里看到了这方面的问题,它有为回收站 View 和卡片 View 添加依赖项的答案。这出现
我在 android 中通过回收站 View 实现卡片 View ,但我的卡片 View 没有显示。我正在使用自定义适配器将数据填充到卡片 View 。我已经尝试了所有方法,但没有显示卡片 View
在我的应用程序中,我有一个卡片 View ,其中包含一个 TextView 和一个按钮,该按钮最初是隐藏的,当单击卡片 View 时,会显示该按钮。我不知道如何在显示按钮时将其设置为动画。任何人都可以
我是一名优秀的程序员,十分优秀!