仪表板 ajax实例,CQD 开发示例 - Skype for Business Server 2015 | Microsoft Docs
CQD 开发示例
2021/7/29
本文内容
摘要: 查看通话质量仪表板的教程和开发示例。 通话质量仪表板是 Skype for Business Server 的工具。
本文提供了有关通话质量仪表板和 CQD (的) 。
通话质量仪表板 (CQD) 示例
教程:使用 CQD 数据服务和存储库服务 API 生成自定义报表演示文稿。
CQD 简介
CQD 提供快速而轻松地访问本地 Skype for Business Server 部署的聚合呼叫质量信息。 CQD 由三个组件组成:QoE 存档数据库、多维数据集和门户。 门户是主表示层,可以进一步划分为以下三个组件:
数据服务,可通过 Skype for Business Server 中 CQD (CQD) 数据 API 供经过身份验证的用户访问。
存储库服务,可通过 Skype for Business Server 中的呼叫质量仪表板存储库 API (CQD) 用户访问。
Web 门户,它是 CQD 用户查看并与之交互的基于 HTML5 的界面。 这可供经过身份验证的用户访问。
Web 门户上显示的报告分为"报告集"。 下图显示了一个报告集,其中具有两个报告。 下面此仪表板中的每个报表都显示有关好通话数、质量欠佳的呼叫数和几个月内质量欠佳的呼叫百分比的查询结果,并应用了各种筛选器。
CQD 是按照 CQM (方法) 创建的,因此默认报告集旨在与 CQM 引入的调查流保持一致。 用户还可以灵活地编辑或创建自定义报告以满足其需求。 但是,由于有多种可视化数据的方法,CQD 提供的可视化可能无法完全满足每个用户的需求。 在这种情况下,用户可以利用数据 API 和存储库 API 创建自定义报告页面。 我们将在本教程中介绍一系列示例。
仪表板如何使用数据服务
导航到 CQD 主页 (例如,从存储库服务检索经过身份验证和授权的用户的报告集和相应 http://localhost/cqd) 报告。 完整 URL 将基于报告集 ID 构建,而年-月 (报告集 ID 是 URL 中"/#/"部分后的整数,默认情况下,当前年份的追加位置为斜杠) 后的报告集 ID 的末尾。 报告定义以 JSON 格式存储,从存储库服务检索时,将用作数据服务的输入。 数据服务根据输入 (MDX) 生成多维表达式,然后针对多维数据集运行这些 MDX 查询以检索每个报告的数据。
生成自定义报告
CQD 在自定义报告方面已经具有很大的灵活性,但在某些情况下,用户可能希望聚合 CQD 中创建的多个报告的数据。 例如,可能需要创建一个报告,该报告显示表中所有可能组合的有线呼叫的欠佳呼叫百分比, (结果如下所示:) :
使用 CQD 提供的门户,用户必须导航到多个报告,以提取并记录每个报告质量欠佳的呼叫百分比,如果有许多需要收集的数据点,这将非常费时。 数据 API 为用户提供了一种编程方式来完成此操作,方法为从数据服务应用程序检索数据 (例如,通过 AJAX) 。
示例 1:简单报告示例
让我们首先看一个简单的示例。 如果我们希望在如下所示的 HTML 页面上显示 2015 年 2 月的音频良好流和音频错误流计数:
我们需要使用正确的参数向数据服务发送调用,并将查询结果显示在 HTML 表中。 下面是 JavaScript 代码的示例:
$($.fn.freeFormReport = function (queries, urlApi, presentation) {
var query = {
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [{
DataModelName: '[StartDate].[Month]',
Value: '[2015-02-01T00:00:00]',
Operand: 0
}],
Measurements:
[{ DataModelName: '[Measures].[Audio Good Streams JPDR Count]' },
{ DataModelName: '[Measures].[Audio Poor Streams JPDR Count]' },]
};
$.ajax({
url: 'http://localhost/QoEDataService/RunQuery',
data: JSON.stringify(query),
type: 'POST',
async: true,
contentType: 'application/json;charset=utf-8',
success: function (data) {
//This is the jQuery syntax for document.GetElementById()
$('#AudioGoodStreamsJPDRCount').html(data.DataResult[0][1]);
$('#AudioPoorStreamsJPDRCount').html(data.DataResult[0][2]);
}
error: function (error) {
alert('Error getting data, check that the data service is running and that the URL is correct.');
}
});
});
此示例可以进一步解构为三个步骤:
构造该 ("查询"变量中定义的查询) 。 查询定义为 JSON 对象,其中包含以下数据:
a. 零个或多个维度。 每个维度由 DataModelName 指示。
b. 零个或多个筛选器。 每个筛选器具有:
DataModelName (将设置筛选器的维度) 。
值 (操作数值进行比较的值) 。
操作 (类型,0 表示"等于") 。
c. 一个或多个度量。
通过 AJAX 调用将查询发送到数据服务。 需要提供以下请求参数:
a. url (应为 http://[ServerName]/QoEDataService/RunQuery) 。
b. data (这是在"query"变量中定义的 JSON 对象的字符串) 。 数据服务将返回查询结果作为调用回叫函数的一个参数以成功。
c. type (For QoEDataService, RunQuery only accepts 'POST' requests) .
d. 异步 (一个标志,指示 AJAX 调用是同步调用还是异步) 。
e. contentType (应为"application/json") 。
f. 成功 (AJAX 调用何时成功完成) 。
g. 错误 (AJAX 调用失败时的错误处理) 。
将数据放入 HTML (代码示例中的 div 元素中,这是在 AJAX 请求成功完成之后通过匿名函数调用) 。
将 JavaScript 代码包含在 HTML 页中,该页面将显示如图所示的报告。 完整的 html 如下所示:
$($.fn.freeFormReport = function (queries, urlApi, presentation) {
var query = {
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [{
DataModelName: '[StartDate].[Month]',
Value: '[2015-02-01T00:00:00]',
Operand: 0
}],
Measurements:
[{ DataModelName: '[Measures].[Audio Good Streams JPDR Count]' },
{ DataModelName: '[Measures].[Audio Poor Streams JPDR Count]' },]
};
$.ajax({
url: 'http://localhost/QoEDataService/RunQuery',
data: JSON.stringify(query),
type: 'POST',
async: true,
contentType: 'application/json;charset=utf-8',
success: function (data) {
//This is the jQuery syntax for document.GetElementById()
$('#AudioGoodStreamsJPDRCount').html(data.DataResult[0][1]);
$('#AudioPoorStreamsJPDRCount').html(data.DataResult[0][2]);
}
error: function (error) {
alert('Error getting data, check that the data service is running and that the URL is correct.');
}
});
});
Audio Good Streams JPDR Count
|
Audio Poor Streams JPDR Count
|
|
February |
到目前为止,报告仍然非常简单。 用户可以添加更多度量、维度或筛选器来自定义报表。 例如,如果你想要显示 AppSharing 质量欠佳的呼叫百分比,那么需要添加关于 AppSharing 的新度量。 如果要显示所有 TCP 调用 v.s。 UDP 调用,应添加与交通类型有关的新维度。 如果要显示特定建筑物内质量欠佳的呼叫数,应添加一个新筛选器,以选择该建筑物的呼叫。
示例 2:报告定义示例
在构造查询时,可能很难找出如何编写度量/维度/筛选器及其对应值的完整列表。 在这种情况下,您可以转到门户,使用报告编辑器生成报表,并查看报告定义的 JSON 字符串,然后将定义复制到自定义报告中。
本示例中,我们将创建一个网页,如图所示,用户可以输入任何现有报告集 (或报表) 的 ID,并在此网页上显示报告集或报表的定义。 然后,用户可以将每个报告的 JSON 字符串插入类似于示例 1 中所示的代码,并构造用户期望的任何自定义报告。
若要创建报告定义查看器工具,我们需要向存储库服务发送调用,以检索所需的每个报告集定义的 JSON 字符串表示形式。 存储库 API 将基于给定的报告集 ID 返回报告集定义。
一个快速示例如下所示,代码包含一个块,该块是一个简单示例,用于向存储库服务发送查询,以基于存储库项的标识符获取存储库项的内容。 下一部分代码 (processReportSetData 方法) 发送 AJAX 调用,获取该报表集内每个报告的定义。 由于 CQD Web 门户中的 ID 是报告集的 ID,因此 AJAX 调用将返回报告集项。 有关存储库 API(特别是 GetItems)的更多详细信息,可以在"获取项目" 中找到。
CQD Report definition viewer
ReportSet Id:
Load
var urlRepositoryApi = 'http://localhost/QoERepositoryService/repository/item/';
var loadReportSet = function ()
{
var reportSetId = document.getElementById('reportSetId').value;
$.ajax({
url: urlRepositoryApi + reportSetId,
data: '',
type: 'GET',
async: false,
contentType: 'application/json;charset=utf-8',
success: function (data) {
var reportSetDiv = document.getElementById('Report');
reportSetDiv.innerHTML = '';
processReportSetData(reportSetDiv, data);
},
error: function (error) {
alert('Error getting Report, check that the qoe data service is running and url is correct.');
}
});
};
var processReportSetData = function (divReportSet, reportSetDef) {
//show the report set definition like Title, Description, etc
showReportSetDefinition(divReportSet, reportSetDef);
//for each Report in the Reportset, get the Report definition from the Repository Service
for (var i = 0; i < reportSetDef.subItemIds.length; i++)
{
//the reportId is in the subItemIds array. This is not shown in the CQD UI at all
var reportId = reportSetDef.subItemIds[i];
var divReport = document.createElement('div');
divReport.style.margin = '12px';
divReportSet.appendChild(divReport);
//retrieve the report definition with the reportId
$.ajax({
url: urlRepositoryApi + reportId,
data: '',
type: 'GET',
async: false,
contentType: 'application/json;charset=utf-8',
success: function (reportData) {
processReportData(divReport, reportData, reportId);
},
error: function (error) {
alert('Error getting Report ' + reportId.toString() + ', check that the qoe data service is running and url is correct.');
}
});
}
};
//helper function to render the ReportSet definition
var showReportSetDefinition = function (divReportSet, reportSetDef) {
var div = document.createElement('div');
ReportSetDefinition = reportSetDef.content;
txt = document.createTextNode(ReportSetDefinition);
div.style.margin = '12px';
div.appendChild(txt);
divReportSet.appendChild(div);
};
//show the report definition
var processReportData = function (divReport, reportData, itemId) {
if (divReport != undefined && reportData.content != undefined) {
var Report = JSON.parse(reportData.content);
var divReportId = document.createElement('div');
var subItemId = reportData.subItemIds.length > 0 ? reportData.subItemIds[0].toString() : 'none';
divReportId.innerHTML = 'ItemId: ' + itemId.toString() + ' (' + Report.Title + ') [subItemId:' + subItemId + ']';
divReport.appendChild(divReportId);
var divReportDef = document.createElement('div');
txt = document.createTextNode(JSON.stringify(Report));
divReportDef.style.margin = '12px';
divReportDef.appendChild(txt);
divReport.appendChild(divReportDef);
}
};
上述内容将导致网页(如图所示) (首次访问时没有报告) 。 从 CQD 门户获取报告集 ID (/#/> 登录 CQD 门户 URL 之后,例如 (ID。 第一个图的报表集 ID 为 3024) ,将此报告集 ID 放入此网页的输入部分。 按"加载"按钮,查看 (、维度、筛选器列表) 报告集的完整定义。
总之,为了快速获取报告/报告集的完整定义。 步骤如下:
转到门户并使用查询编辑器自定义报表 (单击报表上方的"编辑"按钮以编辑、添加、删除度量/维度/筛选器,然后将报表) 。
从 URL 获取报告集 ID, ("/#/"登录 URL 之后获取) 。
启动在示例 2 中创建的此报告定义网页,并输入报告集 ID,并检索要用于数据 API 调用 (报告集) 。
示例 3:记分卡示例
更复杂的任务的时间。 如果我们希望创建如图所示的网页,该做什么? 我们需要更新示例 1, (在示例 2 中生成的网页的帮助下,检索任何报表) 的完整定义,以便我们可以处理更多的数据。
在这种情况下,我们需要更新度量和维度列表。 若要了解如何添加/编辑度量和/或维度,请按照示例 2 中的说明操作,并检索完整的报告定义,包括完整的度量和维度列表。 将完整的报告定义插入示例代码中。
下面是从示例 1 中提供的示例获取图中记分卡页面的详细步骤:
将"query"变量中的度量从和 [Measures].[Audio Good Streams JPDR Count] 更新 [Measures].[Audio Poor Streams JPDR Count] 到 [Measures].[AudioPoorJPDRPercentage] 。
更新筛选器。 示例 1 中 Filters 的 JSON 数据具有一个筛选器,该筛选器在维度上设置 [StartDate].[Month] 。 由于 Filters 是 JSON 数组,因此可以将其他维度添加到筛选器列表中。 例如,若要在"currentMonth"的有线呼叫内获取服务器-客户端,应具有以下筛选器:
Filters: [
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
{
"DataModelName": "[Scenarios].[ScenarioPair]",
"Caption": " Server-Inside-wired,Client-Inside-wired",
"Value": "[1]&[0]&[1]&[1]&[Wired]&[Wired]",
"Operand": 0,
"UnionGroup": ""
},
{ DataModelName: '[StreamType].[StreamType]', Caption: "Valid", Value: "[False]", Operand: 0, UnionGroup: "" }
],
此处将维度 [Scenarios].[ScenarioPair] 设置为相等 [1]&[0]&[1]&[1]&[Wired]&[Wired] 。 这是 [Scenario.][ScenarioPair] 为简化报表创建而创建的特殊维度。 它对应六个值 [FirstIsServer], [SecondIsServer], [FirstInside], [SecondIsServer], [FirstConnectionType], [SecondConnectionType] 。 因此,我们只需要使用 1 个筛选器,而不是使用 6 个筛选器的组合来定义方案。 在我们的示例中,值转换为以下方案:第一个为服务器,第二个不是服务器,第一个位于内部,第一个连接类型为有线,第二个连接类型为有线,这是 [1]&[0]&[1]&[1]&[Wired]&[Wired] "Server-Client-Inside Wired"的确切定义。
每个方案创建一个筛选器集。 图中记分卡的每一行表示不同的方案,即不同的筛选器 (而维度和度量保持不变) 。
分析 AJAX 调用的结果,将它们放在表的正确位置。 由于这主要是 HTML 和 JavaScript 操作,因此我们不会在此处了解详细信息。 相反,代码在附录 A 中提供。
备注
如果启用了跨源资源 (CORS) ,则用户可能会遇到"请求的资源上不存在"Access-Control-Allow-Origin"标头等错误。 因此,不允许访问原点"null"。 若要解决此问题,将 HTML 文件放在默认情况下安装门户 (文件夹下,它应该是 %SystemDrive%\Program Files\Skype for Business 2015 CQD\CQD) 。 然后,通过具有 URL 的任何浏览器访问 http:///cqd/ html。 (本地 CQD 仪表板的默认 URL 为 http:///cqd.)
附录 A
示例 3 的 HTML 代码 (记分卡示例) :
Scoreboard Sample
.row {
margin-right: -15px;
margin-left: -15px;
display: table-row;
}
.col-md-3 {
width: 25%;
display: table-cell;
}
.col-md-2 {
width: 16.66666667%;
display: table-cell;
}
.col-md-1 {
width: 8.33333333%;
display: table-cell;
}
Scoreboard Sample
|
Poor Call %
Month1
Month2
Month3
Month4
Month5
Month6
Wired
Server-Server
Server-Client (inside)
Server-Client (outside)
Client-Client (inside)
Client-Client (outside)
Wireless
Server-Client (inside)
Server-Client (outside)
Client-Client (inside)
Client-Client (outside)
Mobile/Broadband
Server-MobilePhone
Server-MobileBroadBand
Lync Web App
Server-Client (inside & outside)
|
$(function () {
var month_names_short = ['NAM', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var currentMonth = '2015-3';
//update the header with the month names
var row = document.getElementById('Header');
var numMonthsToShow = 6;
for (var m = numMonthsToShow-1; m >= 0; m--) {
var dateSplit = currentMonth.split('-');
var monthInt = parseInt(dateSplit[1]);
var yearInt = parseInt(dateSplit[0]);
monthInt = monthInt - m;
if (monthInt < 1)
{
monthInt += 12;
yearInt--;
}
row.children[numMonthsToShow-m].innerHTML = month_names_short[monthInt];
}
var queries = [
{
Label: "Server-Server",
ID: "SS",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]'}],
Filters: [
{
"DataModelName": "[Scenarios].[ScenarioPair]",
"Caption": " Server-Inside-wired,Server-Inside-wired",
"Value": "[1]&[1]&[1]&[1]&[Wired]&[Wired]",
"Operand": 0,
"UnionGroup": ""
},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
{ DataModelName: '[StreamType].[StreamType]', Caption: "Valid", Value: "[False]", Operand: 0, UnionGroup: ""}
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]'}],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
},
{
Label: "Server-Client (inside)",
ID: "SWI",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{
"DataModelName": "[Scenarios].[ScenarioPair]",
"Caption": " Server-Inside-wired,Client-Inside-wired",
"Value": "[1]&[0]&[1]&[1]&[Wired]&[Wired]",
"Operand": 0,
"UnionGroup": ""
},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
{ DataModelName: '[StreamType].[StreamType]', Caption: "Valid", Value: "[False]", Operand: 0, UnionGroup: "" }
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
},
{
Label: "Server-Client (outside)",
ID: "SWO",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{
"DataModelName": "[Scenarios].[ScenarioPair]",
"Caption": " Server-Inside-wired,Client-Outside-wired",
"Value": "[1]&[0]&[1]&[0]&[Wired]&[Wired]",
"Operand": 0,
"UnionGroup": ""
},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
{ DataModelName: '[StreamType].[StreamType]', Caption: "Valid", Value: "[False]", Operand: 0, UnionGroup: "" }
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
},
{
Label: "Client-Client (inside)",
ID: "WWI",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{
"DataModelName": "[Scenarios].[ScenarioPair]",
"Caption": " Client-Inside-wired,Client-Inside-wired",
"Value": "[0]&[0]&[1]&[1]&[Wired]&[Wired]",
"Operand": 0,
"UnionGroup": ""
},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
{ DataModelName: '[StreamType].[StreamType]', Caption: "Valid", Value: "[False]", Operand: 0, UnionGroup: "" }
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
}
,
{
Label: "Client-Client (outside)",
ID: "WIWO",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{
"DataModelName": "[Scenarios].[ScenarioPair]",
"Caption": "Client-Outside-Wired,Client-Outside-Wired",
"Value": "[0]&[0]&[0]&[0]&[Wired]&[Wired]",
"Operand": 0,
"UnionGroup": ""
},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
{ DataModelName: '[StreamType].[StreamType]', Caption: "Valid", Value: "[False]", Operand: 0, UnionGroup: "" }
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
},
{
Label: "Server-Client (inside)",
ID: "SWFI",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{
"DataModelName": "[Scenarios].[ScenarioPair]",
"Caption": " Server-Inside-wired,Client-Inside-wifi",
"Value": "[1]&[0]&[1]&[1]&[Wired]&[Wifi]",
"Operand": 0,
"UnionGroup": ""
},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
{ DataModelName: '[StreamType].[StreamType]', Caption: "Valid", Value: "[False]", Operand: 0, UnionGroup: "" }
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
},
{
Label: "Server-Client (outside)",
ID: "SWFO",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{
"DataModelName": "[Scenarios].[ScenarioPair]",
"Caption": " Server-Inside-wired,Client-Outside-wifi",
"Value": "[1]&[0]&[1]&[0]&[Wired]&[Wifi]",
"Operand": 0,
"UnionGroup": ""
},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
{ DataModelName: '[StreamType].[StreamType]', Caption: "Valid", Value: "[False]", Operand: 0, UnionGroup: "" }
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
},
{
Label: "Client-Client (inside)",
ID: "WFIWFI",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{
"DataModelName": "[Scenarios].[ScenarioPair]",
"Caption": " Client-Inside-Wifi,Client-Inside-Wifi",
"Value": "[0]&[0]&[1]&[1]&[Wifi]&[Wifi]",
"Operand": 0,
"UnionGroup": ""
},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
{ DataModelName: '[StreamType].[StreamType]', Caption: "Valid", Value: "[False]", Operand: 0, UnionGroup: "" }
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
},
{
Label: "Client-Client (outside)",
ID: "WFOWFO",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{
"DataModelName": "[Scenarios].[ScenarioPair]",
"Caption": "Client-Outside-Wifi,Client-Outside-Wifi",
"Value": "[0]&[0]&[0]&[0]&[Wifi]&[Wifi]",
"Operand": 0,
"UnionGroup": ""
},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
{ DataModelName: '[StreamType].[StreamType]', Caption: "Valid", Value: "[False]", Operand: 0, UnionGroup: "" }
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
},
{
Label: "Server-MobilePhone",
ID: "SMP",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{"DataModelName": "[First Is Server].[Agent]","Caption": "Server","Value": "[1]","Operand": 0,"UnionGroup": ""},
{"DataModelName": "[Second User Agent].[User Agent Type]","Caption": "AndroidLync | iPhoneLync | WPLync","Value": "[AndroidLync],[iPhoneLync],[WPLync]","Operand": 0,"UnionGroup": ""},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 },
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
},
{
Label: "Server-MobileBroadBand",
ID: "SMBB",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{"DataModelName": "[Second Network Connection Type].[Network Connection Detail]","Caption": "MobileBB","Value": "[MobileBB]","Operand": 0,"UnionGroup": ""},
{"DataModelName": "[First Is Server].[Agent]","Caption": "Server","Value": "[1]","Operand": 0,"UnionGroup": ""},
{"DataModelName": "[Second Is Server].[Agent]","Caption": "Client ","Value": "[0]","Operand": 0,"UnionGroup": ""},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 }
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
},
{
Label: "Server-LWA",
ID: "SLWA",
Query:
{
Dimensions: [{ DataModelName: '[StartDate].[Month]' }],
Filters: [
{"DataModelName": "[First Is Server].[Agent]","Caption": "Server","Value": "[1]","Operand": 0,"UnionGroup": ""},
{"DataModelName": "[Second User Agent].[User Agent Type]","Caption": "LWA","Value": "[LWA]","Operand": 0,"UnionGroup": ""},
{ DataModelName: '[StartDate].[Month]', Value: currentMonth, Operand: 0 }
],
Measurements: [{ DataModelName: '[Measures].[AudioPoorJPDRPercentage]' }],
Trend: { EnableTrend: true, SpanCount: numMonthsToShow, TrendDate: currentMonth, Type: 0 }
}
}
];
//get the overall corpnet data
for (var i = 0; i < queries.length; i++) {
$.ajax({
url: 'http://localhost/QoEDataService/RunQuery',
data: JSON.stringify(queries[i].Query),
type: 'POST',
async: false,
withCredentials: true,
contentType: 'application/json;charset=utf-8',
success: function (data) {
//find the table row corresponding to the name of this query
var row = document.getElementById(queries[i].ID);
//update the values for each month
for (var m = 0; m < data.DataResult.length; m++)
{
row.children[m + 1].innerHTML = data.DataResult[m][1].toFixed(2).toString();
}
},
error: function (error) {
var row = document.getElementById(queries[i].ID);
row.children[1].innerHTML = 'error';
}
});
}
});
仪表板 ajax实例,CQD 开发示例 - Skype for Business Server 2015 | Microsoft Docs相关推荐
- Skype for Business Server 2015系列(一)概述和准备工作
对于Lync,相信熟悉微软产品的小伙伴都比较了解了,作为微软旗下的即时通讯软件,面向企业用户,全球500强中的70%都在使用Lync.在今年4月份的时候,微软将 Lync 更名为 Skype for ...
- Skype For Business Server 2015 离线消息
对于之前使用Lync或Skype的用户都会经常吐槽无法发送离线消息,那么对Skype For Business Server 2015 CU3开始就支持了离线IM,但是对客户端同样是有很高要求的. 离 ...
- Skype For Business Server 2015
在Skype For Business Server 2015发布之后,自己也进行了一些测试,总体的部署配置上跟Lync Server 2013的步骤是非常相似的.而且微软Technet网站上SFB的 ...
- Skype for Business Server与Microsoft Teams的长期共存模式
自从去年7月份Skype for Business Online被微软停用以后,还是有很多的企业没有把Skype用户迁移到Teams上面,而且主要的原因就是各种各样的规定不允许去做迁移.但是用户还是可 ...
- Skype for business server 2015和PSTN集成后,无法完成呼叫
最近做了一个关于SFB2015和PSTN语音网关集成的项目,遇到了问题,无法完成呼叫.在此将此问题及处理方法分享给大家,希望对大家有所帮助. 问题描述: 通过SFB205客户端拨打电话时报错,如下: ...
- Skype for Business Server 2015-06-持久聊天服务器-3-配置
申明:文章中部分内容有涉及官方帮助或者网上资源整合,如有违权,请速与作者联系,谢谢! 作者:316191099@qq.com 培训:Skype for Business Server 2015-项目实 ...
- 组件skype服务器,Skype for Business Server 中的中介服务器组件
Skype for Business Server 中的中介服务器组件Mediation Server component in Skype for Business Server 2021/3/24 ...
- 前端服务器共享的文件产品内容,Skype for Business Server 2015-04-前端服务器-2-创建一个文件共享...
申明:文章中部分内容有涉及官方帮助或者网上资源整合,如有违权,请速与作者联系,谢谢! 作者:316191099@qq.com 培训:Skype for Business Server 2015-项目实 ...
- Skype for Business Server 2019 本地部署
Skype for Business Server 2019预览版在七月底已经发布,公开披露新增了四个主要功能,云语音邮件.云自动话务员.云呼叫数据连接器.简化的Teams迁移,越来与Office 3 ...
最新文章
- 软件测试学java,软件测试学习Java的内存模型
- Java线程:线程的调度-合并
- [Android]乐Pad开发准备
- 谈谈感想,8元体会易生信培训
- SpringBoot 精通系列-SpringBoot如何操作Memcache
- linux版Nacos安装、集群配置
- 全球最大的同性交友网站,竟然还有这些骚操作
- 樱花FRP(SAKURA FRP)远程桌面+rdpwrap绕过限制
- Hibernate中类的继承使用union-subclass实现
- 5 月最大的 GameFi 崩溃受害者能否在熊市中生存?| May Monthly Report
- python入门教程陈孟林_Python快速入门指南,没基础没关系
- DSPE-PEG9-Mal纯度是95%以上的单分散小分子PEG试剂
- [苹果开发者账号]02 申请苹果开发者账号 快速申请邓白氏编码DUNS(提示:抱歉,您暂时不能注册)
- ZCANPRO的.can文件解析
- java 自旋_java自旋锁的代码实现
- linux修改文件名的三种方法
- Mutation Observer API
- 电磁场与电磁波-2-恒定电场
- 上网看视频国家版八段锦,很好的预防和治疗久坐办公室带来的肩周颈椎疾病...
- 有时,你需要宣扬你的野心
热门文章
- 搭建个人网站---域名+解析+github
- jQuery 性能优化
- 亚马逊运营怎么做广告?六大方法!
- 如何制定SEO文章发布模板?
- gala米兰达斯(Mirandus)游戏介绍
- Hadoop-2.7.1+Zookeeper-3.4.8+HBase-1.2.1+Hive-2.0.0完全分布式集群
- 华为平板可不可以安装Android,华为平板能跟iPad过招?MatePad Pro在安卓称王但用户不一定买单...
- 前端基础_像素的处理
- PHP获取图片和视频类型
- Mac电脑搞自动化浏览器总是自动化更新怎么办?看这个就可以了。