為了讓每一個數字都能夠顯示 Raw Data,James 採用了 Ext Window 來呈現資料明細。
亦即按下數字的 Link,會直接在頁面中開啟視窗,並以 Grid 的方式呈現資料。與前面 Grid 的作法不同的是,這裡 James 採用的是 Ext js 4.0 的新功能 Grouping Data,可以做出小計的功能。
James 將之前 grid_Stock.js 中 Column 的 renderer 改寫:
{
text: '銷售預測(PM)' ,
columns: [{
text: lfsq,
width: 80,
align: 'right',
renderer: Ext.util.Format.numberRenderer( '0,000,000,000' ),
dataIndex: 'fq'
}
renderer 改以 inline function 的方式,加入 URL Link,並且維持數字格式的輸出。
{
text: '銷售預測(PM)' ,
columns: [{
text: lfsq,
width: 80,
align: 'right',
renderer: function (value, metaData, record, row, col, store, gridView) {
return (value == 0) ? Ext.util.Format.number(value, '0,000,000,000') : '<a href="javascript:winFcstDetail(\'' + part_id + '\',\'' + lfsq + '\',\'銷售預測(PM)\');" title="點選查詢明細">' + Ext.util.Format.number(value, '0,000,000,000') + '</a>' ;
},
dataIndex: 'fq'
}
為了讓每一個數字的 Link 都達到同樣的功能,James 將 Open Window 的動作寫成模組,讓每一次的呼叫只要傳遞相關參數即可,以簡化程式碼的撰寫。
James 設計了一支 mdlERP.js,作為撰寫共用的 Library 的地方。
mdlERP.js
function winFcstDetail(part_id, yymm, stype) {
createWindow(stype + ':' + part_id + ' 年月:' + yymm, 235, 724, 'qryFcst.aspx?part_id=' + part_id + '&yymm=' + yymm + '&stype=' + stype);
}
function winResaleDetail(part_id, yymm) {
createWindow('銷售查詢:' + part_id + ' 年月:' + yymm, 235, 724, 'qryResale.aspx?part_id=' + part_id + '&yymm=' + yymm);
}
function winProcDetail(slip_no, slip_date, part_id, yymm, agg_type, s1, s2, op) {
createWindow('採購單查詢:' + part_id + ' ' + ((agg_type == 'week' ) ? ' 區間:' : ' 年月:') + yymm, 235, 724, 'qryProc.aspx?slip_no=' + slip_no + '&slip_date=' + slip_date + '&part_id=' + part_id + '&s1=' + s1 + '&s2=' + s2 + '&agg_type=' + agg_type + '&op=' + op);
}
function winOrderDetail(slip_no, slip_date, part_id, yymm, agg_type, s1, s2, op) {
createWindow('客戶訂單查詢:' + part_id + ' ' + ((agg_type == 'week') ? ' 區間:' : ' 年月:' ) + yymm, 235, 724, 'qryOrder.aspx?slip_no=' + slip_no + '&slip_date=' + slip_date + '&part_id=' + part_id + '&s1=' + s1 + '&s2=' + s2 + '&agg_type=' + agg_type + '&op=' + op);
}
function createWindow(t, h, w, s) {
Ext.create('Ext.window.Window', {
title: t,
height: h,
width: w,
layout: 'fit',
modal: true,
iframe: true,
closeAction: 'hide',
resizable: false,
bodyBorder: false,
animate: true,
html: '<iframe src="' + s + '" style="overflow:auto;width:100%;height:100%;" frameborder="0">'
}).show();
}
在 createWindow 中,James 透過 iFrame 的手法(註1),將 Grid 嵌入Windows Layout 當中,而且透過 Config,Window 可以做出 Modal 效果,同時也可以在頁面上移動位置,對於使用者的操作來說,相當方便。更重要的是,他還是在同一個頁面當中,並沒有實際開啟 Browser 視窗。
iFrame 指向的網頁,同樣的也 include 了相對應的 js 來建構 Detail 的 Grid。
grid_Fcst_Detail.js
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.state.*'
]);
Ext.onReady(function () {
var sign = "";
Ext.QuickTips.init();
var store = new Ext.data.JsonStore({
// store configs
autoDestroy: true,
storeId: 'Sold',
proxy: {
type: 'ajax',
url: 'BusinessObject/qryEISbySQL.aspx?sql=select part_id,cust_abv,pm_nm,sales_nm,asp as fup,curncy as fcur,sum(qty) as fqty,sum(fcst_amt) as famt,sum(qty_s) as sqty,sum(sold_amt) as samt from fcst_' + stype + '_eis where yymm=\'' + yymm + '\' and part_id=\'' + encodeURIComponent(part_id) + '\' group by part_id,cust_abv,pm_nm,sales_nm,asp,curncy',
reader: {
type: 'json'
}
},
//alternatively, a Ext.data.Model name can be given (see Ext.data.Store for an example)
fields: [
{ name: 'cust_abv', type: 'string' },
{ name: 'pm_nm', type: 'string' },
{ name: 'sales_nm', type: 'string' },
{ name: 'sqty', type: 'float' },
{ name: 'samt', type: 'float' },
{ name: 'part_id', type: 'string' },
{ name: 'fqty', type: 'float' },
{ name: 'fup', type: 'float' },
{ name: 'famt', type: 'float' }
],
groupField: 'part_id'
});
// create the Grid
var grid = Ext.create( 'Ext.grid.Panel', {
store: store,
columnLines: false,
enableColumnHide: false,
features: [{
id: 'group',
ftype: 'groupingsummary',
groupHeaderTpl: '{name}',
hideGroupedHeader: true,
enableGroupingMenu: false
}],
columns: [{
text: '料號',
flex: 1,
tdCls: 'parts',
locked: true,
sortable: true,
dataIndex: 'part_id',
hideable: false,
summaryType: 'count',
summaryRenderer: function (value, summaryData, dataIndex) {
return ((value === 0 || value > 1) ? '(' + value + ' Parts)' : '(1 Parts)' );
}
}, {
text: '客戶',
align: 'left',
locked: true,
width: 100,
dataIndex: 'cust_abv'
}, {
text: 'PM',
align: 'left',
locked: true,
width: 85,
dataIndex: 'pm_nm'
}, {
text: 'Sales',
align: 'left',
locked: true,
width: 85,
dataIndex: 'sales_nm'
}, {
text: '銷售數量' ,
align: 'right',
width: 120,
dataIndex: 'sqty',
summaryType: 'sum',
renderer: Ext.util.Format.numberRenderer( '0,000,000,000'),
summaryRenderer: function (value, summaryData, dataIndex) {
return Ext.util.Format.number(value, '0,000,000,000' );
}
}, {
text: '銷售金額(NTD)' ,
align: 'right',
width: 150,
dataIndex: 'samt',
summaryType: 'sum',
renderer: Ext.util.Format.numberRenderer( '0,000,000,000'),
summaryRenderer: function (value, summaryData, dataIndex) {
return Ext.util.Format.number(value, '0,000,000,000' );
}
}, {
text: '預測數量' ,
align: 'right',
width: 120,
dataIndex: 'fqty',
summaryType: 'sum',
renderer: Ext.util.Format.numberRenderer( '0,000,000'),
summaryRenderer: function (value, summaryData, dataIndex) {
return Ext.util.Format.number(value, '0,000,000,000' );
}
}, {
text: '預測單價' ,
align: 'right',
width: 85,
renderer: Ext.util.Format.numberRenderer( '0,000,000,000'),
dataIndex: 'fup'
}, {
text: '預測金額(NTD)' ,
align: 'right',
width: 150,
dataIndex: 'famt',
summaryType: 'sum',
renderer: Ext.util.Format.numberRenderer( '0,000,000,000'),
summaryRenderer: function (value, summaryData, dataIndex) {
return Ext.util.Format.number(value, '0,000,000,000' );
}
}],
height: 203,
width: 712,
renderTo: 'grid-fcst-detail',
viewConfig: {
stripeRows: true
}
});
store.load({
scope: this,
callback: function (records, operation, success) {
// the operation object
// contains all of the details of the load operation
console.log(records);
}
});
});
不同於之前 Gird 的設計方式,在 Data Store 的部份指定了 groupField 來做為 Grouping 的欄位,同時在 Columns 中多了 summaryType 與 summaryRenderer 兩個 Config,作為 Summary 欄位的輸出格式。(圖1)
圖1:Ext Window 輸出圖
註1:在這邊不直接使用 Grid 的方式,是因為在 Window 中直接擺上 Grid,還要處理 Data Store,每一個來源的資料與欄位都不同,這樣會將程式複雜化,透過iFrame 將結果直接透過 DOM 的操作替換掉 Windows 的內容,是最簡便的方式,而 DOM 的操作,並不需要寫什麼程式,Ext js 自己會處理掉。
請教一個老掉牙的問題
資料筆數較多時
是否有分頁處理或其他做法
To 海綿大:
Ext js 的 Grid 提供很多功能,可以參考他的範例
http://dev.sencha.com/deploy/ext-4.1.0-gpl/examples/#sample-2
包括 Paging
http://dev.sencha.com/deploy/ext-4.1.0-gpl/examples/grid/paging.html
Search
http://dev.sencha.com/deploy/ext-4.1.0-gpl/examples/grid/live-search-grid.html
還有 scrolling & filtering
http://dev.sencha.com/deploy/ext-4.1.0-gpl/examples/grid/infinite-scroll-with-filter.html
果然早有準備
謝謝