# B-CP-PRDS-02 販售產品詳細頁
> [name=JasonWu]
###### tags: `CP頁`
## 網址
- https://{domain}/product/{型錄名稱}-{型錄ID}.html
- ex: https://www.taiwantrade.com/product/font-color-red-salvia-miltiorrhiza-mouth-dissolving-font-pastilles-120-pastille-bottle-2-bottles-box-518429.html
## 原版程式
* com.hyweb.tt.cms.front.rest.ProductContentResource.java
* com.hyweb.tt.cms.front.service.pagedata.ProductContentPageData.java
## 頁面功能說明
- 透過 api 取得頁面所需資料
- 頁首部分共用
- 型錄內容說明 
- 上方需顯示麵包屑 > api 提供
- 點選下面的小圖,上面會顯示對應大圖
- 大圖須提供 zoom in 功能 
- 圖片下方的 facebook, twitter 等按鈕 
請參考 https://s7.addthis.com/js/300/addthis_widget.js#pubid=ra-585239dd7919d697
- 當公司是 ep 類型時,Supplier 下方會出現 More About This Product,會連結至 ep 頁面 > 如果 api 有回傳 epUrl 時顯示
- 如果有販售,顯示 Price、Payment 等相關訊息,api 會提供
- 如果有販售,api 提供的資訊有折扣時,顯示的金額都會是 "折扣價"
- 如果有販售,點選 Request for Quotation,會開新視窗,顯示 "RFQ商機頁"
- 如果有販售,Quantity 可以變更,變更範圍需要參考上面的 Price table,決定對應的上下限 
參考上圖,Quantity 需介於 1~12 之間
- 如果有販售,Quantity 變更時,需要從 price 表中找到對應的價格,並計算總額,以上圖為例,Quantity = 4,所以 Price 採用 900.00,並乘上數量後,顯示於 Total Price
- 如果有販售,specInfoSelect 的資料需要做特殊效果處理
- 以 https://www.ttstaging.com.tw/product/1560112 為例,當選擇 color 的時候,如果後台有設定 color = red 有圖片時
,型錄詳目頁需要顯示對應的圖片
- 如果有販售,會有 Buy Now 按鈕,點選 Buy Now 時,將會開啟視窗,進入 shopping cart 頁面
- 點選 Buy Now 按鈕時,如果如上圖,有 Size, Color 這類的 SpecInfoSelect 資訊時,必須都要選擇後,才可以開啟 shopping cart 頁面
- 點選 Contact Supplier 按鈕,頁面跳轉到下方的聯絡區塊
- Add to cart 與 Add to favorite 請參考條列頁,點選後將此型錄加入 cart 或是 favorite,如果已經加入,購物車跟 favorite 的小圖示需要顯示對應的狀態
- 下方的 line, skype 等資訊,依照 api 回傳值來判斷是否要顯示
---
- Product Detail
- 型錄相關資訊,顯示 api 所回傳的資料
- 點選認證圖片的燈箱效果參考 C-CP-COMS-2 認證燈箱
- 如果 api 有回傳附加檔案,點選後可以下載 
---
- Company Profile
- 公司相關資訊,顯示 api 所回傳的資料
- 如果 api 有 other products 資料 
- 點選 product 連結,會 redirect 到該型錄詳目頁
- 如果 api 有 All products 連結,代表該公司有 ep 網址,redirect 到對應的 url
- Contact Us 需要判斷使用者是否登入,如果尚未登入,顯示的畫面會是 
- 如果沒有登入,點選 Log in to view detail 時,需要 direct 到登入頁面,登入成功後會回到原本的 product cp 頁面
- <font color="red">使用者提到要用燈箱來處理登入相關資訊,需要確認需求</font>
- 如果使用者已登入,可以看到 Owner, Contact Person, Business Phone Number 等資料 
- 點選 Contact Supplier,跳轉至頁面下方的聯絡區塊
- 如果 api 有回傳地址,需要顯示 google map 燈箱
---
- Shipping & Packaging 
- 顯示 api 相關資料
- 當切換國家、區域的時候,再次呼叫 api,並顯示 api 回傳的資料
---
- Payment Terms 
- 顯示 api 相關資料
---
- Return Policy 
- 顯示 api 相關資料
---
- 聯絡人區塊 
- 參考 Inquiry Product 商機頁 (步驟一) 與 Inquiry Product 商機頁 (步驟二)
---
- 型錄推薦區塊 
- 顯示 api 相關資料
- 透過 slider 切換顯示項目
- 點選型錄 url,redirect 至該型錄詳目頁
## 相關 api 分析
- 依照功能分類 api,可以分為以下幾類
- 產品詳目頁 API
- 公司內容 API
- 認證 API
- 如果有販售,需要有計算運費取得國家的 API
- 如果有販售,需要有計算運費取得國家區域的 API
- 如果有販售,需要有計算運費的 API
- 推薦產品 API
- Inquiry Product 新增商機 API
- SEO ADM 設定 product cp 參數 API
- 參考 ep 設計,可參考的 API 可以分為以下幾個區塊
- basicInfo > 取得產品名稱、型號、產品說明、產品認證等基本內容
- sliderGallery > 取得產品圖片內容
- videoInfo > 取得影片內容
- multimedia > 取得 3d/360/video 的多媒體內容
- specInfo > 取得產品設定的其他額外內容
- specInfoSelect > 特殊規格內容,例如大小、顏色等內容
- priceRangeInfo > 數量與價格對應表
- attachInfo > 取得附加檔案
- paymentTerm > 如果有販售,需取得 payment 相關內容
- returnPolicy > 如果有販售,需取得退換貨相關內容
## 產品詳目頁 API
- 取得型錄相關資訊
### 規格
- path : ${TT-API網址}/product/info/{did}
- method : GET
- query : ?pid={pid}&langId={langId}
### API 邏輯
- 傳入 product id 與 language id
- 透過 sql 找出該型錄相關的資料並回傳
- 是否有販售,回傳資訊不同,顯示方式也不同
### Input
Column | Type | Require | Desc
-----------|----------|---------|---------
did | number | Y | domain id
pid | number | Y | 型錄id
langId | number | Y | 語系id
### Output
- 回傳相關 json 內容,基本欄位參考 ep 相關功能
- 呼叫一次 api 回傳所有資訊,或者依區塊切開 api 內容,呼叫多次,這一段需要再討論
- 目前先依照一隻 api 回傳的方式來處理
- json 內容如下:
```=json
{
"code" : {{ number }} , // 代碼,0:ok、 < 0: error 使用
"errorMsg" : {{ string }} , // 錯誤訊息
// 型錄基本訊息
"basicInfo" : {
"productId" : {{ number }} , // 型錄
"productName" : {{ string }} , // 型錄名稱
"epUrl" : {{ string }} , // ep url
"modelNo" : {{ string }} , // 型號
"hasNewest" : {{ number }} , // 無(0)/有(1) newest tag
"hasFeatured" : {{ number }} , // 無(0)/有(1) featured tag
"hasSelling" : {{ number }} , // 無(0)/有(1) 販售
"hasDiscount" : {{ number }} , // 無(0)/有(1) 折扣
"hasFreeShipment" : {{ number }} , // 無(0)/有(1) 免運費
"catalogStandardCid" : {{ number }} , // 標準 taitra code
"fullCatalogName" : {{ string }} , // 標準 taitra code 名稱
"madeIn" : {{ string }} , // 產地
"priceCurrencyName" : {{ string }} , // 幣別
"priceRange" : {{ string }} , // 價格區間,格式 min-max
"discount" : {{ number }} , // 折扣,無折扣為 null
"discountStartDate" : {{ string }} , // 折扣開始日期,無折扣為 ""
"discountEndDate" : {{ string }} , // 折扣結束日期,無折扣為 ""
"fullDiscountEndDate" : {{ string }} , // 折扣結束日期,無折扣為 ""
"discountDayLeft" : {{ number }} , // 折扣剩餘天數,無折扣為 null
"discountPriceRange" : {{ string }} , // 折扣價格區間,格式 min-max
"unitName" : {{ string }} , // 單位
"ezMinOrderCount" : {{ number }} , // 最小訂購數量
"ezMaxOrderCount" : {{ number }} , // 最大訂購數量
"contactSkype" : {{ string }} , // 聯絡人 skype 帳號
"contactLine" : {{ string }} , // 聯絡人 line 帳號
"contactQq" : {{ string }} , // 聯絡人 qq 帳號
"contactWeChat" : {{ string }} , // 聯絡人 wechat 帳號
"contactWhatsApp" : {{ string }} , // 聯絡人 whatsapp 帳號
"contactFbMessenger" : {{ string }} , // 聯絡人 fb 帳號
"videoId" : {{ number }} , // 影片 video id,沒有為 null
"videoTypeName" : {{ string }} , // 影片 type
"videoTitle" : {{ string }} , // 影片標題
"videoUrl" : {{ string }} , // 影片 url
"adSlogan" : {{ string }} , // 型錄廣告詞
"logoType" : {{ number }} , // 1:MIC_logo, 2:DIC_logo, 其他:不顯示
"keyFaturesHtml" : {{ string }} , // 型錄說明
"paymentTerms" : {{ string }} , // 其他 Payment 說明
"minOrderQuantityDesc" : {{ string }} , // 最小訂購數量說明
"payCodeInfos" : {{ string }} , // 其他 Payment 圖示與排序資訊
// "[{\"sort\": 1, \"code\": \"idealez_paypal\"},{\"sort\": 2, \"code\": \"idealez_card\"},...]"
},
// 圖片相關,array 中可以放多張
"sliderGalleryInfos" : [
{
"seq" : {{ number }} , // 圖片順序
"haspPrimary" : {{ number }} , // 是(1)/否(0) 為主圖
"imgDesc" : {{ string }} , // 圖片說明
"img360_360Url" : {{ string }} , // 圖片 360x360
"img100_100Url" : {{ string }} , // 圖片 100x100
"imgOriUrl" : {{ string }} , // 原始圖片 url
"pcImgUrl" : {{ string }} , // pc 版本顯示圖片 url
"mobileImgUrl" : {{ string }} // mobile 版本顯示圖片 url
}
],
// 影片相關
"videoInfo" : {
"id" : {{ number }} , // 影片 id
"type" : {{ string }} , // 影片類型
"title" : {{ string }} , // 影片標題
"url" : {{ string }} // 影片 url
},
// 3d/360 多媒體相關
"multimedia" : {
"multi_media_3d_title" : {{ string }} , // 多媒體 3d 標題
"multimedia_3d_url" : {{ string }} , // 多媒體 3d url
"multi_media_360_title" : {{ string }} , // 多媒體 360 標題
"multimedia_360_url" : {{ string }} , // 多媒體 360 url
"video_title" : {{ string }} , // 多媒體 video 標題
"video_url" : {{ string }} // 多媒體 video url
},
// 規格相關,可能有多筆,顯示於說明文字
"specInfo" : [
{
"name" : {{ string }} , // 規格名稱
"value" : {{ string }} // 規格值
},
],
// 規格下拉相關,可能有多筆,選擇後有可能需要增加對應的圖片
"specInfoSelect" : [
{
"sid" : {{ number }}, // 序號
"name" : {{ string }}, // 名稱
"specDatas" : [
{
"specDetailId" : {{ number }}, // 序號
"name" : {{ string }}, // 名稱
"attachId" : {{ number }}, // 圖片 aid
"pic480" : {{ string }}, // 480x480 圖片
"pic50" : {{ string }}, // 50x50 圖片
"pic100" : {{ string }} // 100x100 圖片
},
]
}
],
// 購買數量與價格匹配區間,可以多筆,對應的金額會用在計算上
"priceRangeInfo" : [
{
"seq" : {{ number }}, // 序號
"quantityRange" : {{ string }}, // 數量區間 min-max
"price" : {{ string }}, // 本區間價格,格式: 幣別 + 金額,例如 USD 10.50
"prepareDay" : {{ string }}, // 準備日
"discount" : {{ number }}, // 折扣,無折扣為 0
"isSelling" : {{ number }}, // 是(1)/否(0) 販售
"discountPrice" : {{ string }} // 本區間折扣價格,格式: 幣別 + 金額,例如 USD 10.50
}
],
// 附加檔案,可能有多筆
"attachInfo" : [
{
"fileUrl" : {{ string }}, // 檔案 url
"fileName" : {{ string }}, // 檔案名稱
"fileDesc" : {{ string }}, // 檔案說明
"fileMbSize" : {{ string }} // 檔案大小
}
],
// 如果有販售,需取得 payment 相關內容
"paymentTerm" : [
{
"code" : {{ string }}, // payment code
"allCurrency" : {{ string }} // payment 幣別
}
],
"returnPolicy" : {{ string }} // 退換貨內容文字
}
```
### 取值方式
- 透過 sql 取值
```=sql
```
---
## 公司內容 API
- 參考相關公司 API
### 規格
- path : ${TT-API網址}/product/company/{did}
- method : GET
- query : ?cid={cid}&langId={langId}&loginCheck={check}
### Input
Column | Type | Require | Desc
-----------|----------|---------|---------
did | number | Y | domain id
cid | number | Y | 公司 id
langId | number | Y | 語系 id
loginCheck | string | Y | 是否已登入,決定是否要回傳公司聯絡人資訊,要定義一下作法
### Output
- 參考相關公司 API
### 取值方式
- 參考相關公司 API
---
## 販售國家 API
- 參考目前 ep 的販售國家取法
### 規格
- path : ${TT-API網址}/product/deliverycountry/{languageId}
- method : GET
### Input
Column | Type | Require | Desc
---------------|----------|---------|---------
languageId | number | Y | 語系id
### Output
- json 內容如下:
```=json
{
"code" : {{ number }} , // 代碼,0:ok、 < 0: error 使用
"errorMsg" : {{ string }} , // 錯誤訊息
"rows" : [
{
"cid" : {{ number }} , // 國家 id
"hasDefault" : {{ number }} , // 是否為預設選取
"code" : {{ string }} , // 國家簡碼
"name" : {{ string }} // 國家名稱
},...
]
}
```
### 取值方式
- 透過 sql 取值
```
```
---
## 販售區別 API
- 參考目前 ep 的販售區域取法
- 需要傳入國家id
### 規格
- path : ${TT-API網址}/product/deliverystate/{countryId}/{langId}
- method : GET
### Input
Column | Type | Require | Desc
-----------|----------|---------|---------
countryId | number | Y | 運送國家id
langId | number | Y | 語系id
### Output
- json 內容如下:
```=json
{
"code" : {{ number }} , // 代碼,0:ok、 < 0: error 使用
"errorMsg" : {{ string }} , // 錯誤訊息
"rows" : [
{
"cid" : {{ number }} , // 區域 id
"name" : {{ string }} // 區域名稱
},...
]
}
```
### 取值方式
- 透過 sql 取值
```
```
---
## 販售運費計算 API
- 參考目前 ep 的販售運費算法
- 需要傳入國家id,不同國家取得的運費不同
### 規格
- path : ${TT-API網址}/product/sellinfo/{did}
- method : GET
- query : ?pid={pid}&countryId={countryId}&langId={langId}
### Input
Column | Type | Require | Desc
-----------|----------|---------|---------
did | number | Y | domain id
pid | number | Y | 型錄id
countryId | number | Y | 運送國家id
langId | number | Y | 語系id
### Output
- json 內容如下:
```=json
{
"code" : {{ number }} , // 代碼,0:ok、 < 0: error 使用
"errorMsg" : {{ string }} , // 錯誤訊息
"rows" : [
{
"code" : {{ string }} , // code
"name" : {{ string }} , // name
"shippingType" : {{ number }} , // 0: 免運費 1:自訂運費 2:固定運費 3:會員專屬優惠運費
"customAmount" : {{ number }} , // 自訂運費單位數
"customPortage" : {{ number }} , // 自訂運費
"customOverAmount" : {{ number }} , // 自訂超過運費單位數
"customOverPortage" : {{ number }} , // 自訂超過運費
"forAllCountry" : {{ number }} , // 是否為全部國家(1: 是, 0: 否, default 為 0)
"fixFee" : {{ number }} , // 固定運費
"spType" : {{ number }} , // 優惠方案:1-貿協優惠運費,2-廠商自訂折扣
"customDiscount" : {{ number }} , // 廠商自訂折扣折數
"calculateRule" : {{ number }} , // 計價原則
"productHeight" : {{ number }} , // 產品高
"productLength" : {{ number }} , // 產品長
"productWidth" : {{ number }} , // 產品寬
"productWeight" : {{ number }} , // 產品重量
"estimatedDeliveryTime" : {{ string }} // 預計寄送時間
}
]
}
```
### 取值方式
- 透過程式取值
```
```
---
## 推薦產品 API
- 透過 idol 取得該型錄推薦的未販售型錄
- recommane > 未販售型錄
- small order > 有販售型錄
- 參考現行邏輯,組出 idol url
### 規格
- 參考 https://hackmd.io/@jTFbLxrFR6qCyUF4lSdQCA/rJoPiGVI_
- path : ${TT-API網址}/products/detail/recommends/{did}
- method : GET
- query : ?id={id}&type={type}&cid={cid}
### Input
Column | Type | Require | Desc
-----------|----------|---------|---------
did | number | Y | domain id
id | number | Y | 型錄id
type | string | Y | 固定傳入 'product'
cid | number | Y | 公司id
### Output
- json 內容如下:
```=json
{
"code" : {{ number }} , // 代碼,0:ok、 < 0: error 使用
"errorMsg" : {{ string }} , // 錯誤訊息
"rows" : [
{
"productId" : {{ number }}, // 推薦型錄id
"name" : {{ string }}, // 推薦型錄名稱
"modelNo" : {{ string }}, // 推薦型錄型號
"productUrl" : {{ string }}, // 推薦型錄url
"imgUrl150" : {{ string }}, // 推薦型錄圖片 150x150
"imgUrl220" : {{ string }}, // 推薦型錄圖片 220x220
"imgUrl480" : {{ string }}, // 推薦型錄圖片 480x480
"isFreeShipping" : {{ number }}, // 推薦型錄 是(1)/否(0) 免運費
"isSelling" : {{ number }}, // 推薦型錄 是(1)/否(0) 販售
"isDiscount" : {{ number }}, // 推薦型錄 是(1)/否(0) 折扣
"quantity" : {{ number }}, // 推薦型錄數量
"unitName" : {{ string }}, // 推薦型錄單位
"priceRange" : {{ string }}, // 推薦型錄價格,USD 10.00-20.00
"priceDiscountRange" : {{ string }}, // 推薦型錄折扣價格,USD 10.00-20.00
}
]
}
```
### 取值方式
- 透過 idol 取值
---
## Inquiry Product 新增商機 API
- 參考 https://hackmd.io/-JgxZNPEQ2OCtJPxCYVLYw
---
## SEO ADM 設定 product cp 參數 API
- adm 可以設定相關頁面的標題等資訊,透過此 api 取得設定檔
- 相關頁面都有可能會用到此功能
- 透過 api 取得 adm 所設定的格式,例如 Product %productName% %companyName%
- 一併回傳其他頁面相關 meta tag
### 規格
- 參考 https://docs.google.com/spreadsheets/d/12U90GlZtqTFVemxzp5lFCv5l_eAZchVlOJN6xbRxDLI/edit#gid=0&range=A67
- path : ${TT-API網址}/domains/seo/{seoType}/{pageType}/{did}/{rowId}
- method : GET
### Input
Column | Type | Require | Desc
-----------|----------|---------|---------
seoType | string | Y | normal
pageType | string | Y | 固定為 productCp
did | number | Y | domain id
rowId | number | Y | 傳入 product id
### Output
- 參考 https://docs.google.com/spreadsheets/d/12U90GlZtqTFVemxzp5lFCv5l_eAZchVlOJN6xbRxDLI/edit#gid=0&range=A67
### 取值方式
- 參考 https://docs.google.com/spreadsheets/d/12U90GlZtqTFVemxzp5lFCv5l_eAZchVlOJN6xbRxDLI/edit#gid=0&range=A67