2026年5月25日 星期一

V1060301- 專案定更定檢件清單 - 單檔維護(新增/修改/刪除/挎貝) - 下載匯入格式/匯入/匯出

 目的: V1060301- 專案定更定檢件清單 - 單檔維護(新增/修改/刪除/挎貝) - 匯入/匯出

處理說明: 1>單檔維護(新增/修改/刪除/挎貝)
                       var S_DB = Ext.create('S_DB', {
                                              apiName: 'V1060301'
                                          });
                        呼叫 ..\V1060301API\Update() , Insert()
                 2>編輯欄位挑選:
                     {
xtype: "fieldcontainer", fieldLabel: "分類", labelWidth: 160, layout: "hbox", items: [
{ id: "TYPE", name: "TYPE", xtype: "textfield", width: 30, padding: "0 4 0 0", maxLength: 1 },
{ id: "TYPE_", name: "TYPE_", xtype: "textfield", width: 60, fieldCls: "calculate", readOnly: true, padding: "0 4 0 0" },
{
  id: "btn_TYPE", name: "btn_TYPE", xtype: "button", text: "...",
  //handler: function () {
// var win = EditPickx('挑選分類', '../api/V1060301API/get_TYPEPick',
// ['TYPE', 'DESCPT'], ['TYPE', 'TYPE_'],
// J_pickstore_TYPE, J_pickcolumns_TYPE);
// win.show();
//}
}
], labelStyle: "font-size:11pt;"
}, 

    //分類 - on 不可用 handler -屬性名稱, click 才是event 名稱
    Ext.getCmp('btn_TYPE').on("click", function () {
        var win = EditPickx('分類', '../api/V1060301API/get_TYPEPick', ['TYPE', 'DESCPT'], ['TYPE', 'TYPE_'], J_pickstore_TYPE, J_pickcolumns_TYPE);
        win.show();
    });

               3>下載匯入格式/匯入/匯出 
   {  // checkbox 方式 - 分頁勾選
            xtype: 'button', text: '下載匯入格式', id: 'DownloadBtn_1',
            listeners: {
                click: function () {
                    document.location = "../api/VUTLAPI/dnloadSS_File?FNAME=V1060301_專案定更定檢清單_匯入.xlsx";
                }
            }
        },
        {  //以 checkbox 分頁勾選方式 , 由 cbxArr1()  至後端取得資料匯入 
            xtype: 'button', text: '匯入', id: 'XlsInBtn_1',
            listeners: {
                click: function () {                    
                    CALL_V1060301B();
                }
            }
        },




1>*.js

{  // checkbox 方式 - 分頁勾選
            xtype: 'button', text: '下載匯入格式', id: 'DownloadBtn_1',
            listeners: {
                click: function () {
                    //DownloadBtn_1_click();
                    document.location = "../api/VUTLAPI/dnloadSS_File?FNAME=V1060301_專案定更定檢清單_匯入.xlsx";
                }
            }
        },
        {  //以 checkbox 分頁勾選方式 , 由 cbxArr1()  至後端取得資料匯入 
            xtype: 'button', text: '匯入', id: 'XlsInBtn_1',
            listeners: {
                click: function () {                    
                    //XlsInBtn_1_click();                     
                    CALL_V1060301B();
                }
            }
        },
        {  //以 checkbox 分頁勾選方式 , 由 cbxArr1()  至後端取得資料匯出 
            xtype: 'button', text: '匯出', id: 'XlsOutBtn_1',
            listeners: {
                click: function () {                    
                    Ext.Ajax.request({
                        url: '../api/V1060301API/getGridData_M?par_paging=false',
                        method: 'POST',
                        params: { all: 1 },
                        async: false, //將非同步功能關閉
                        failure: function (response, opts) {
                        },
                        success: function (response, opts) {
                            let Tmp_DataAry1 = [];
                            var obj = Ext.decode(response.responseText);
                            obj.T1.forEach(function (item, i) {
                                Tmp_DataAry1.push(item);
                            });
                            CALL_V1060301C(Tmp_DataAry1); //排程資料匯出
                        }
                    });
                }
            }
        },
        {  //以 checkbox 分頁勾選方式 , 由 cbxArr1()  至後端取得資料匯出 
            xtype: 'button', text: '撤銷', id: 'RemoveBtn_1',
            listeners: {
                click: function () {
                    var Tmp_Str;
                    var Tmp_CHKCHG_NM;
                    var cur_recs = Ext.getCmp('grid_Single').getSelectionModel().getSelection();
                    var cur_rec = null;
                    if (cur_recs.length == 0)
                    {
                        Tmp_Str = "請先選擇要撤銷的定更定檢項目!!";
                        myalert(Tmp_Str);
                    }
                    else {
                        console.log("cur_recs:", cur_recs);
                        cur_rec = cur_recs[0];
                        console.log("cur_rec:", cur_rec);
                        Tmp_CHKCHG_NM = nulltoStr(cur_rec.data['CHKCHG_NM']).toString();
                        Tmp_Str = "確定將本定更定檢項目(" + Tmp_CHKCHG_NM + ")\r\n"
                            + "撤銷嗎?\r\n";
                        var id = confirm(Tmp_Str);
                        if (id) {
                            CALL_V1060301D();
                        };
                    }
                    
                }
            }
        },

2026年5月24日 星期日

V1060302 – 專案定更檢清單 - 分類 – Runtime 設定挑選欄位 - click - 不可用handler

 目的: V1060302 – 專案定更檢清單 - 分類 – Runtime 設定挑選欄位

處理說明:  1> click 才是 event 名稱, 不可用 handler

                        handler 是屬性名稱,不是 event name , 所以不可用在 on('handler', function(){


1>*.js
//設定[編輯]畫面 - 欄位挑選(DoubleClick)設定    
    Ext.getCmp('btn_TYPE').on("click", function () {
        var win = EditPickx('分類', '../api/V1060301API/get_TYPEPick', 
                   ['TYPE', 'DESCPT'], ['TYPE', 'TYPE_'], J_pickstore_TYPE, J_pickcolumns_TYPE);
        win.show();
    });

--> 不可用 on("handler",function(){


2026年5月7日 星期四

按[F12]鈕 - Network Debug 的範例 - 當前端發出一個 Url Request 時(../API/V80E01AAPI/get_sub_TreeData1) , Debug 資料是否正確

目的: 按[F12]鈕  - Network Debug 的範例
           當前端發出一個 Url Request 時(../API/V80E01AAPI/get_sub_TreeData1) , 
           Debug 資料(url/Request method/傳入參數/傳回值/..)是否正確
           -Ex: V80E01A - 展開節點時, 按 F12 ,可以看到 URL , FormData 及傳回資料

處理說明: 1>當呼叫後端Request(url) 時,按 [F12]鈕, 
                      可以看到[Network]頁 列出後端的 URL
                  2>於 [Network]頁, 點[Header]Sheet, 看到 Request method: Post/Get
                  3>點[Payload]Sheet, 看到 傳入參數: Form Data
                  4>點[PreView]Sheet,看到傳回的資料(DataSet/Table)
                  5>點[Respons]Sheet,看到傳回的資料(json結構)



1>[Network]頁: URL
2>[Header]Sheet: Request method

3>[Payload]Sheet: 傳入參數(Form Date)


4>[Preview]Sheet : 傳回結果(dataset/datatable)


5>[Response]Sheet: 顯示 json結構



好的,我來示範一個「Network Debug 範例」,讓你能在瀏覽器 F12 檢查 TreeStore 的請求是否真的送出到後端:


🔧 步驟

  1. 打開瀏覽器開發者工具

    • 在 Chrome/Edge 按 F12Ctrl+Shift+I
    • 切換到 Network 面板。
  2. 展開節點觸發請求

    • 在你的 Ext.tree.Panel 裡點擊某個節點。
    • 如果 TreeStore 正常設定,這時候應該會送出一個 HTTP 請求。
  3. 檢查請求細節

    • 在 Network 面板找到對應的請求 (通常 URL 是 ../api/V80E01AAPI/get_sub_TreeData1)。
    • 點擊該請求,檢查:
      • Request Method:是否為 POST(如果後端是 [HttpPost])。
      • Request Payload / Form Data:是否有帶上 cur_DEPID
      • Response:後端是否回傳 JSON,格式是否正確。
  4. 常見錯誤排查

    • 如果請求沒有出現 → 代表 TreeStore 沒有觸發 Proxy,檢查 beforeload 是否正確設定。
    • 如果請求出現但狀態碼是 405 Method Not Allowed → 前端用 GET,後端只允許 POST。
    • 如果狀態碼是 404 Not Found → URL 路徑不匹配。
    • 如果狀態碼是 200 OK 但沒有資料 → 後端查詢邏輯或回傳格式不符。

範例截圖檢查重點

  • Request URL: http://localhost:xxxx/api/V80E01AAPI/get_sub_TreeData1
  • Request Method: POST
  • Form Data:
    cur_DEPID: AIDC
    
  • Response JSON:
    [
      { "id":"A001", "text":"A001:部門", "leaf":false },
      { "id":"E001", "text":"E001:員工", "leaf":true }
    ]
    

👉 這樣你就能快速判斷:到底是 前端沒送出,還是 後端沒接到,或是 資料格式不符

要不要我幫你寫一個「最小可測試範例」的 TreeStore + Controller,讓你可以直接跑起來測試 Network 面板?


2026年5月6日 星期三

V80E01A - 以 Ext.Tree.Panel 的應用 - 以 資料庫欄位建位 TreeView - store.proxy

 目的: V80E01A -以 Ext.Tree.Panel & Ext.data.TreeStore 的應用 
             -以資料庫欄位建位 TreeView - store.proxy

處理說明: 1>資料庫結構 - HR_DEP & HR_EMPLYM & HR_DEPHIRCH
                  2>設  Ext.data.TreeStore 元件 - proxy / type / reader / actionMethods 的欄位值
                       proxy: {
            type: 'ajax',
            url: '../api/V80E01AAPI/get_sub_TreeData1',
            actionMethods: { read: 'POST' },   // 改成 POST
            reader: { type: 'json' },
        }
       3> 將 Ext.tree.Panel.store  設定成 myTreeStore         
            var cmp_sub_TreePanel1 =  
                   get_cmp_treepanel1("sub_TreePanel1","AIDC",10, myTreeStore);                           
       4>Ext.tree.Panel - DoubleClick 展開節點時, 會呼叫URL     
           會自動呼叫 URL (store.proxy.url) 讀取下層節點


SQL:
SELECT  B.DPRTID as P_DEPID,A.DEPID as ID,A.DEPNM as NM,0 as leaf ,2 as itm      
FROM     HR_DEP A, HR_DEPHIRCH B
WHERE  A.DEPID=B.DEPID
AND       B.DPRTID='800'
union
SELECT  C.DEPID as P_DEPID,C.EMPLYID as ID,C.EMPLYNM as NM,1 as leaf, 1 as itm
FROM     HR_EMPLYM C
WHERE  C.DEPID='800'
ORDER   BY itm,ID;

            2>store.proxy 的應用
function CALL_V80E01A() {
    console.log(" 1  顯示 AIDC 組織圖 ");
    //panel11 - 拆檢案專案日期選項
    var myTreeStore =
    {
        xtype: 'treeStore',
        proxy: {
            type: 'ajax',
            url: '../api/V80E01AAPI/get_sub_TreeData1',
            actionMethods: { read: 'POST' },   // 改成 POST
            reader: { type: 'json' },
        },
        root: {
            id:'AIDC',
            text: 'AIDC',
            expanded: true,
            children: [
                { text: '節點 A1', leaf: true },
                {
                    text: '節點 A2', expanded: true, children: [
                        { text: '節點 A2-1', leaf: true }
                    ]
                }
            ]
        }
    };
    
 //透過連接資料庫,取得 TreeView 節點資訊
 var cmp_sub_TreePanel1 = get_cmp_treepanel1("sub_TreePanel1","AIDC",10, myTreeStore);

sub_TreePanel1.on('beforeload', function (store, operation) {        
        // operation.node 是目前要展開的節點
        var np = {};
        np["cur_DEPID"] = operation.node.data.id;
        if (operation.node.hasChildNodes())
            return;
        sub_TreePanel1.store.getProxy().extraParams = np;
        //store.getProxy().setExtraParams(np);
    });

//
 //[顯示公司組織圖]鈕- 透過連接資料庫,取得 TreeView 節點資訊
    function V80E01A_StoreProxy() {
        var np = {};
        np["cur_DEPID"] = "AIDC";
        sub_TreePanel1.store.getProxy().url = '../api/V80E01AAPI/get_sub_TreeData1',
        sub_TreePanel1.store.getProxy().extraParams = np; //分頁OK,篩選條件OK
        sub_TreePanel1.store.load();
    };


JSON介紹 - 什麼是 JSON

 JSON(JavaScript Object Notation)是一種輕量級的資料交換格式,常用來在不同系統之間傳遞資料。它的設計理念是「簡單、易讀、易解析」,既能讓人類直觀理解,也能被電腦快速處理。

1>✨ JSON 的特點

  • 純文字格式:資料以文字形式儲存,通常是 .json 檔案。

  • 結構清晰:由「鍵值對」組成,類似字典或物件。

  • 跨平台通用:不依賴特定程式語言,幾乎所有語言都能解析。

  • 常用於網路傳輸:例如 API 回傳資料時,最常見的格式就是 JSON

2> JSON範例
{
  "name": "Alice",
  "age": 25,
  "isStudent": true,
  "skills": ["Python", "JavaScript", "SQL"],
"node": {856:"系統設計課",611292: "蔡聰進",610929:"楊清榮",} , }
  • 字串:用雙引號 " " 包起來

  • 數字:直接寫,不需要引號

  • 布林值truefalse

  • 陣列:用 [] 包起來

  • 物件:用 {} 包起來裡面是鍵值對

3> JSON 的用途
  • API 資料交換:伺服器和前端之間傳遞資料。

  • 設定檔:許多應用程式用 JSON 來儲存設定。

  • 資料儲存:簡單的資料庫或檔案系統也會用 JSON。

V80E01A - 以 Ext.Tree.Panel 的簡單應用 - 新增節點 - 新增子節點

 目的: V80E01A  - 以 Ext.Tree.Panel & Ext.data.TreeStore 的簡單應用

處理說明: 
     1> 透過 Ext.Tree.Panel 產生  Tree
           var cmp_sub_TreePanel1 = get_cmp_treepanel1("sub_TreePanel1","AIDC",10, myTreeStore);
     2> 直接建 TreeNode - 透過 root
function get_cmp_treepanel1(par_id,par_title, par_flex, par_store) {
    if (checkisnull(par_flex)) {
        par_flex = 10;
    }
    var rtn_cmp =
    {
        xtype: 'treepanel', border: 0,
        id: par_id,
        title: par_title,
        flex: par_flex,
        store: par_store,  //若par_store有值,則會以 par_store 為主,並覆蓋如下 root 的設定
        rootVisible: true,                   
        root: {
            text: par_title,
            expanded: true,
            children: [
                {
                    text: '子節點 1',
                    leaf: true
                },
                {
                    text: '子節點 2',
                    expanded: true,
                    children: [
                        { text: '子節點 2-1', leaf: true },
                        { text: '子節點 2-2', leaf: true }
                    ]
                }
            ]
        }, // end of s_AMM單號

    };
    return rtn_cmp;
};
     3> 透過  Ext.data.TreeStore 建 TreeNode   - 透過 .store
  var myTreeStore =
    {
        xtype: 'treeStore',
        root: {
            text: '根節點A',
            expanded: true,
            children: [
                { text: '節點 A1', leaf: true },
                {
                    text: '節點 A2', expanded: true, children: [
                        { text: '節點 A2-1', leaf: true }
                    ]
                }
            ]
        }
    };
    var cmp_sub_TreePanel1 = get_cmp_treepanel1("sub_TreePanel1","AIDC",10, myTreeStore);

     4> 新增同層節點 先取得父節點 , 再由父節點.新增子節
                     function V80E01A_Add() {
                         var sub_TreePanel1 = Ext.getCmp("sub_TreePanel1");
                         var selectedNode = sub_TreePanel1.getSelectionModel().getSelection()[0];
                         if (selectedNode) {
                            var parentNode = selectedNode.parentNode;
                                  parentNode.insertChild(parentNode.indexOf(selectedNode) + 1, {
                                         text: '新同層節點',
                                         leaf: true
                                 });
                           // 如果要立即展開顯示
                          parentNode.expand();
                      }
                     };
     5> 新增子層節點 :
function V80E01A_AddSub() {
var sub_TreePanel1 = Ext.getCmp("sub_TreePanel1");
var selectedNode = sub_TreePanel1.getSelectionModel().getSelection()[0];
if (selectedNode) {
//若目前selectedNode為leaf , 則需先設為 false , 否則 appendChild 會無效
if (selectedNode.get('leaf')) {
   selectedNode.set('leaf', false);
};
selectedNode.appendChild({
text: '新子節點',
leaf: true
});
    // 如果要立即展開顯示            
    selectedNode.expand();
   }
};




1>*.js
function CALL_V80E01A() {
    console.log(" 1  顯示 AIDC 組織圖 ");
    //panel11 - 拆檢案專案日期選項
    var myTreeStore =
    {
        xtype: 'treeStore',
        root: {
            text: '根節點A',
            expanded: true,
            children: [
                { text: '節點 A1', leaf: true },
                {
                    text: '節點 A2', expanded: true, children: [
                        { text: '節點 A2-1', leaf: true }
                    ]
                }
            ]
        }
    };
    

    var cmp_sub_TreePanel1 = get_cmp_treepanel1("sub_TreePanel1","AIDC",10, myTreeStore);
       
    var sub_V80E01A_Flds = [
        {
            type: 'panel', bodyStyle: "background-color:transparent;", border: 5, padding: "1",
            layout: 'border',
            items: [
                {
                    xtype: 'panel', id: 'sub_panelAA1', region: 'center', 
                    height: 100,
                    //layout: { type: 'vbox', align: 'stretch' },
                    layout: { type: 'fit',},
                    items: [
                        cmp_sub_TreePanel1
                    ],
                },               
            ]
        }
    ];

    //2>顯示子畫面 - [列印子畫面]
    var Btns_V80E01A = [
        {
            xtype: 'button', text: '新增同層節點', id: 'AddBtn_V80E01A',
            listeners: {
                click: function (me, e, eOpts) {                    
                    V80E01A_Add();                    
                }
            }
        },
        {
            xtype: 'button', text: '新增子層節點', id: 'AddSubBtn_V80E01A',
            listeners: {
                click: function (me, e, eOpts) {
                    V80E01A_AddSub();
                }
            }
        },
        {
            xtype: 'button', text: '顯示 TreePanel.Store', id: 'ShowStoreBtn_V80E01A',
            listeners: {
                click: function (me, e, eOpts) {
                    V80E01A_ShowStore();
                }
            }
        },
        {
            xtype: 'button', text: '取消', id: 'CancelBtn_V80E01A',
            listeners: {
                click: function () {                    
                    //3>取消時,不重新顯示資料                    
                    this.up("window").close();
                    this.up("window").destroy();
                }
            }
        },
    ];

    //子畫面: mySubFormA
    //var win = getMyWindow("撿料完成", J_formFields_V80E01A, Btns_V80E01A, "F");
    var winAA1 = getMyWindow("顯示 AIDC 公司組織圖 ", sub_V80E01A_Flds, Btns_V80E01A, "AA");
    //win.onshow = Sub1_onShow(np1);
    winAA1.width = 500;
    winAA1.height =500;    
    winAA1.show();

    //將目前所選節點加入子節點
    function V80E01A_AddSub() {
        var sub_TreePanel1 = Ext.getCmp("sub_TreePanel1");
        var selectedNode = sub_TreePanel1.getSelectionModel().getSelection()[0];        
        if (selectedNode) {
            if (selectedNode.get('leaf')) {
                selectedNode.set('leaf', false);
            };
            selectedNode.appendChild({
                text: '新子節點',
                leaf: true
            });

            // 如果要立即展開顯示            
            selectedNode.expand();
        }
    };
    //將目前所選節點加入同層節點
    function V80E01A_Add() {
        var sub_TreePanel1 = Ext.getCmp("sub_TreePanel1");
        var selectedNode = sub_TreePanel1.getSelectionModel().getSelection()[0];

        if (selectedNode) {
            var parentNode = selectedNode.parentNode;
            parentNode.insertChild(parentNode.indexOf(selectedNode) + 1, {
                text: '新同層節點',
                leaf: true
            });
            // 如果要立即展開顯示
            parentNode.expand();
        }
    };

    function V80E01A_ShowStore() {
        var sub_TreePanel1 = Ext.getCmp("sub_TreePanel1");
        console.log("sub_TreePanel1.store", sub_TreePanel1.store);
    };

};  // end of  function CALL_V80E01A() {



2026年5月5日 星期二

V80E01A - 以 Ext.Tree.Panel 建立公司組織圖 - TreeView

 目的: V80E01A 以 Ext.Tree.Panel & Ext.data.TreeStore 建立公司組織圖

處理說明: 1>TreeView : 利用 [Ext.Tree.Panel] 元件
                  2>若 TreeView 要由後端資料庫取得節點資料,則透過 .store.proxy  取得後端資料
                       部門下層節點資料 SQL :  存取該部門下層 DEP 及該部門員工                  
                       (HR_DEPHIRCH/HR_DEP/HR_EMPLYM) , SQL如下
                  3> DoubleClick節點展開: 
                       Ext.Tree.Panel元件已設計好, DoubleClick 節點時,
                       會呼叫 proxy , 觸發 beforeload event 
                       只要重傳傳入參數(=部門ID) , 透過 proxy.url 重新取得下層節點SQL即可
                       該元件會依 proxy 傳回資料,自動建置該節點下層節點                        


2>SQL如下:

SQL:
SELECT  'DEP' as TYPE,B.DPRTID as P_DEPID,A.DEPID as ID,A.DEPNM as NM        
FROM    HR_DEP A, HR_DEPHIRCH B      
WHERE   A.DEPID = B.DEPID      
AND     B.DPRTID = '800'    
union       
SELECT  'EMP' as TYPE,C.DEPID as P_DEPID,C.EMPLYID as ID,C.EMPLYNM as NM
FROM    HR_EMPLYM C     
WHERE  C.DEPID = '800'  
ORDER BY TYPE DESC,ID; 


1>*.js
function CALL_V80E01A() {
    console.log(" 1  顯示 AIDC 組織圖 ");
    //panel11 - 拆檢案專案日期選項
    var myTreeStore =
    {
        xtype: 'treeStore',
        proxy: {
            type: 'ajax',
            url: '../api/V80E01AAPI/get_sub_TreeData1',
            actionMethods: { read: 'POST' },   // 改成 POST
            reader: { type: 'json' },
        },
        root: {
            id:'AIDC',
            text: 'AIDC',
            expanded: true,
            children: [
                { text: '節點 A1', leaf: true },
                {
                    text: '節點 A2', expanded: true, children: [
                        { text: '節點 A2-1', leaf: true }
                    ]
                }
            ]
        }
    };
    
     var cmp_sub_TreePanel1 = get_cmp_treepanel1("sub_TreePanel1","AIDC",10, myTreeStore);
 //透過連接資料庫,取得 TreeView 節點資訊

var sub_TreePanel1 = Ext.getCmp("sub_TreePanel1");
function V80E01A_StoreProxy() {
        var np = {};
        np["cur_DEPID"] = "AIDC";
        sub_TreePanel1.store.getProxy().url = '../api/V80E01AAPI/get_sub_TreeData1',
        sub_TreePanel1.store.getProxy().extraParams = np; //分頁OK,篩選條件OK
        sub_TreePanel1.store.load();
    };


    sub_TreePanel1.on('beforeload', function (store, operation) {
        
        // operation.node 是目前要展開的節點
        var np = {};
        np["cur_DEPID"] = operation.node.data.id;
        if (operation.node.hasChildNodes())
            return;
        sub_TreePanel1.store.getProxy().extraParams = np;  //設定 extraParams ,重新會呼叫 URL
    });