089 xl json dates, gpu fixes
This commit is contained in:
+2
-1
@@ -15,6 +15,7 @@
|
||||
<cfset this.mappings["/mod"] = getDirectoryFromPath(getCurrentTemplatePath()) & "mod/" />
|
||||
<cfset this.customTagPaths = expandPath(getDirectoryFromPath(getCurrentTemplatePath())&'mod')/>
|
||||
<cfset this.timeZone = "Europe/Moscow"/><!--- для биллинга очень важен часовой пояс, поэтому ставим вручную в коде --->
|
||||
<!--- <cfset this.serialization.json.date = "iso8601"/> --->
|
||||
<cfset this.datasource = "dwh"/>
|
||||
|
||||
<cfset this.defaultdatasource = this.datasource/>
|
||||
@@ -87,7 +88,7 @@
|
||||
|
||||
<!--- global settings --->
|
||||
<!--- *************************************************************************************************** --->
|
||||
<cfset request.APP_VERSION="0.00.087"/> <!--- *********************************************************** --->
|
||||
<cfset request.APP_VERSION="0.00.089"/> <!--- *********************************************************** --->
|
||||
<!--- *************************************************************************************************** --->
|
||||
<cfset request.STAND=getStand()/>
|
||||
<cfset request.RECORDS_PER_PAGE=500/>
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
k.__name as contragent
|
||||
,k.id_klienta as wz
|
||||
,k.__index as contragent_index
|
||||
,d."_plannedDueDate" as _plannedDueDate
|
||||
<!--- ,d."_plannedDueDate" as _plannedDueDate --->
|
||||
,d."__createdAt"
|
||||
,d."__index" as deal_index
|
||||
,s.status
|
||||
@@ -131,12 +131,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tr">
|
||||
<!--- <div class="tr">
|
||||
<div class="th">_plannedDueDate</div>
|
||||
<div class="td">#dateFormat(qDecoration._plannedDueDate,'YYYY-MM-DD')#
|
||||
Паразитное поле, не использовать в расчетах
|
||||
</div>
|
||||
</div>
|
||||
</div> --->
|
||||
|
||||
<div class="tr">
|
||||
<div class="th">Статус</div>
|
||||
|
||||
+26
-8
@@ -8,21 +8,39 @@
|
||||
<m:prepare_ls entity="crm2cloud" accessObject="" pageInfoOut="pageInfo" trackOut="tr"/>
|
||||
|
||||
|
||||
<cfset this.nullSupport = true/>
|
||||
|
||||
|
||||
<cfquery name="qGPU" datasource="billing-vc" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
|
||||
select obj_uuid, obj_id, client_id as WZ, vcd, org, org_vdc, vcenter, gpu, dt_load, dt_load_ts, org_status, cluster as clus, is_template
|
||||
<cfquery name="qRead" datasource="billing-vc" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
|
||||
select
|
||||
<d:field_set titleMapOut="titleMap" lengthOut="fieldCount">
|
||||
<d:field>obj_uuid::text as obj_uuid</d:field>
|
||||
<d:field>obj_id</d:field>
|
||||
<d:field>client_id as WZ</d:field>
|
||||
<d:field>vcd</d:field>
|
||||
<d:field>org</d:field>
|
||||
<d:field>org_vdc</d:field>
|
||||
<d:field>vcenter</d:field>
|
||||
<d:field>gpu::text as gpu</d:field>
|
||||
<d:field cfSqlType="CF_SQL_TIMESTAMP">dt_load</d:field>
|
||||
<d:field cfSqlType="CF_SQL_TIMESTAMP">dt_load_ts</d:field>
|
||||
<d:field>org_status</d:field>
|
||||
<d:field>cluster as clus</d:field>
|
||||
<d:field cfSqlType="CF_SQL_BOOLEAN" formatter=#request.castToBoolSimple#>is_template</d:field>
|
||||
<d:field cfSqlType="CF_SQL_BOOLEAN" formatter=#request.castToBoolSimple#>(1=1) as t1</d:field>
|
||||
<d:field cfSqlType="CF_SQL_BOOLEAN" formatter=#request.castToBoolSimple#>(1=0) as t2</d:field>
|
||||
<d:field cfSqlType="CF_SQL_BOOLEAN" formatter=#request.castToBoolSimple#>(1=null) as t3</d:field>
|
||||
</d:field_set>
|
||||
from gpu.vm
|
||||
order by client_id
|
||||
</cfquery>
|
||||
|
||||
<!--- <cfdump var=#qGPU# abort=true/> --->
|
||||
<!--- <cfdump var=#qRead# abort=true/> --->
|
||||
|
||||
<cfif isDefined("output_xls")>
|
||||
<layout:xml qRead=#qCharge# titleMap=#titleMap# filename="#pageInfo.entity#.xml"/>
|
||||
<layout:xml qRead=#qRead# titleMap=#titleMap# filename="#pageInfo.entity#.xml"/>
|
||||
<cfabort/>
|
||||
</cfif><cfif isDefined("output_json")>
|
||||
<layout:json qRead=#qCharge# titleMap=#titleMap# filename="#pageInfo.entity#.json"/>
|
||||
<layout:json qRead=#qRead# titleMap=#titleMap# filename="#pageInfo.entity#.json"/>
|
||||
<cfabort/>
|
||||
</cfif><!---
|
||||
---><layout:page section="header" pageInfo=#pageInfo#>
|
||||
@@ -45,7 +63,7 @@ order by client_id
|
||||
|
||||
<a href="#request.thisPage#?output_json" title="экспорт в json" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/json.svg" style="vertical-align:text-bottom;" width="13" height="13"/></a>
|
||||
</cfoutput>
|
||||
<cfoutput><b>#qGPU.recordCount#</b></cfoutput>
|
||||
<cfoutput><b>#qRead.recordCount#</b></cfoutput>
|
||||
<table class="worktable">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -62,7 +80,7 @@ order by client_id
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<cfoutput query="qGPU">
|
||||
<cfoutput query="qRead">
|
||||
<tr>
|
||||
<td><a href="contragent.cfm?wz=#WZ#&#tr.fwx#">#WZ#</a></td>
|
||||
<td>#obj_uuid#</td>
|
||||
|
||||
@@ -311,6 +311,29 @@ public string function formatJsonString(str) {
|
||||
}
|
||||
request.formatJsonString = formatJsonString;
|
||||
//нужна еще функция, которая сериализует структуру как pretty printed json. См. https://github.com/bennadel/JsonSerializer.cfc (все не совсем просто, например, не заранее не определен формат даты)
|
||||
|
||||
/**
|
||||
* @hint Приводит поле резалтсета к булевому типу, пригодному для сериализации в json, вместо null возвращает false.
|
||||
*/
|
||||
boolean function castToBoolSimple(any x) {
|
||||
if ( !structKeyExists( arguments, "x" ) || isNull( arguments.x ) ) {
|
||||
return false;
|
||||
}
|
||||
// 2. Handle empty strings, empty arrays, or empty structs
|
||||
if ( isSimpleValue( arguments.x ) && trim( arguments.x ) == "" ) {
|
||||
return false;
|
||||
}
|
||||
if ( isArray( arguments.x ) && arrayIsEmpty( arguments.x ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( isStruct( arguments.x ) && structIsEmpty( arguments.x ) ) {
|
||||
return false;
|
||||
}
|
||||
// 3. Fall back to standard CFML truthy evaluation
|
||||
return isBoolean( arguments.x ) && arguments.x ? true : false;
|
||||
}
|
||||
request.castToBoolSimple=castToBoolSimple;
|
||||
|
||||
</cfscript>
|
||||
|
||||
<cffunction name=structGetKey>
|
||||
@@ -361,3 +384,5 @@ request.formatJsonString = formatJsonString;
|
||||
</cffunction>
|
||||
<cfset request.camel2snake = camel2snake/>
|
||||
|
||||
|
||||
|
||||
|
||||
+59
-4
@@ -67,7 +67,7 @@
|
||||
</cfloop>
|
||||
|
||||
<cfset var outArray=arrayNew(1)/>
|
||||
//copy fields to structure, renaming fields, this preserves data type
|
||||
<!--- //copy fields to structure, renaming fields, this preserves data type --->
|
||||
<cfloop query=#arguments.qry#>
|
||||
<cfset var structRow=structNew()/>
|
||||
<cfloop index="i" from="1" to=#listLen(columnsOut)#>
|
||||
@@ -76,9 +76,9 @@
|
||||
<cfset arrayAppend(outArray,structRow)/>
|
||||
</cfloop>
|
||||
|
||||
<cfreturn serializeJSON(outArray)/>
|
||||
<cfreturn customJson(outArray)/>
|
||||
<cfelse>
|
||||
<cfreturn serializeJSON(arguments.qry,"struct")/>
|
||||
<cfreturn customJson(arguments.qry,"struct")/>
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
@@ -96,4 +96,59 @@
|
||||
type="application/json"
|
||||
/><cfoutput>#query2json(ATTRIBUTES.qRead,ATTRIBUTES.convertSnakeToCamel)#</cfoutput><!---
|
||||
,<cfoutput>"duration":"#(getTickCount()- msStartAt)#"</cfoutput>} --->
|
||||
<cfexit method="exittag"/>
|
||||
<cfexit method="exittag"/>
|
||||
|
||||
<!--- *** еще добиться форматирования null, true, false
|
||||
https://www.bennadel.com/blog/2165-returning-null-values-in-json-using-serializejson-and-coldfusion.htm
|
||||
--->
|
||||
<cfscript>
|
||||
public string function customJson(required any data) {
|
||||
return serializeJson(formatDatesToIso(arguments.data));
|
||||
}
|
||||
|
||||
private any function formatDatesToIso(required any input) {
|
||||
// 1. Handle Dates (Strict verification using isValid and checking underlying type)
|
||||
// Lucee dates are typically objects (java.util.Date / java.time).
|
||||
// This prevents strings like "12345" or "Yes" from being treated as dates.
|
||||
if (isDate(arguments.input) && (isObject(arguments.input) || !isValid("integer", arguments.input))) {
|
||||
return dateTimeFormat(arguments.input, "iso8601");
|
||||
}
|
||||
|
||||
// 2. Handle Structs (Preserve case-sensitivity using [:] syntax)
|
||||
if (isStruct(arguments.input)) {
|
||||
var newStruct = [Ordered: true]; // Lucee/CF literal for preserving key case
|
||||
for (var key in arguments.input) {
|
||||
newStruct[key] = formatDatesToIso(arguments.input[key]);
|
||||
}
|
||||
return newStruct;
|
||||
}
|
||||
|
||||
// 3. Handle Arrays
|
||||
if (isArray(arguments.input)) {
|
||||
var newArray = [];
|
||||
for (var item in arguments.input) {
|
||||
arrayAppend(newArray, formatDatesToIso(item));
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
// 4. Handle Queries
|
||||
if (isQuery(arguments.input)) {
|
||||
var queryArray = [];
|
||||
var columns = arguments.input.getColumnNames(); // Returns correct case array
|
||||
|
||||
loop query="arguments.input" {
|
||||
var rowStruct = [Ordered: true];
|
||||
loop array="#columns#" index="col" {
|
||||
// Safely grab cell using row coordinates
|
||||
rowStruct[col] = formatDatesToIso(arguments.input[col][arguments.input.currentRow]);
|
||||
}
|
||||
arrayAppend(queryArray, rowStruct);
|
||||
}
|
||||
return queryArray;
|
||||
}
|
||||
|
||||
// 5. Return everything else untouched (Strings, Numbers, Booleans, etc.)
|
||||
return arguments.input;
|
||||
}
|
||||
</cfscript>
|
||||
@@ -219,7 +219,7 @@ ORDER BY
|
||||
<td class="c<cfif NOT (status EQ "prod" OR status EQ "internal-test") AND isDate(dt_end_of_test) AND dt_end_of_test LE Now()> b err</cfif>">#dateFormat(dt_end_of_test,"YYYY-MM-DD")#</td>
|
||||
|
||||
<td><a href="deal.cfm?__id=#deal_uid#&#tr.fwx#">#deal#</a></td>
|
||||
<td>#deal_status# [#status_id#]</td>
|
||||
<td>#deal_status#<cfif len(status_id)> [#status_id#]</cfif></td>
|
||||
|
||||
<td><a href="additional_agreement.cfm?__id=#additional_agreement_uid#&#tr.fwx#">#additional_agreement#</a></td>
|
||||
<td><a href="contract.cfm?__id=#contract_uid#&#tr.fwx#">#contract#</a> <cfif contract_id NEQ contract>(#contract_id#)</cfif> </td>
|
||||
|
||||
+3
-2
@@ -89,9 +89,10 @@ GPU-VM Power State: <b<cfif datediff("h",qGpuAge.dt_load, Now()) GT 24> class="e
|
||||
</b>
|
||||
|
||||
<br/>
|
||||
<a href="#request.thisPage#?output_xls" title="экспорт в Excel" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/xls.gif" style="vertical-align:text-bottom;"/></a>
|
||||
<a href="#request.thisPage#?output_xls&dt_start=#dateFormat(dt_start,'YYYY-MM-DD')#&dt_finish=#dateFormat(dt_finish,'YYYY-MM-DD')#" title="экспорт в Excel" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/xls.gif" style="vertical-align:text-bottom;"/></a>
|
||||
|
||||
<a href="#request.thisPage#?output_json" title="экспорт в json" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/json.svg" style="vertical-align:text-bottom;" width="13" height="13"/></a>
|
||||
<a href="#request.thisPage#?output_json&dt_start=#dateFormat(dt_start,'YYYY-MM-DD')#&dt_finish=#dateFormat(dt_finish,'YYYY-MM-DD')#" title="экспорт в json" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/json.svg" style="vertical-align:text-bottom;" width="13" height="13"/></a>
|
||||
<i>(перед выгрузкой отчета на произвольную дату просмотрите его в браузере)</i>
|
||||
</cfoutput>
|
||||
<table class="worktable">
|
||||
<thead>
|
||||
|
||||
Reference in New Issue
Block a user