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

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相关推荐

  1. Skype for Business Server 2015系列(一)概述和准备工作

    对于Lync,相信熟悉微软产品的小伙伴都比较了解了,作为微软旗下的即时通讯软件,面向企业用户,全球500强中的70%都在使用Lync.在今年4月份的时候,微软将 Lync 更名为 Skype for ...

  2. Skype For Business Server 2015 离线消息

    对于之前使用Lync或Skype的用户都会经常吐槽无法发送离线消息,那么对Skype For Business Server 2015 CU3开始就支持了离线IM,但是对客户端同样是有很高要求的. 离 ...

  3. Skype For Business Server 2015

    在Skype For Business Server 2015发布之后,自己也进行了一些测试,总体的部署配置上跟Lync Server 2013的步骤是非常相似的.而且微软Technet网站上SFB的 ...

  4. Skype for Business Server与Microsoft Teams的长期共存模式

    自从去年7月份Skype for Business Online被微软停用以后,还是有很多的企业没有把Skype用户迁移到Teams上面,而且主要的原因就是各种各样的规定不允许去做迁移.但是用户还是可 ...

  5. Skype for business server 2015和PSTN集成后,无法完成呼叫

    最近做了一个关于SFB2015和PSTN语音网关集成的项目,遇到了问题,无法完成呼叫.在此将此问题及处理方法分享给大家,希望对大家有所帮助. 问题描述: 通过SFB205客户端拨打电话时报错,如下: ...

  6. Skype for Business Server 2015-06-持久聊天服务器-3-配置

    申明:文章中部分内容有涉及官方帮助或者网上资源整合,如有违权,请速与作者联系,谢谢! 作者:316191099@qq.com 培训:Skype for Business Server 2015-项目实 ...

  7. 组件skype服务器,Skype for Business Server 中的中介服务器组件

    Skype for Business Server 中的中介服务器组件Mediation Server component in Skype for Business Server 2021/3/24 ...

  8. 前端服务器共享的文件产品内容,Skype for Business Server 2015-04-前端服务器-2-创建一个文件共享...

    申明:文章中部分内容有涉及官方帮助或者网上资源整合,如有违权,请速与作者联系,谢谢! 作者:316191099@qq.com 培训:Skype for Business Server 2015-项目实 ...

  9. Skype for Business Server 2019 本地部署

    Skype for Business Server 2019预览版在七月底已经发布,公开披露新增了四个主要功能,云语音邮件.云自动话务员.云呼叫数据连接器.简化的Teams迁移,越来与Office 3 ...

最新文章

  1. 软件测试学java,软件测试学习Java的内存模型
  2. Java线程:线程的调度-合并
  3. [Android]乐Pad开发准备
  4. 谈谈感想,8元体会易生信培训
  5. SpringBoot 精通系列-SpringBoot如何操作Memcache
  6. linux版Nacos安装、集群配置
  7. 全球最大的同性交友网站,竟然还有这些骚操作
  8. 樱花FRP(SAKURA FRP)远程桌面+rdpwrap绕过限制
  9. Hibernate中类的继承使用union-subclass实现
  10. 5 月最大的 GameFi 崩溃受害者能否在熊市中生存?| May Monthly Report
  11. python入门教程陈孟林_Python快速入门指南,没基础没关系
  12. DSPE-PEG9-Mal纯度是95%以上的单分散小分子PEG试剂
  13. [苹果开发者账号]02 申请苹果开发者账号 快速申请邓白氏编码DUNS(提示:抱歉,您暂时不能注册)
  14. ZCANPRO的.can文件解析
  15. java 自旋_java自旋锁的代码实现
  16. linux修改文件名的三种方法
  17. Mutation Observer API
  18. 电磁场与电磁波-2-恒定电场
  19. 上网看视频国家版八段锦,很好的预防和治疗久坐办公室带来的肩周颈椎疾病...
  20. 有时,你需要宣扬你的野心

热门文章

  1. 搭建个人网站---域名+解析+github
  2. jQuery 性能优化
  3. 亚马逊运营怎么做广告?六大方法!
  4. 如何制定SEO文章发布模板?
  5. gala米兰达斯(Mirandus)游戏介绍
  6. Hadoop-2.7.1+Zookeeper-3.4.8+HBase-1.2.1+Hive-2.0.0完全分布式集群
  7. 华为平板可不可以安装Android,华为平板能跟iPad过招?MatePad Pro在安卓称王但用户不一定买单...
  8. 前端基础_像素的处理
  9. PHP获取图片和视频类型
  10. Mac电脑搞自动化浏览器总是自动化更新怎么办?看这个就可以了。