iT邦幫忙

DAY 13
8

進程。Processing系列 第 13

[進程。Processing] 13.視窗(Window)

為了讓每一個數字都能夠顯示 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 自己會處理掉。

Prev Next

本篇全系列文章


上一篇
[進程。Processing] 12.塑型(Modeling)
下一篇
[進程。Processing] 14.圖表(Chart)
系列文
進程。Processing31

2 則留言

0
海綿寶寶
iT邦大神 1 級 ‧ 2012-10-13 11:05:12

請教一個老掉牙的問題
臉紅

資料筆數較多時
是否有分頁處理或其他做法
謝謝

jamesjan iT邦高手 1 級 ‧ 2012-10-14 09:22:47 檢舉

果然早有準備
臉紅
謝謝

我要留言

立即登入留言