P/PromptTools
Instruction asset / frontend-instructions

Frontend.instructions.md

從 Google Drive .github/instructions/Frontend.instructions.md 匯入

共用指令內容

使用中

---

applyTo: '**/*.{aspx,ascx,js}'

---

前端 (ASPX, JavaScript) 開發規範

⛔ 0. ASPX Code-Behind 強制規範 (CRITICAL)

每一個 .aspx 頁面都必須有對應的 .aspx.cs code-behind 檔案,且該類別必須繼承 BasePage

沒有 code-behind 的頁面等於繞過 BasePage 的 SSO 驗證與權限機制,形成嚴重的資安漏洞。

0.1 @Page 指令必要屬性

.aspx 檔案的 <%@ Page %> 指令必須包含 CodeFileInherits


<%@ Page Language="C#"

    MasterPageFile="~/System/MasterPage/XXXMaster.master"

    AutoEventWireup="true"

    CodeFile="PageName.aspx.cs"

    Inherits="Pages_Feature_PageName"

    Title="頁面標題" %>

0.2 Code-Behind 類別命名規範

  • 依照檔案路徑,以底線 _ 串接資料夾與檔名:

- Pages/Welfare/Index.aspxPages_Welfare_Index

- Pages/Welfare/Admin/Dashboard.aspxPages_Welfare_Admin_Dashboard

0.3 後台 Admin 頁面範本


using System;



public partial class Pages_Feature_Admin_PageName : BasePage

{

    protected override void OnPreInit(EventArgs e)

    {

        this.CheckAuthorization = true; // ⛔ 後台頁面必須啟用

        base.OnPreInit(e);

    }



    protected void Page_Load(Object sender, EventArgs e)

    {

    }

}

0.4 前台公開頁面範本

前台頁面仍須繼承 BasePage(取得 Session / CurrEmpInfo 基礎設施),但 CheckAuthorization 維持預設 false


using System;



public partial class Pages_Feature_PageName : BasePage

{

    protected void Page_Load(Object sender, EventArgs e)

    {

    }

}

0.5 禁止模式

  • ❌ 建立 .aspx 但不建立對應 .aspx.cs
  • .aspx@Page 指令缺少 CodeFileInherits
  • ❌ Code-behind 類別不繼承 BasePage
  • ❌ 後台 Admin 頁面未設定 CheckAuthorization = true

---

1. UI/UX 佈局

  • 框架: 必須使用 Bootstrap 5.2.3 組件來建構 UI,並確保響應式設計。
  • 表格: 使用 DataTables 來顯示和操作資料表格。
  • DataTables 中文語系載入規範 (CRITICAL): 專案的語系檔 /App_JS/datatables-zh-TW.jsJS 變數宣告var dtZhTW = {...}),不是純 JSON。必須用 <script src="/App_JS/datatables-zh-TW.js"></script> 引入,再以 language: dtZhTW 使用。絕對禁止使用 language: { url: '/App_JS/datatables-zh-TW.js' } 方式載入,該方式會以 AJAX 抓取並解析為 JSON,導致 SyntaxError: Unexpected token ':'ReferenceError: dtZhTW is not defined
  • 圖表: 使用 Chart.js 來呈現數據圖表。
  • 字體與圖示: 使用「芫荽字體」assets/fonts/iansui.css,assets/fonts/Iansui-Regular.ttf和 FontAwesome 圖示庫。
  • 離線化: 專案為完全離線化,不可使用 CDN 引用任何外部函式庫。

2. JavaScript 開發

  • 函式庫: 使用 jQuery 3.7.1 作為主要的 DOM 操作和 Ajax 函式庫。
  • 事件綁定: 使用 $(document).ready()$(function() { ... }); 來確保頁面載入完成後才執行腳本。事件應使用 .on() 方法進行綁定。
  • Ajax 呼叫: 必須使用統一的 Ajax 呼叫模式與 WebService (.asmx) 進行通訊。

3. Ajax 呼叫範例


// 使用統一的 Ajax 呼叫 WebService 模式

$.ajax({

    type: "POST",

    url: "/App_Code/WS/UserWS.asmx/GetAllUsers", // WebService 的路徑

    contentType: "application/json; charset=utf-8",

    dataType: "json",

    data: "{}", // 若無參數,傳遞空 JSON 物件

    success: function (response) {

        // 處理成功的回應。注意:ASP.NET ASMX 的回傳值會被包在 .d 屬性中

        var userList = response.d;

        console.log(userList);

        // ...後續處理邏輯...

    },

    error: function (xhr, status, error) {

        // 使用統一的錯誤處理機制,例如顯示一個 Bootstrap Alert

        console.error("API 呼叫失敗", error);

    },

});



---



## 4. ⚠️ ASMX ScriptService `resp.d` 拆包規範 (CRITICAL)



> **教訓來源**:2026-04 實際踩坑  

> 使用 `FormData` 上傳檔案(`processData: false, contentType: false`)時,開發者容易誤以為 ASMX 不會包 `d`,直接 `JSON.parse(res)` 或 `res.success` 存取,導致取不到值,功能靜默失敗。



### 4.1 規則



**所有**呼叫 `.asmx` WebService 的 success callback,**無論是否使用 FormData 上傳**,回傳值**一律被包在 `resp.d` 內**:



// ✅ 正確:先拆包再使用

success: function (resp) {

var d = (typeof resp.d !== "undefined") ? resp.d : resp;

var obj = (typeof d === "string") ? JSON.parse(d) : d;

if (!obj.success) { showMsg("error", obj.message); return; }

// ...

}

// ❌ 錯誤:FormData 上傳後直接解析,漏掉 .d 拆包

success: function (res) {

var obj = (typeof res === "string") ? JSON.parse(res) : res;

// obj 實際上是 { d: "..." },obj.success === undefined → 靜默失敗

}




### 4.2 ASHX vs ASMX 對照



| 端點類型 | 回傳結構 | success callback 取值方式 |

|---|---|---|

| `.asmx` (ScriptService) | `{ "d": "{...}" }` | 先取 `resp.d`,再 parse |

| `.ashx` (Generic Handler) | `"{...}"` (純 JSON 字串) | 直接 `JSON.parse(resp)` |



---



## 5. ⚠️ TinyMCE editor 實例取得規範 (CRITICAL)



> **教訓來源**:2026-04 實際踩坑  

> `tinymce.get('editorId')` 在 TinyMCE 6+ 某些載入情境下回傳 `undefined` 或拋出 `TypeError: tinymce.get is not a function`,導致儲存時取不到編輯器內容。



### 5.1 規則



在 `setup` 回呼的 `editor.on('init')` 中,將 editor 實例存入模組層級變數,後續**禁止**使用 `tinymce.get()`:



// ✅ 正確:以 _editors 物件儲存實例

var _editors = {};

tinymce.init({

selector: "#introContent, #recruitNotice",

setup: function (editor) {

editor.on('init', function () {

_editors[editor.id] = editor; // 儲存實例

});

}

});

// 讀取內容

var content = _editors['introContent'] ? _editors['introContent'].getContent() : '';

// ❌ 錯誤:直接使用 tinymce.get(),可能拋出 TypeError

var content = tinymce.get('introContent').getContent();




### 5.2 單一編輯器簡化寫法



頁面只有一個 TinyMCE 時,可用單一變數:



var _editor = null;

tinymce.init({

selector: "#txtContent",

setup: function (editor) {

editor.on('init', function () { _editor = editor; });

}

});

// 讀取

var content = _editor ? _editor.getContent() : '';

// 設值

if (_editor) _editor.setContent(data.Content || '');


版本紀錄

1 個不可變版本
v1
從 Google Drive 初次匯入
2026/07/28 02:59:48