※ 安裝ECPAY SDK(軟體開發工具包):
載點:https://github.com/ECPay/ECPayAIO_Node.js
方法:1.把code dowonload下來。
在專案中下載ECPAY SDK代碼的原因如下:
- 參考學習:開發時,可以直接參考 SDK 內的內容。
- 錯誤排查:SDK 內的資料夾和 JavaScript 內容,可以在開發過程中通過 console.log 方法來檢查,幫助我們發現參數中的錯誤。
操作流程如下:
- 下載ECPayAIO_Node.js-master。
- 將ECPayAIO_Node.js-master解壓縮。
- ECPayAIO_Node.js-master資料夾移動到專案中的server資料夾裡面。
- 在src資料夾中新增adapters資料夾,adapters功能是將 API 包裝成一個或多個函數,方便在應用程式中使用。
- adapters資料夾中新增ecpay資料夾,新增index.ts撰寫關於ecpay內容。
- 接著把ECPAY_Payment_node_js放進ecpay資料夾中,其餘關於ECPayAIO_Node.js-master的檔案都刪除。
2.使用npm install。

※ 設計ECPAY 接口:
●定義IECPayAdapter接口:ecpay → index.js
export interface IECPayAdapter {
createCVS()
}
程式碼解說:
export
關鍵字讓IECPayAdapter
接口可以在其他模組中被import
,進而確保不同的類別可以依據這個接口的定義來實現createCVS
方法。IECPayAdapter
是用來適配 ECPay 的支付功能。
●createCVS()要搭配的參數查找步驟:
- 打開
aio_check_out_cvs.js
文件:- 打開專案目錄中的 aio_check_out_cvs.js 文件。
- 查找
createCVS()
函數:- 在文件中查找 createCVS() 函數定義和使用。通常可以使用編輯器的搜尋功能(如 Ctrl + F 或 Cmd + F)快速定位。
- 檢查
createCVS()
函數的參數:- 檢查這個函數的參數和相關的邏輯,了解它需要哪些資料來創建 CSV。


程式碼解說:
●CVS_INFO
接口:
定義了有關 CVS(便利商店)相關資訊的結構,包括商店過期日期、描述和支付訊息網址等。
interface CVS_INFO {
StoreExpireDate: string; // 商店過期日期
Desc_1: string; // 描述1
Desc_2: string; // 描述2
Desc_3: string; // 描述3
Desc_4: string; // 描述4
PaymentInfoURL: string; // 支付訊息的網址
}
●CVS_PARAMS 接口
:
定義了與 CVS 交易相關的參數,包括商戶交易號、交易日期、總金額、交易描述、商品名稱和回傳網址等。
interface CVS_PARAMS {
MerchantTradeNo: string; // 商戶交易號
MerchantTradeDate: string; // 商戶交易日期
TotalAmount: string; // 總金額
TradeDesc: string; // 交易描述
ItemName: string; // 商品名稱
ReturnURL: string; // 回傳網址
}
●CreateBillParams
接口:
interface CreateBillParams {
cvsInfo?: CVS_INFO; // CVS 信息
cvsPrams: CVS_PARAMS; // CVS 參數
inv_param?: {}; // 可選的發票參數
client_redirect_url?: string; // 可選的客戶重定向網址
}
- 定義了用於創建帳單所需的參數結構,包含
CVS_INFO
和CVS_PARAMS
兩個主要部分,以及可選的發票參數和客戶重定向網址。 - 在
cvsInfo
屬性後加上問號,表示這個屬性是可選的(optional)。
●IECPayAdapter 接口
:
定義了一個用於適配 ECPay 的接口,包括一個名為 createCVS
的方法。這個方法接受 CreateBullParams
類型的參數,並返回一個字串。
export interface IECPayAdapter {
createCVS(createBillParams: CreateBillParams): string; // 用於創建 CVS 的方法
}
●讓ECPayAdapter使用 ECPay 提供的 API 來執行支付相關的操作。
export class ECPayAdapter implements IECPayAdapter {
private ecpayInstance;
constructor(options: IECPayAdapterOptions = defaultOptions) {
this.ecpayInstance = new ECPAY(options);
}
}
程式碼解說:
1.導入 ECPay 模組:
import ECPAY from './ECPAY_Payment_node_js';
將 ECPAY_Payment_node_js
文件中的內容作為模組導入,並命名為 ECPAY
。這個模組應該包含了 ECPay 的支付功能實現,例如創建 CVS、查詢支付狀態等。
※ 參考資料來源:ECPAY_Payment_node_js/example/aio_check_out_cvs.js

2.export class ECPayAdapter implements IECPayAdapter
:
ECPayAdapter
類別實現了IECPayAdapter
接口,這表示它必須包含IECPayAdapter
接口中定義的createCVS 方法。
3.private ecpayInstance;
:
這行程式碼宣告了一個私有變數 ecpayInstance
,用來儲存 ECPay 的實例。private
關鍵字表示這個變數只能在 ECPayAdapter
類別內部使用,外部無法直接存取或修改。
4.
constructor(options: IECPayAdapterOptions = defaultOptions)
:
- 構造函數:這是 ECPayAdapter 類別的構造函數,用於在創建類別實例時進行初始化。
- options 參數:這個參數的類型是 IECPayAdapterOptions,用來接收初始化配置選項。
- 默認值 defaultOptions:options 參數設定為 defaultOptions 作為默認值,表示如果沒有傳遞具體的 options,則使用 defaultOptions。
5.this.ecpayInstance = new ECPAY(options);
:- 這行程式碼在構造函數內執行,創建一個新的 ECPAY 實例並賦值給
this.ecpayInstance
。這樣,ECPayAdapter
類別就可以使用this.ecpayInstance
來調用 ECPay 的支付功能。 options
參數通常是一個配置物件,用來設置 ECPay 的一些初始化選項,例如商戶 ID、金鑰、API URL 等。
- 這行程式碼在構造函數內執行,創建一個新的 ECPAY 實例並賦值給
●定義optionsc後再依據 IECPayAdapterOptions 創建的一個具體變數或物件。
※ 參考資料來源:ECPAY_Payment_node_js/conf/config-example.js

interface IECPayAdapterOptions {
OperationMode: "Test" | "Production", //Test or Production
MercProfile: {
MerchantID: string;
HashKey: string;
HashIV: string;
},
"IgnorePayment": [];
"IsProjectContractor": boolean;
}
程式碼解說:
OperationMode
:- 類型是 "Test" | "Production",表示運行模式可以是 "Test"(測試模式)或 "Production"(生產模式)。這個屬性用來設定 ECPay 是在測試環境還是生產環境中運行。
MercProfile
:- 這是一個物件,包含三個字串屬性,用於設定商戶的基本資料。
- MerchantID:商戶 ID,用於標識商戶身份。HashKey:哈希金鑰,用於加密資料。HashIV:哈希初始化向量,用於加密資料。
IgnorePayment
:- 這是一個空的陣列,表示要忽略的支付方式。這個屬性可以用來設定不需要支持的支付方式。
IsProjectContractor
:- 類型是 boolean,表示是否是項目承包商。這個屬性用來標識商戶是否以項目承包商的身份運行。
● 設定defaultOptions
:
//定義一組預設的配置選項
const defaultOptions: IECPayAdapterOptions
= {}
程式碼解說:
- 設置預設值:當用戶在初始化某個功能或類別時沒有提供具體的選項,
defaultOptions
中定義的預設值將會被使用,確保系統有合理的初始設置。 - 類型:
IECPayAdapterOptions
:意味著它必須符合這個接口中定義的結構和屬性。
● 設定defaultOptions內容
:定義一組預設的配置選項
const defaultOptions: IECPayAdapterOptions = {
OperationMode: "Test", //Test or Production
MercProfile: {
MerchantID: "2000132",
HashKey: "5294y06JbISpM5x9",
HashIV: "v77hoKGq4kWxNNIS"
},
"IgnorePayment": [
// "Credit",
// "WebATM",
// "ATM",
// "CVS",
// "BARCODE",
// "AndroidPay"
],
"IsProjectContractor": false
}
程式碼解說:
※ 複製資料來源:ECPAY_Payment_node_js/conf/config-example.js

● 查看HashKey和
HashIV:
進入綠界科技的開發者測試後台:

登入後進入系統開發管理:

確認程式碼是否一樣:

● 設定create cvs
:
createCVS = (createParams: CreateBillParams) => {
const { cvsInfo, cvsPrams, inv_param, client_redirect_url } = createParams;
}
程式碼解說:
createCVS = (createParams: CreateBillParams) => { ... }
:
- 這是一個箭頭函數,用於處理 createCVS 方法的邏輯。
- createParams 是函數的參數,類型為 CreateBillParams。
const { cvsInfo, cvsPrams, inv_param, client_redirect_url } = createParams;
:
- 這行程式碼使用了解構賦值語法,從
createParams
參數中提取出cvsInfo
、cvsPrams
、inv_param
和client_redirect_url
屬性。 - 這樣做的目的是為了方便在函數內部直接使用這些變數,而不必每次都通過
createParams
物件來訪問。
● 定義了一個cvsInfo 的物件:
cvsInfo = {
StoreExpireDate: '',
Desc_1: '',
Desc_2: '',
Desc_3: '',
Desc_4: '',
PaymentInfoURL: ''
},
程式碼解說:
※ 複製資料來源:ECPAY_Payment_node_js/conf/config-example.js

StoreExpireDate
:- 描述:這個屬性通常用於指定便利商店的訂單過期日期。
- 初始值:空字串。
Desc_1
,Desc_2
,Desc_3
,Desc_4
:- 描述:這些屬性用於存儲額外的描述資訊,通常用於提供關於訂單或支付的詳細描述。
- 初始值:空字串。
PaymentInfoURL
:- 描述:這個屬性用於指定一個 URL,該 URL 包含支付資訊,可能會將用戶重定向到相關的支付信息頁面。
- 初始值:空字串
● 從 createParams 參數中提取 cvsPrams 屬性,並給 inv_param 和 client_redirect_url 設置默認值:
const {
cvsPrams,
inv_param = {},
client_redirect_url = ''
} = createParams;
程式碼解說:
cvsPrams
:- 直接從 createParams 中解構出來。
- 這個變數用來存儲與 CVS(便利商店)相關的參數信息。
inv_param = {}
:- 使用解構賦值的語法,並設置默認值為空物件 {}。
- 這個變數用來存儲發票相關的參數。如果 createParams 中沒有 inv_param 屬性,則使用默認的空物件。
client_redirect_url = ''
:- 使用解構賦值的語法,並設置默認值為空字串 ''。
- 這個變數用來存儲客戶重定向的 URL。如果 createParams 中沒有 client_redirect_url 屬性,則使用默認的空字串。
● 生成的 HTML 表單輸出到控制台:
※ 複製資料來源:ECPAY_Payment_node_js/conf/config-example.js:

※ 將程式碼修改成以下:
//調用函數並使用返回的結果:
const html = this.ecpayInstance.payment_client.aio_check_out_cvs
(cvsInfo, cvsPrams, inv_param, client_redirect_url)
return html;
程式碼解說:
const html = this.ecpayInstance.payment_client.aio_check_out_cvs(cvsInfo, cvsPrams, inv_param, client_redirect_url);
:- 這行程式碼使用 ECPay 實例的 payment_client 來呼叫 aio_check_out_cvs 方法,生成 CVS 支付的 HTML 表單,這個表單可以嵌入網頁,讓用戶進行支付。
- 參數:
- cvsInfo:包含 CVS 支付的相關資訊,例如訂單過期日期、描述等。cvsPrams:包含 CVS 支付的具體參數,例如商品資訊、金額等。inv_param:包含發票相關的參數(如果有)。client_redirect_url:支付完成後用戶將被重定向到的 URL。
return html
:- 將 html 作為函數的返回值,使得調用者可以接收並使用這個結果。
● 建立dispatcher資料夾,管理多種支付:dispatcher → index.js
1.定義了一個異步函數 paymentDispatcher,用來處理支付相關的邏輯:
import { PaymentProvider, PaymentWay } from "@/model/order"
//建立發派function
export const paymentDispatcher = async ({
paymentProvider,
paymentWay,
payload
}: {
paymentProvider: PaymentProvider;
paymentWay: PaymentWay;
payload: PaymentPayload
}) => {
}
程式碼解說:
1.函數定義:
export const paymentDispatcher =
async ({ paymentProvider, paymentWay, payload }
: { paymentProvider: PaymentProvider; paymentWay: PaymentWay; payload: any })
=> { };
export
:這個關鍵字使得paymentDispatcher
函數可以在其他模組中被導入和使用。const
:使用const
關鍵字宣告一個常數,表示paymentDispatcher
的值不能被重新賦值。async
:這個關鍵字表明paymentDispatcher
是一個非同步函數,該函數會返回一個Promise
,並且可以使用await
關鍵字來處理非同步操作。
2.參數解構賦值:
({ paymentProvider, paymentWay, payload })
- 從傳入的參數對象中解構出
paymentProvider
、paymentWay
和payload
屬性。 paymentProvider
:支付提供商的類型,可以是如 ECPay、PayPal 等不同的金流服務。paymentWay
:支付方式,例如信用卡、ATM、便利商店等。payload
:包含支付過程中所需的其他參數和資訊。
3.參數類型定義:
: { paymentProvider: PaymentProvider; paymentWay: PaymentWay; payload: PaymentPayload }
為解構賦值參數提供類型定義,確保傳入的參數符合預期的結構和類型。
2.根據指定的支付提供商 (PaymentProvider) 和支付方式 (PaymentWay),生成一個 CVS 支付的 HTML 表單:
const ecpay = new ECPayAdapter();
if (paymentProvider === PaymentProvider.ECPAY) {
if (paymentWay === PaymentWay.CVS) {
const html = ecpay.createCVS({
cvsPrams: {
MerchantTradeNo: payload.billId,
MerchantTradeDate: dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss"),
TotalAmount: String(payload.totalPrice),
TradeDesc: payload.desc,
ItemName: payload.details.map(content =>
`${content.name} x ${content.price}`).join("#"),
ReturnURL: payload.returnUrl,
},
});
return html;
} else throw new Error('No suitable payment way.');
程式碼解說:
1.建立 ECPayAdapter 實例:
const ecpay = new ECPayAdapter();
這行程式碼創建了一個新的 ECPayAdapter 實例,名為 ecpay
。
2.判斷支付提供商:
if (paymentProvider === PaymentProvider.ECPAY) {}
判斷 paymentProvider
是否為 PaymentProvider.ECPAY
,即檢查支付提供商是否為 ECPay。
3.判斷支付方式:
if (paymentWay === PaymentWay.CVS) {}
判斷 paymentWay
是否為 PaymentWay.CVS
,即檢查支付方式是否為 CVS。
4.生成 CVS 支付表單:
const html = ecpay.createCVS({
cvsPrams: {
MerchantTradeNo: payload.billId, // 商戶交易編號
MerchantTradeDate: dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss"), // 交易日期
TotalAmount: String(payload.totalPrice), // 總金額(這裡似乎應該是金額,而不是交易編號,可能需要確認)
TradeDesc: payload.desc, // 交易描述
ItemName: payload.details.map(content =>
`${content.name} x ${content.price}`).join("#"), // 商品名稱及價格
ReturnURL: payload.returnUrl // 返回 URL
}
});
return html;
MerchantTradeNo
:從payload
中獲取的商戶交易編號。MerchantTradeDate
:使用dayjs
庫格式化當前日期和時間為"YYYY-MM-DD HH:mm:ss"
格式。- 安裝 dayjs:
npm install dayjs
- 匯入 dayjs:
import dayjs from 'dayjs';
TotalAmount
:總金額,這裡使用payload.totalPrice
,檢查這是否為正確的金額值。TradeDesc
:交易描述,從payload.desc
獲取。ItemName
:商品名稱及價格,使用map
函數將payload.details
中每個商品的名稱和價格組合成name x price
的格式,並用#
分隔。ReturnURL
:支付完成後返回的 URL,從payload.returnUrl
獲取。- 當支付提供商為 ECPay 且支付方式為 CVS 時,使用 ECPay 的
createCVS
方法生成 CVS 支付的 HTML 表單。 - 使用 payload 中的數據來填充 CVS 支付參數(cvsPrams)。
5.處理不合適的支付方式:
} else throw new Error('No suitable payment way.');
- 如果支付方式不合適,則拋出一個錯誤,提示 "No suitable payment way."。
3.定義PaymentPayload
的接口:用來定義支付資料的結構,確保物件的屬性和類型符合預期。
export interface PaymentPayload {
billId: string;
totalPrice: number;
desc: string;
details: OrderDetail[];
returnURL: string;
}
程式碼解說:
export interface PaymentPayload
:- export:這個關鍵字表示這個接口可以被其他模組導入和使用。
- interface:定義了一個接口,名為 PaymentPayload。
billId: string
:- 定義了一個名為 billId 的屬性,類型是字串。
- 描述:這個屬性通常用於表示交易或訂單的唯一標識符。
totalPrice: number
:- 定義了一個名為 totalPrice 的屬性,類型是數字。
- 描述:這個屬性用來表示交易的總金額。
desc: string
:- 定義了一個名為 desc 的屬性,類型是字串。
- 描述:這個屬性用來表示交易的描述或說明。
details: OrderDetail[]
:- 定義了一個名為 details 的屬性,類型是 OrderDetail 類型的陣列。
- 描述:這個屬性用來表示交易中的每個商品的詳細信息。OrderDetail 是一個自定義的類型,用來描述每個商品的詳細內容。
returnUrl: string
:- 定義了一個名為 returnUrl 的屬性,類型是字串。
- 描述:這個屬性用來表示支付完成後,用戶將被重定向到的 URL。
4.定義OrderDetail
的接口:接口用來描述單個商品的詳細信息,包括價格、名稱和數量。
interface OrderDetail {
price: string;
name: string;
amount: number;
}
程式碼解說:
interface OrderDetail
:- interface:定義了一個接口,名為 OrderDetail。
- 接口是一種用來定義物件結構的方式,確保物件符合預期的屬性和類型。
price: string
:- 定義了一個名為 price 的屬性,類型是字串。
- 描述:這個屬性用來表示商品的價格。將價格定義為字串類型允許它包含貨幣符號或小數點。
name: string
:- 定義了一個名為 name 的屬性,類型是字串。
- 描述:這個屬性用來表示商品的名稱。
amount: number
:- 定義了一個名為 amount 的屬性,類型是數字。
- 描述:這個屬性用來表示商品的數量。
※ 設計ECPAY control:
●controller →orderController.ts:(目的在創建訂單和支付請求)
const result = await paymentDispatcher({
paymentProvider,
paymentWay,
payload: {
billId: uid,
totalPrice,
desc: `create order bill from ${uid} with ${contents
.map((content) => content.productId)
.join(",")
}`,
returnURL: `${process.env.END_POINT}/orders/update`,
details: contentInfos || [],
}
})
程式碼解說:
1.等待非同步操作完成:await
關鍵字用來等待 paymentDispatcher
函數返回一個 Promise
,並在該 Promise
被解決(resolved)後返回結果。
2.處理非同步函數的返回值:當 paymentDispatcher
函數完成並給出結果時,這個結果會被存到 result
變數。就可以在後續的程式碼中使用 result
了。
3.金流 API 的呼叫:使用 paymentDispatcher
函數來處理金流 API 的串接。
4.paymentProvider
和 paymentWay
:這兩個變數指定了支付提供商(如 ECPAY)和支付方式(如 CVS)。
5.payload
:payload
是傳遞給 paymentDispatcher
函數的參數物件,包含了支付的相關資料。
6.billId
:uid
是一個唯一的識別碼,用於標識這筆支付交易。
7.totalPrice
:表示支付的總金額。
8.desc
:描述欄位裡面生成的字串說明了這筆訂單,包含了 uid
和 contents
中每個商品的 productId
。
9.returnURL
:使用環境變數 process.env.END_POINT
作為指定支付完成後返回的URL。
※ 環境變數.env
END_POINT='http://localhost:30000'

10.details
:
- 檢查
contentInfos
是否為null
或undefined
:確保details
屬性有一個預設值,避免因為contentInfos
沒有值而引發錯誤。 - 提供預設值:當
contentInfos
沒有值時,提供一個預設的空陣列[]
,確保程式碼正常運行。
●controller →orderController.ts:(目的在保留與支付相關的商品名稱和價格)
const contentInfos = contents.map(content => ({
name: ((products?.find(p => p.id === content.productId))?.name|| "",
price: content.price
}))
程式碼解說:
1.從 contents 陣列中提取訊息,並生成一個新的陣列 contentInfos。新的陣列包含每個商品的名稱和價格。
2.使用 map
函數迭代 contents
陣列:
map
函數會為 contents
中的每個元素呼叫一次回調函數,並返回一個新的陣列。每個元素會被轉換為新陣列中的一個元素。
3.尋找商品名稱:
- 使用
find
函數在products
陣列中查找與content.productId
相匹配的商品。 - 如果找到匹配的商品,
find
函數會返回該商品物件;否則,返回undefined
。
4.條件運算子 ?:
第一個 ?.:確保 products 為 null 或 undefined 時,不會引發錯誤。
第二個 ?.:確保 find 方法未找到匹配元素時,不會引發錯誤。
5.提供默認值:
- 當前面的鏈條返回
undefined
時,使用|| ""
提供一個默認值空字串。 - 這樣可以確保
name
屬性永遠有一個值,即使查找失敗或products
為null
或undefined
值而導致的錯誤。
6.生成 contentInfos
陣列的元素:
為新陣列 contentInfos
中的每個元素建立一個物件,包含商品名稱和價格。
●controller →orderController.ts:(目的在擷取產品 ID)
const products = await this.productModel.findByIds
(contents.map(product => product.productId))
程式碼解說:
1.擷取產品 ID:
contents.map(product => product.productId)
使用 map
函數從 contents
陣列中提取每個商品的 productId
,並生成一個新的包含所有 productId
的陣列。
2.查找產品資料:
const products = await this.productModel.findByIds
(contents.map(product => product.productId));
- 使用
findByIds
方法,將提取到的productId
陣列作為參數傳入,從資料庫中查找所有與這些productId
匹配的產品資料。 await
關鍵字表示這是一個非同步操作,會等待查詢操作完成後再繼續執行下一步。
●model →product.ts:(目的在從資料庫中查找與指定 ID 列表匹配的產品)
findByIds(ids: string[], trx?: Knex.Transaction): Promise<Product[] | null>

程式碼解說:
1.定義函數:
findByIds(ids: number[], trx?: Knex.Transaction): Promise<Product[] | null>
這個函數定義接受一個包含多個產品 ID 的字串陣列(ids
)和一個可選的資料庫交易(trx
)。
並返回一個 Promise
,該 Promise
解析為 Product
類型的陣列或 null
。
2.參數:
ids: number[]
:要查找的產品 ID 列表,這個陣列包含多個產品的 ID。trx?: Knex.Transaction
:可選的 Knex 交易物件,用於確保所有資料庫操作在一個交易中執行。
●model →product.ts:(目的在根據 ID 列表從資料庫中查找產品。)
public findByIds: IProductModel['findByIds'] = async (ids, trx) => {
let queryBuilder = this.knexSql(this.tableName).whereIn('id', ids)
if (trx) queryBuilder = queryBuilder.transacting(trx);
const result = await queryBuilder;
if (isEmpty(result)) return null
return result.map(this.DBData2DataObject) as Product[];
}
程式碼解說:
1.函數定義:
public findByIds: IProductModel['findByIds'] = async (ids, trx) => {}
findByIds
是IProductModel
介面中的方法。- 它是個非同步函數(
async
),接受兩個參數:ids
是一個字串陣列,包含需要查找的產品 ID;trx
是一個可選的 Knex 交易物件。
2.建立查詢構建器:
let queryBuilder = this.knexSql(this.tableName).whereIn('id', ids);
使用 Knex 建立一個查詢構建器(queryBuilder
),從資料表中查找 ID 在 ids
列表中的產品。
3.事務處理:
if (trx) queryBuilder = queryBuilder.transacting(trx);
如果傳入了 trx
參數,將查詢構建器與該交易物件關聯,確保所有操作在同一個事務中執行。
4.執行查詢:
const result = await queryBuilder;
使用 await
等待查詢執行並獲取結果。
5.檢查結果是否為空:
if (isEmpty(result)) return null;
使用 lodash 的 isEmpty 函數檢查查詢結果是否為空。如果結果為空,返回 null。
6.轉換結果:
return result.map(this.DBData2DataObject) as Product[];
如果結果不為空,使用 map
方法將每個資料庫返回的記錄轉換為 Product
物件,並返回轉換後的陣列。
●model →base.ts:
從 public
到 protected
的變更:目的在限制DBData2DataObject存取範圍。

●controller →orderController.ts:(目的在透過 Express 框架將 JSON 格式的回應傳送給客戶端)
//金流API的串接
const result = await paymentDispatcher({
paymentProvider,
paymentWay,
payload: {
billId: uid,
totalPrice,
desc: `create order bill from ${uid} with ${contents
.map((content) => content.productId)
.join(",")
}`,
returnURL: `${process.env.END_POINT}/orders/update`,
details: contentInfos || [],
},
});
res.json({ status: 'success', data: result })
});
} catch (err) {
res.status(500).json({ errors: err })
throw err;
}
程式碼解說:
res.json({ status: 'success', data: result })
-
res.json()
方法用來傳送 JSON 格式的資料作為回應。這是一種方便的方法來設定Content-Type
為application/json
並傳送 JSON 資料。 status
: 顯示回應狀態。在這裡,它設為'success'
,表示操作成功。data
: 包含操作結果。這裡,result
是之前由paymentDispatcher
函數返回的結果。
※ 產生ECPAY 前端畫面:
●javascripts →index.js:(目的在將從 result 中獲取的 HTML 資料顯示在頁面上)
const { data: html } = result;
this.ecpayHtml = html;
this.$nextTick(() => {
document.getElementById('_form_aiochk').submit();
})
console.log("--->", this.ecpayHtml);
},
},
程式碼解說:
1.解構賦值:
const { data: html } = result;
將 result
物件中的 data
屬性解構出來,並賦值給變數 html
。
2.設定成員變數:
this.ecpayHtml = html;
將 html
資料賦值給 this.ecpayHtml
,這樣可以在 Vue 中使用該資料。
3.使用 nextTick
:
this.$nextTick(() => {
document.getElementById('_form_aiochk').submit();
});
this.$nextTick
是 Vue 中的一個方法,確保 DOM 更新後自動提交表單。- 在回調函數中,通過
document.getElementById('_form_aiochk').submit();
處理付款後自動提交具有 ID_form_aiochk
的表單。
4.除錯輸出:
console.log("--->", this.ecpayHtml);
輸出 this.ecpayHtml
到瀏覽器控制台,以便檢查 html
資料的內容。
●javascripts →index.js:(目的在初始化組件的資料狀態)
return {
ecpayHtml: '',
};
程式碼解說:
- 返回一個物件,其中包含
ecpayHtml
屬性,初始值設為空字串''
。 - 在 Vue 組件中,這通常是在
data
方法中使用,用來初始化組件的資料屬性。 - 初始化
ecpayHtml
為空字串是為了在組件創建時有個預設值,這樣後面可以正確地更新和使用這個屬性。
●views →index.ejs:(目的在插入動態的 HTML 內容)
<div id="ecpay" v-html="ecpayHtml"></div>
程式碼解說:
1.v-html
指令:
v-html
是 Vue.js 提供的一個指令,用來在元素內部動態插入 HTML 內容。
2.ecpayHtml
變數:
ecpayHtml
是一個包含 HTML 字串的變數。Vue.js 會自動更新 div
元素內部的內容,使其顯示最新的 HTML。
3.id="ecpay"
可以在 JavaScript 中使用 document.getElementById('ecpay')
精確定位這個 div
元素,便於進行後續操作。
●測試結果:
1.按下按鈕:

2.畫面結果:

3.取得繳費代碼:

※ 確認支付流程:
●廠商後台管理:
1.登入綠界科技的開發者測試後台:

2.確認MySQL的訂單:

3.進入一般訂單查詢全方位金流訂單,付款方式選擇超商代碼,然後按查詢:

4.出現訂單結果:


●驗證支付流程是否正確:按下模擬付款
