x
This commit is contained in:
1 parent
4014e4d97b
commit
c7c08d7d64
2 files changed
+839
-13
No files matched your search
@@ -0,0 +1,797 @@
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
Sparkles,
|
||||
Copy,
|
||||
Check,
|
||||
X,
|
||||
BookOpen,
|
||||
Flower2,
|
||||
Sparkle,
|
||||
Shirt,
|
||||
Wrench,
|
||||
Code2,
|
||||
CheckCircle2,
|
||||
Layers,
|
||||
Globe2
|
||||
} from 'lucide-react'
|
||||
|
||||
interface ProductJsonGuideModalProps {
|
||||
isOpen: boolean
|
||||
onClose: () => void
|
||||
onOpenImport?: () => void
|
||||
}
|
||||
|
||||
const GUIDE_OVERVIEW_MARKDOWN = `# คู่มือการใช้ AI/LLM สร้าง JSON สำหรับนำเข้าสินค้า (Product Catalog Generator)
|
||||
|
||||
ระบบรองรับการสร้างสินค้าจำนวนมากผ่าน **JSON Import** ในหน้า Admin (/admin/products -> คลิกปุ่ม "Import JSON") หรือเรียก API POST /api/products/bulk
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ ข้อกำหนดทางเทคนิคสากล (Universal Schema Rules)
|
||||
|
||||
ไม่ว่าจะใช้ไฟล์หรือหมวดหมู่ใด LLM จะต้องยึดหลักเกณฑ์ทางเทคนิคของระบบดังนี้:
|
||||
|
||||
1. Format: ต้องส่งคืนเฉพาะ Valid JSON Array ([ ... ]) ล้วนๆ ไม่มีข้อความเกริ่นหรือปิดท้าย
|
||||
2. Numeric Fields: price, stock, order ต้องเป็นตัวเลข Number แท้จริง (ห้ามครอบเครื่องหมายคำพูด เช่น "1500")
|
||||
3. Product Types:
|
||||
- Simple Product (สินค้าเดี่ยว): ใส่ price, stock, sku, barcode ที่ระดับบนสุด ระบบจะแปลงเป็น Base Variant ในฐานข้อมูลให้อัตโนมัติ
|
||||
- Variable Product (สินค้ามีตัวเลือก ไซส์/สี/ขนาด): กำหนด options (เช่น [{"name": "ขนาด", "values": ["S", "M"]}]) และใน variants ต้องมี option1 ตรงกับค่าใน values ทุกตัวอักษร
|
||||
4. Multilingual (รองรับครบ 8 ภาษา): ระบบรองรับการแปลภาษาผ่านฟิลด์ translations ครบทั้ง 8 ภาษามาตรฐานของระบบ:
|
||||
- th (ไทย - ภาษาหลัก)
|
||||
- en (English - สากล)
|
||||
- ja (日本語 - ญี่ปุ่น)
|
||||
- zh (简体中文 - จีนตัวย่อ)
|
||||
- vi (Tiếng Việt - เวียดนาม)
|
||||
- ko (한국어 - เกาหลี)
|
||||
- lo (ພາສາລາວ - ลาว)
|
||||
- it (Italiano - อิตาลี)
|
||||
ในแต่ละภาษากำหนด name, description, details ให้สอดคล้องกัน
|
||||
5. Images: กำหนดเป็น Array ของ URL รูปภาพจริง เช่น จาก Unsplash หรือ CDN
|
||||
|
||||
---
|
||||
|
||||
## 🚀 ขั้นตอนการนำเข้าข้อมูล (Import Workflow)
|
||||
|
||||
1. เลือกแท็บหมวดธุรกิจที่ต้องการ แล้วกดปุ่ม "Copy Prompt"
|
||||
2. ส่งให้ LLM เช่น ChatGPT, Claude 3.5 Sonnet หรือ Google Gemini
|
||||
(สามารถระบุจำนวนสินค้าที่ต้องการเพิ่มเติมได้ เช่น "ขอ 20 รายการ")
|
||||
3. คัดลอกผลลัพธ์ JSON ที่ได้จาก LLM
|
||||
4. คลิกปุ่ม "เปิดหน้าต่าง Import JSON" -> วางโค้ด JSON -> กดยืนยันนำเข้าสินค้า`
|
||||
|
||||
const WELLNESS_PROMPT = `คุณคือ Senior E-commerce Catalog Specialist และ Luxury Brand Copywriter ระดับสากล เชี่ยวชาญสินค้ากลุ่ม Luxury Wellness, Organic Aromatherapy, Fine Fragrance และ Spa Lifestyle (ในระดับเทียบเคียงกับแบรนด์ Panpuri, Jo Malone, Diptyque, Aesop, HARNN)
|
||||
|
||||
[ภารกิจของคุณ]:
|
||||
สร้างข้อมูลสินค้าสำหรับนำเข้าสู่ระบบ E-commerce ในรูปแบบ **Valid JSON Array** ตาม Schema ของระบบอย่างเคร่งครัด
|
||||
|
||||
[กฎและข้อกำหนดทางเทคนิค]:
|
||||
1. ผลลัพธ์ต้องเป็น Valid JSON Array ล้วนๆ เริ่มต้นด้วย [ และจบด้วย ] เท่านั้น (ห้ามมีคำเกริ่นนำหรือคำลงท้าย)
|
||||
2. ฟิลด์ตัวเลข (price, stock) ต้องเป็น Number เท่านั้น ห้ามใส่เครื่องหมายคำพูด (ห้ามเป็น String)
|
||||
3. หมวดหมู่สินค้า (categoryName) ให้ใช้กลุ่มคำ เช่น:
|
||||
- "Essential Oil & Extract"
|
||||
- "Reed Diffuser"
|
||||
- "Aromatic Candle"
|
||||
- "Body & Bath Sanctuary"
|
||||
- "Room & Linen Mist"
|
||||
- "Hand & Nail Care"
|
||||
4. แบรนด์ (brandName): กำหนดเป็นชื่อแบรนด์หรู เช่น "Panpuri", "Jo Malone London", "HomAroma Heritage", "Siam Botanicals"
|
||||
5. รูปภาพ (images): ให้ใส่ Array ของ URL รูปภาพความละเอียดสูงจาก Unsplash ที่เกี่ยวข้องกับ Luxury Perfume, Candle, Essential Oil, Diffuser ที่เปิดดูได้จริง เช่น:
|
||||
- "https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?w=800"
|
||||
- "https://images.unsplash.com/photo-1617897903246-719242758050?w=800"
|
||||
- "https://images.unsplash.com/photo-1605651202774-7d573fd3f12d?w=800"
|
||||
- "https://images.unsplash.com/photo-1592945403244-b3fbafd7f539?w=800"
|
||||
6. การเขียน Copywriting:
|
||||
- "description": ภาษาหรูหรา ถ่ายทอดอารมณ์ สัมผัส และการบำบัดจิตใจ (Aromachology)
|
||||
- "details": ระบุ Scent Profile ละเอียด (Top Notes, Heart Notes, Base Notes), ปริมาตร/ขนาด, วิธีการใช้งาน, ส่วนผสมออร์แกนิก
|
||||
7. การรองรับหลายภาษา (Multilingual):
|
||||
ระบบรองรับครบ 8 ภาษาตาม Language Code สากล:
|
||||
- "th": ภาษาไทย (ภาษาหลัก)
|
||||
- "en": English (สากล)
|
||||
- "ja": 日本語 (ญี่ปุ่น)
|
||||
- "zh": 简体中文 (จีนตัวย่อ)
|
||||
- "vi": Tiếng Việt (เวียดนาม)
|
||||
- "ko": 한국어 (เกาหลี)
|
||||
- "lo": ພາສາລາວ (ลาว)
|
||||
- "it": Italiano (อิตาลี)
|
||||
ในฟิลด์ "translations" ให้สร้าง Object สำหรับแต่ละรหัสภาษาที่มี "name", "description", "details" แปลอย่างเป็นธรรมชาติ สละสลวย ตรงกับบริบทสินค้า
|
||||
8. โครงสร้างประเภทสินค้า:
|
||||
- สินค้าเดี่ยว (Simple): ระบุ price, stock, sku, barcode ที่ระดับบนสุด
|
||||
- สินค้ามีตัวเลือกย่อย (Variable เช่น ขนาด 10ml, 50ml, 100ml หรือกลิ่น): ต้องมี "options" และ "variants" ที่ค่า option1 ตรงกันทุกตัวอักษร
|
||||
|
||||
[ตัวอย่างรูปแบบ JSON ที่ต้องการ]:
|
||||
[
|
||||
{
|
||||
"name": "น้ำมันหอมระเหยบริสุทธิ์ ไซมีส วอเตอร์ 100% Pure Essential Oil",
|
||||
"categoryName": "Essential Oil & Extract",
|
||||
"brandName": "Panpuri",
|
||||
"description": "กลิ่นหอมอันเป็นเอกลักษณ์ที่ผสานความหอมละมุนของดอกมะลิหลวง กระดังงา และสะระแหน่ มอบความสดชื่น ผ่อนคลาย และฟื้นฟูจิตใจให้สงบสมดุล",
|
||||
"details": "• Scent Profile: Floral, Exotic, Uplifting\\n• Top Notes: Italian Bergamot, Crisp Mint\\n• Heart Notes: Royal Thai Jasmine, Organic Ylang Ylang\\n• Base Notes: Warm Sandalwood, Siam Benzoin\\n• วิธีใช้: หยด 4-6 หยดลงในเครื่องพ่นอโรมา หรืออ่างอาบน้ำ\\n• ขนาด: 10ml, 30ml",
|
||||
"options": [
|
||||
{
|
||||
"name": "ขนาด",
|
||||
"values": ["10ml", "30ml"]
|
||||
}
|
||||
],
|
||||
"variants": [
|
||||
{
|
||||
"option1": "10ml",
|
||||
"price": 1250,
|
||||
"stock": 40,
|
||||
"sku": "PP-SW-10ML",
|
||||
"barcode": "8859210010011"
|
||||
},
|
||||
{
|
||||
"option1": "30ml",
|
||||
"price": 2650,
|
||||
"stock": 25,
|
||||
"sku": "PP-SW-30ML",
|
||||
"barcode": "8859210010028"
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
"https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?w=800",
|
||||
"https://images.unsplash.com/photo-1617897903246-719242758050?w=800"
|
||||
],
|
||||
"translations": {
|
||||
"th": {
|
||||
"name": "น้ำมันหอมระเหยบริสุทธิ์ ไซมีส วอเตอร์ 100% Pure Essential Oil",
|
||||
"description": "กลิ่นหอมอันเป็นเอกลักษณ์ที่ผสานความหอมละมุนของดอกมะลิหลวง กระดังงา และสะระแหน่ มอบความผ่อนคลายและสมดุลแห่งจิตใจ",
|
||||
"details": "• กลิ่น: มะลิหลวง, กระดังงา, มิ้นต์สด\\n• ปริมาตร: 10ml, 30ml\\n• ธรรมชาติ 100% ไม่แต่งกลิ่นสังเคราะห์"
|
||||
},
|
||||
"en": {
|
||||
"name": "Siamese Water 100% Pure Essential Oil Blend",
|
||||
"description": "Signature scent blending sensual Royal Jasmine, Exotic Ylang Ylang, and refreshing Peppermint to inspire serenity.",
|
||||
"details": "• Scent: Royal Jasmine, Ylang Ylang, Fresh Peppermint\\n• Sizes: 10ml, 30ml\\n• 100% Pure Natural Essential Oil Blend"
|
||||
},
|
||||
"ja": {
|
||||
"name": "サイアミーズ ウォーター 100% ピュア エッセンシャルオイル",
|
||||
"description": "タイ王室のジャスミン、イランイラン、ミントが織りなす上質で穏やかな癒しの香り。",
|
||||
"details": "• 香調: フローラル、リラクゼーション\\n• 容量: 10ml / 30ml\\n• 100% 天然精油ブレンド"
|
||||
},
|
||||
"zh": {
|
||||
"name": "暹罗之水 100% 纯天然复方精油",
|
||||
"description": "融合皇家泰国茉莉、依兰依兰与清凉薄荷的招牌芬芳,舒缓身心,带来宁静祥和的安抚力量。",
|
||||
"details": "• 香调: 芳醇花香调、清新宁神\\n• 规格: 10ml, 30ml\\n• 100% 纯天然植物萃取"
|
||||
},
|
||||
"vi": {
|
||||
"name": "Tinh dầu nguyên chất Siamese Water 100%",
|
||||
"description": "Hương thơm đặc trưng hòa quyện hoa nhài hoàng gia Thái, ngọc lan tây và bạc hà thanh mát, mang lại sự thư thái tuyệt đối.",
|
||||
"details": "• Nốt hương: Hoa nhài, Ngọc lan tây, Bạc hà\\n• Dung tích: 10ml, 30ml\\n• 100% thiên nhiên"
|
||||
},
|
||||
"ko": {
|
||||
"name": "샴 워터 100% 퓨어 에센셜 오일",
|
||||
"description": "태국 로열 자스민, 일랑일랑, 상쾌한 페퍼민트가 어우러져 깊은 휴식과 마음의 평온을 선사하는 시그니처 향.",
|
||||
"details": "• 향 노트: 자스민, 일랑일랑, 페퍼민트\\n• 용량: 10ml, 30ml\\n• 100% 천연 에센셜 오일"
|
||||
},
|
||||
"lo": {
|
||||
"name": "ນ້ຳມັນຫອມລະເຫີຍ ໄຊຍາມີສ ວໍເຕີ 100% Pure Essential Oil",
|
||||
"description": "ກິ່ນຫອມອັນເປັນເອກະລັກທີ່ຜະສານດອກມະລິຫຼວງ, ດອກກະດັງງາ ແລະ ໃບສະລະແໜ່ ໃຫ້ຄວາມຜ່ອນຄາຍຈິດໃຈ.",
|
||||
"details": "• ກິ່ນ: ດອກມະລິ, ດອກກະດັງງາ, ມິ້ນ\\n• ຂະໜາດ: 10ml, 30ml"
|
||||
},
|
||||
"it": {
|
||||
"name": "Siamese Water Olio Essenziale Puro 100%",
|
||||
"description": "Fragranza iconica con Gelsomino Reale Thailandese, Ylang Ylang e Menta Piperita per favorire armonia e serenità.",
|
||||
"details": "• Profilo Olfattivo: Gelsomino, Ylang Ylang, Menta\\n• Formati: 10ml, 30ml\\n• 100% puro e naturale"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
[คำสั่ง]:
|
||||
กรุณาสร้างรายการสินค้ากลุ่ม Luxury Wellness ตามข้อกำหนดด้านบน จำนวน 8 รายการ โดยผสมผสานระหว่าง Reed Diffuser, Essential Oil, Scented Candle, Body Oil และ Room Spray ส่งผลลัพธ์เป็น Valid JSON Array เท่านั้น`
|
||||
|
||||
const BEAUTY_PROMPT = `คุณคือ Senior Beauty Merchandiser และ Cosmetics Catalog Specialist เชี่ยวชาญการจัดทำฐานข้อมูลสินค้าสำหรับร้านมัลติแบรนด์ความงามชั้นนำ เช่น EVEANDBOY, Beautrium, Sephora, Watsons
|
||||
|
||||
[ภารกิจของคุณ]:
|
||||
สร้างข้อมูลสินค้าเครื่องสำอางและสกินแคร์สำหรับนำเข้าสู่ระบบ E-commerce ในรูปแบบ **Valid JSON Array** ตาม Schema ของระบบอย่างเคร่งครัด
|
||||
|
||||
[กฎและข้อกำหนดทางเทคนิค]:
|
||||
1. ผลลัพธ์ต้องเป็น Valid JSON Array ล้วนๆ เริ่มต้นด้วย [ และจบด้วย ] เท่านั้น (ห้ามมีคำเกริ่นนำหรือคำลงท้าย)
|
||||
2. ฟิลด์ตัวเลข (price, stock) ต้องเป็น Number เท่านั้น ห้ามใส่เครื่องหมายคำพูด (ห้ามเป็น String)
|
||||
3. หมวดหมู่สินค้า (categoryName) ให้ใช้กลุ่มคำ เช่น:
|
||||
- "Skincare & Serum"
|
||||
- "Sunscreen & UV Protection"
|
||||
- "Face Makeup & Cushion"
|
||||
- "Lip Care & Color"
|
||||
- "Cleanser & Toner"
|
||||
- "Eye & Brow"
|
||||
4. แบรนด์ (brandName): ใส่ชื่อแบรนด์ยอดนิยมระดับโลกและแบรนด์ดังในไทย เช่น "La Roche-Posay", "CeraVe", "Laneige", "Rom&nd", "4U2", "Canmake", "Mizumi", "Jung Saem Mool"
|
||||
5. รูปภาพ (images): ใส่ Array ของ URL รูปภาพจาก Unsplash เกี่ยวกับ Cosmetics, Skincare Bottle, Makeup, Lipstick เช่น:
|
||||
- "https://images.unsplash.com/photo-1522337360788-8b13dee7a37e?w=800"
|
||||
- "https://images.unsplash.com/photo-1620916566398-39f1143ab7be?w=800"
|
||||
- "https://images.unsplash.com/photo-1571781926291-c477ebfd024b?w=800"
|
||||
- "https://images.unsplash.com/photo-1599305445671-ac291c95aaa9?w=800"
|
||||
6. การเขียน Copywriting:
|
||||
- "description": จุดเด่น สรรพคุณ ปัญหาผิวที่ตอบโจทย์ ผลลัพธ์หลังใช้ (เช่น ลดสิว, ผิวชุ่มชื้น 72 ชม., ป้องกันแสงแดด SPF50+ PA++++)
|
||||
- "details": ส่วนผสมสำคัญ (Active Ingredients เช่น Niacinamide, Hyaluronic Acid, Salicylic Acid), สภาพผิวที่เหมาะสม, วิธีการใช้, ปริมาณสุทธิ
|
||||
7. การรองรับหลายภาษา (Multilingual):
|
||||
ระบบรองรับครบ 8 ภาษาตาม Language Code สากล:
|
||||
- "th": ภาษาไทย (ภาษาหลัก)
|
||||
- "en": English (สากล)
|
||||
- "ja": 日本語 (ญี่ปุ่น)
|
||||
- "zh": 简体中文 (จีนตัวย่อ)
|
||||
- "vi": Tiếng Việt (เวียดนาม)
|
||||
- "ko": 한국어 (เกาหลี)
|
||||
- "lo": ພາສາລາວ (ลาว)
|
||||
- "it": Italiano (อิตาลี)
|
||||
ในฟิลด์ "translations" ให้สร้าง Object สำหรับแต่ละรหัสภาษาที่มี "name", "description", "details" แปลอย่างเป็นธรรมชาติ ตรงกับศัพท์ความงามและเครื่องสำอาง
|
||||
8. โครงสร้างประเภทสินค้า:
|
||||
- สินค้าเดี่ยว (Simple): เซรั่ม, โฟมล้างหน้า, ครีมกันแดดทั่วไป (ใส่ price, stock, sku, barcode ที่ระดับบนสุด)
|
||||
- สินค้ามีเฉดสี / ตัวเลือก (Variable): ลิปสติก, คุชชั่น, คอนซีลเลอร์ (ต้องมี "options": [{"name": "เฉดสี", "values": ["01 Light", "02 Natural"]}] และ "variants" ที่มี option1 ตรงกัน)
|
||||
|
||||
[ตัวอย่างรูปแบบ JSON ที่ต้องการ]:
|
||||
[
|
||||
{
|
||||
"name": "เซรั่มบำรุงผิวหน้าไฮยาลูรอนเข้มข้น B5 Hyaluronic Serum 30ml",
|
||||
"categoryName": "Skincare & Serum",
|
||||
"brandName": "La Roche-Posay",
|
||||
"price": 1490,
|
||||
"stock": 120,
|
||||
"sku": "LRP-B5-30ML",
|
||||
"barcode": "8858340010015",
|
||||
"description": "เซรั่มเข้มข้นฟื้นบำรุงผิวล้ำลึก ผสานไฮยาลูรอนิค 2 โมเลกุล และวิตามินบี 5 ช่วยเติมเต็มความชุ่มชื้น ลดเลือนริ้วรอยแรกเริ่ม ให้ผิวดูอิ่มฟู เปล่งปลั่ง สุขภาพดี เหมาะกับผิวบอบบางแพ้ง่าย",
|
||||
"details": "• Active Ingredients: Pure Hyaluronic Acid, Vitamin B5 (Panthenol), Madecassoside\\n• คุณสมบัติ: คืนความยืดหยุ่น ปลอบประโลมผิวขาดน้ำ เสริมเกราะป้องกันผิว\\n• วิธีใช้: ทาบำรุงทั่วใบหน้าและลำคอเป็นประจำเช้า-เย็น ก่อนทามอยส์เจอไรเซอร์\\n• ปริมาณสุทธิ: 30 ml\\n• สูตร Paraben-free, Non-comedogenic",
|
||||
"images": [
|
||||
"https://images.unsplash.com/photo-1620916566398-39f1143ab7be?w=800"
|
||||
],
|
||||
"translations": {
|
||||
"th": {
|
||||
"name": "เซรั่มบำรุงผิวหน้าไฮยาลูรอนเข้มข้น B5 Hyaluronic Serum 30ml",
|
||||
"description": "เซรั่มเข้มข้นฟื้นบำรุงผิวล้ำลึก ผสานไฮยาลูรอนิคและวิตามินบี 5 ให้ผิวดูอิ่มฟู เปล่งปลั่ง อ่อนโยนต่อผิวแพ้ง่าย",
|
||||
"details": "• ส่วนผสมหลัก: Pure Hyaluron, Vitamin B5\\n• วิธีใช้: ทาทั่วใบหน้า เช้า-เย็น\\n• ขนาด: 30ml"
|
||||
},
|
||||
"en": {
|
||||
"name": "Hyalu B5 Pure Hyaluronic Acid Face Serum 30ml",
|
||||
"description": "Anti-aging ultra-hydrating pure hyaluronic acid serum with Vitamin B5. Replenishes skin moisture barrier and visibly plumps skin.",
|
||||
"details": "• Key Ingredients: Hyaluronic Acid, Vitamin B5, Madecassoside\\n• Usage: Apply 3-4 drops morning and evening to face and neck.\\n• Volume: 30ml"
|
||||
},
|
||||
"ja": {
|
||||
"name": "ヒアロ B5 ヒアルロン酸 美容液 30ml",
|
||||
"description": "2種の高純度ヒアルロン酸とビタミンB5配合。敏感肌にもうるおいとハリを与える濃縮エイジングケアセラム。",
|
||||
"details": "• 主成分: 純粋ヒアルロン酸, ビタミンB5\\n• 使用方法: 朝晩、化粧水の後にお使いください\\n• 容量: 30ml"
|
||||
},
|
||||
"zh": {
|
||||
"name": "理肤泉 B5 玻尿酸紧致修护精华液 30ml",
|
||||
"description": "蕴含高纯度双分子玻尿酸与维生素原B5,深层补水锁水,修护肌肤屏障,淡化细纹,重焕弹润光彩。",
|
||||
"details": "• 核心成分: 玻尿酸、维生素原B5、积雪草苷\\n• 用法: 早晚取3-4滴涂抹于面部及颈部\\n• 规格: 30ml"
|
||||
},
|
||||
"vi": {
|
||||
"name": "Serum phục hồi và cấp ẩm Hyalu B5 30ml",
|
||||
"description": "Tinh chất dưỡng ẩm chuyên sâu với Hyaluronic Acid và Vitamin B5 giúp phục hồi hàng rào bảo vệ da, cho làn da căng mọng đàn hồi.",
|
||||
"details": "• Thành phần: Hyaluronic Acid, Vitamin B5\\n• Dung tích: 30ml"
|
||||
},
|
||||
"ko": {
|
||||
"name": "히알루 B5 퓨어 히알루론산 세럼 30ml",
|
||||
"description": "고순도 히알루론산과 비타민 B5가 피부 탄력과 수분 장벽을 집중 케어하여 촉촉하고 탄탄한 피부로 가꿔줍니다.",
|
||||
"details": "• 주요성분: 히알루론산, 비타민 B5\\n• 용량: 30ml"
|
||||
},
|
||||
"lo": {
|
||||
"name": "ເຊຣັ່ມບຳລຸງຜິວໜ້າ ໄຮຢາລູຣອນເຂັ້ມຂຸ້ນ B5 30ml",
|
||||
"description": "ເຊຣັ່ມເຂັ້ມຂຸ້ນຟື້ນຟູຜິວຢ່າງລ້ຳລຶກ ຜະສານໄຮຢາລູຣອນ ແລະ ວິຕາມິນ B5 ໃຫ້ຜິວຊຸ່ມຊື່ນອີ່ມຟູ.",
|
||||
"details": "• ສ່ວນປະສົມຫຼັກ: Hyaluron, Vitamin B5\\n• ຂະໜາດ: 30ml"
|
||||
},
|
||||
"it": {
|
||||
"name": "Siero Viso Idratante Antirughe Hyalu B5 30ml",
|
||||
"description": "Siero concentrato riparatore e rimpolpante all'Acido Ialuronico puro e Vitamina B5 per pelle disidratata e sensibile.",
|
||||
"details": "• Ingredienti: Acido Ialuronico, Vitamina B5\\n• Volume: 30ml"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "คุชชั่นผิวโกลว์เนื้อบางเบา Dewy Radiant Cushion SPF50+ PA++++",
|
||||
"categoryName": "Face Makeup & Cushion",
|
||||
"brandName": "Jung Saem Mool",
|
||||
"options": [
|
||||
{
|
||||
"name": "เฉดสี",
|
||||
"values": ["#19 Fair-Light", "#21 Light", "#23 Medium"]
|
||||
}
|
||||
],
|
||||
"variants": [
|
||||
{
|
||||
"option1": "#19 Fair-Light",
|
||||
"price": 1350,
|
||||
"stock": 45,
|
||||
"sku": "JSM-CUSH-19",
|
||||
"barcode": "8858340020014"
|
||||
},
|
||||
{
|
||||
"option1": "#21 Light",
|
||||
"price": 1350,
|
||||
"stock": 80,
|
||||
"sku": "JSM-CUSH-21",
|
||||
"barcode": "8858340020021"
|
||||
},
|
||||
{
|
||||
"option1": "#23 Medium",
|
||||
"price": 1350,
|
||||
"stock": 60,
|
||||
"sku": "JSM-CUSH-23",
|
||||
"barcode": "8858340020038"
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
"https://images.unsplash.com/photo-1522337360788-8b13dee7a37e?w=800"
|
||||
],
|
||||
"translations": {
|
||||
"th": {
|
||||
"name": "คุชชั่นผิวโกลว์เนื้อบางเบา Dewy Radiant Cushion SPF50+ PA++++",
|
||||
"description": "คุชชั่นเนื้อบางเบา ปกปิดเรียบเนียน ฟินิชผิวโกลว์สุขภาพดี ติดทนตลอดวัน",
|
||||
"details": "• กันแดด SPF50+ PA++++ พร้อมตลับจริงและรีฟิล 14g x 2"
|
||||
},
|
||||
"en": {
|
||||
"name": "Dewy Radiant Glow Cushion Foundation SPF50+ PA++++",
|
||||
"description": "Long-lasting weightless cushion foundation delivering a luminous, natural glow with buildable coverage.",
|
||||
"details": "• Sun Protection: SPF50+ PA++++\\n• Includes: Compact 14g + Refill 14g"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
[คำสั่ง]:
|
||||
กรุณาสร้างรายการสินค้ากลุ่ม Beauty & Cosmetics ตามข้อกำหนดด้านบน จำนวน 8 รายการ โดยครอบคลุมทั้ง Serum, Sunscreen, Cushion, Matte Lipstick, Cleanser, Toner จากแบรนด์ดังในสไตล์ EVEANDBOY / Beautrium ส่งผลลัพธ์เป็น Valid JSON Array เท่านั้น`
|
||||
|
||||
const FASHION_PROMPT = `คุณคือ Senior Fashion Merchandiser และ Apparel Catalog Specialist เชี่ยวชาญการจัดทำฐานข้อมูลสินค้าสำหรับแบรนด์เสื้อผ้าและแฟชั่นรีเทลชั้นนำ เช่น Jaspal, CPS CHAPS, CC Double O, Lyn Around, Zara, Gentlewoman
|
||||
|
||||
[ภารกิจของคุณ]:
|
||||
สร้างข้อมูลสินค้าแฟชั่นและเครื่องแต่งกายสำหรับนำเข้าสู่ระบบ E-commerce ในรูปแบบ **Valid JSON Array** ตาม Schema ของระบบอย่างเคร่งครัด
|
||||
|
||||
[กฎและข้อกำหนดทางเทคนิค]:
|
||||
1. ผลลัพธ์ต้องเป็น Valid JSON Array ล้วนๆ เริ่มต้นด้วย [ และจบด้วย ] เท่านั้น (ห้ามมีคำเกริ่นนำหรือคำลงท้าย)
|
||||
2. ฟิลด์ตัวเลข (price, stock) ต้องเป็น Number เท่านั้น ห้ามใส่เครื่องหมายคำพูด (ห้ามเป็น String)
|
||||
3. หมวดหมู่สินค้า (categoryName) ให้ใช้กลุ่มคำ เช่น:
|
||||
- "Tops & Shirts"
|
||||
- "Dresses & Jumpsuits"
|
||||
- "Trousers & Denim"
|
||||
- "Outerwear & Blazers"
|
||||
- "Bags & Leather Goods"
|
||||
- "Accessories & Belts"
|
||||
4. แบรนด์ (brandName): ใส่ชื่อแบรนด์แฟชั่นชั้นนำ เช่น "Jaspal", "CPS CHAPS", "CC Double O", "Lyn Around", "Misty Mynx", "Royal Ivy Regatta", "Gentlewoman"
|
||||
5. รูปภาพ (images): ใส่ Array ของ URL รูปภาพจาก Unsplash เกี่ยวกับ Fashion, Apparel, Model, Handbag, Outfit เช่น:
|
||||
- "https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=800"
|
||||
- "https://images.unsplash.com/photo-1596755094514-f87e34085b2c?w=800"
|
||||
- "https://images.unsplash.com/photo-1551028719-00167b16eac5?w=800"
|
||||
- "https://images.unsplash.com/photo-1548036328-c9fa89d128fa?w=800"
|
||||
- "https://images.unsplash.com/photo-1576995853123-5a10305d93c0?w=800"
|
||||
6. การเขียน Copywriting:
|
||||
- "description": ซิลูเอท (Silhouette), คอนเซปต์การดีไซน์, โอกาสในการสวมใส่ (Workwear, Casual, Evening), ลุคที่ได้
|
||||
- "details": เนื้อผ้า (Fabric composition เช่น 100% Cotton, Linen blend, Polyester Satin), คัตติ้ง, ซับใน, วิธีการดูแลรักษา (ซักมือ, ห้ามฟอกขาว, รีดไฟอ่อน), ตารางเทียบขนาด (Sizing guide)
|
||||
7. การรองรับหลายภาษา (Multilingual):
|
||||
ระบบรองรับครบ 8 ภาษาตาม Language Code สากล:
|
||||
- "th": ภาษาไทย (ภาษาหลัก)
|
||||
- "en": English (สากล)
|
||||
- "ja": 日本語 (ญี่ปุ่น)
|
||||
- "zh": 简体中文 (จีนตัวย่อ)
|
||||
- "vi": Tiếng Việt (เวียดนาม)
|
||||
- "ko": 한국어 (เกาหลี)
|
||||
- "lo": ພາສາລາວ (ลาว)
|
||||
- "it": Italiano (อิตาลี)
|
||||
ในฟิลด์ "translations" ให้สร้าง Object สำหรับแต่ละรหัสภาษาที่มี "name", "description", "details" แปลอย่างเป็นธรรมชาติ ตรงตามศัพท์แฟชั่น ดีไซน์ และการดูแลรักษาผ้า
|
||||
8. โครงสร้างประเภทสินค้า:
|
||||
- สินค้ามีขนาด / ไซส์ (Variable): เสื้อ, เดรส, กางเกง ต้องมี "options": [{"name": "ขนาด", "values": ["S", "M", "L"]}] และ "variants" ที่มี option1 ตรงตาม values ทุกประการ
|
||||
- สินค้าชิ้นเดียว (Simple): กระเป๋าโท้ท, เข็มขัดหนัง, ผ้าพันคอ (ใส่ price, stock, sku, barcode ที่ระดับบนสุด)
|
||||
|
||||
[ตัวอย่างรูปแบบ JSON ที่ต้องการ]:
|
||||
[
|
||||
{
|
||||
"name": "เดรสสั้นผ้าซาตินคอวีทรงเข้ารูป Satin V-Neck Mini Dress",
|
||||
"categoryName": "Dresses & Jumpsuits",
|
||||
"brandName": "Jaspal",
|
||||
"description": "มินิเดรสผ้าซาตินเนื้อเงาพรีเมียม โดดเด่นด้วยดีเทลคอวีทรงป้ายและตีเกล็ดช่วงเอว ช่วยเสริมสรีระให้ดูเพรียวระหง เหมาะสำหรับใส่ทำงานหรือแฮงเอาท์ในงานปาร์ตี้ช่วงค่ำ",
|
||||
"details": "• เนื้อผ้า: 95% Polyester, 5% Spandex (ซาตินทอละเอียด ทิ้งตัวสวย)\\n• ซับใน: มีซับในเต็มตัว ผิวสัมผัสนุ่มลื่น ไม่ระคายเคือง\\n• การเปิด-ปิด: ซิปซ่อนด้านหลัง รูดลื่นเรียบเนียน\\n• การดูแลรักษา: ควรซักแห้งหรือซักมือด้วยน้ำเย็น รีดด้านในด้วยไฟอ่อน\\n• นางแบบสูง 175 ซม. สวมใส่ไซส์ S",
|
||||
"images": [
|
||||
"https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=800"
|
||||
],
|
||||
"options": [
|
||||
{
|
||||
"name": "ขนาด",
|
||||
"values": ["S", "M", "L"]
|
||||
}
|
||||
],
|
||||
"variants": [
|
||||
{
|
||||
"option1": "S",
|
||||
"price": 2490,
|
||||
"stock": 20,
|
||||
"sku": "JSP-DRS-01-S",
|
||||
"barcode": "8857410010012"
|
||||
},
|
||||
{
|
||||
"option1": "M",
|
||||
"price": 2490,
|
||||
"stock": 35,
|
||||
"sku": "JSP-DRS-01-M",
|
||||
"barcode": "8857410010029"
|
||||
},
|
||||
{
|
||||
"option1": "L",
|
||||
"price": 2490,
|
||||
"stock": 15,
|
||||
"sku": "JSP-DRS-01-L",
|
||||
"barcode": "8857410010036"
|
||||
}
|
||||
],
|
||||
"translations": {
|
||||
"th": {
|
||||
"name": "เดรสสั้นผ้าซาตินคอวีทรงเข้ารูป Satin V-Neck Mini Dress",
|
||||
"description": "มินิเดรสผ้าซาตินเงางามพรีเมียม ทรงสวยช่วยเสริมสรีระ เหมาะสำหรับออกงานหรือวันพิเศษ",
|
||||
"details": "• ผ้า: 95% Polyester, 5% Spandex\\n• มีซับในเต็มตัว พร้อมซิปซ่อนด้านหลัง"
|
||||
},
|
||||
"en": {
|
||||
"name": "Satin V-Neck Fitted Mini Dress",
|
||||
"description": "Lustrous premium satin mini dress with flattering draped V-neckline and tailored waistline for elevated daytime or evening look.",
|
||||
"details": "• Material: 95% Polyester, 5% Spandex\\n• Fully lined with concealed back zipper"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
[คำสั่ง]:
|
||||
กรุณาสร้างรายการสินค้ากลุ่ม Fashion & Apparel ตามข้อกำหนดด้านบน จำนวน 8 รายการ โดยผสมผสานระหว่าง Shirts, Trousers, Blazers, Dresses, Handbags จากแบรนด์ดังในสไตล์ Jaspal / CPS CHAPS ส่งผลลัพธ์เป็น Valid JSON Array เท่านั้น`
|
||||
|
||||
const MOTO_PROMPT = `คุณคือ Senior Motorcycle Parts Specialist และ Aftermarket Catalog Merchandiser เชี่ยวชาญการจัดทำฐานข้อมูลอะไหล่แต่งมอเตอร์ไซค์สมรรถนะสูง เช่น RCB (Racing Boy), Brembo, Öhlins, YSS Suspension, Akrapovič, Yoshimura
|
||||
|
||||
[ภารกิจของคุณ]:
|
||||
สร้างข้อมูลสินค้าอะไหล่แต่งและอุปกรณ์มอเตอร์ไซค์สำหรับนำเข้าสู่ระบบ E-commerce ในรูปแบบ **Valid JSON Array** ตาม Schema ของระบบอย่างเคร่งครัด
|
||||
|
||||
[กฎและข้อกำหนดทางเทคนิค]:
|
||||
1. ผลลัพธ์ต้องเป็น Valid JSON Array ล้วนๆ เริ่มต้นด้วย [ และจบด้วย ] เท่านั้น (ห้ามมีคำเกริ่นนำหรือคำลงท้าย)
|
||||
2. ฟิลด์ตัวเลข (price, stock) ต้องเป็น Number เท่านั้น ห้ามใส่เครื่องหมายคำพูด (ห้ามเป็น String)
|
||||
3. หมวดหมู่สินค้า (categoryName) ให้ใช้กลุ่มคำ เช่น:
|
||||
- "Brake Systems & Calipers"
|
||||
- "Suspension & Shocks"
|
||||
- "Master Cylinders & Levers"
|
||||
- "Exhaust & Headers"
|
||||
- "Alloy Wheels & Footrests"
|
||||
- "Engine & Drivetrain Performance"
|
||||
4. แบรนด์ (brandName): ใส่ชื่อแบรนด์อะไหล่แต่งชั้นนำ เช่น "RCB", "Brembo", "Öhlins", "YSS Suspension", "Akrapovič", "Yoshimura", "GaleSpeed"
|
||||
5. รูปภาพ (images): ใส่ Array ของ URL รูปภาพจาก Unsplash เกี่ยวกับ Motorcycle Parts, Mechanic, Motorbike, Caliper เช่น:
|
||||
- "https://images.unsplash.com/photo-1558981403-c5f9899a28bc?w=800"
|
||||
- "https://images.unsplash.com/photo-1568772585407-9361f9bf3a87?w=800"
|
||||
- "https://images.unsplash.com/photo-1599819811279-d5ad9cccf838?w=800"
|
||||
- "https://images.unsplash.com/photo-1609630875171-b1321377ee65?w=800"
|
||||
6. การเขียน Copywriting:
|
||||
- "description": คุณสมบัติการขับขี่ การระบายความร้อน การลดระยะเบรก สมรรถนะในสนามแข่งและการใช้งานบนท้องถนน รุ่นรถที่รองรับ (Compatible models เช่น Forza 350, XMAX 300, Wave 125i, CBR650R)
|
||||
- "details": วัสดุ (เช่น Billet Aluminum 6061-T6 CNC, Hard Anodized finish), ลูกสูบเบรก (Piston spec), การปรับพรีโหลด/รีบาวด์ (Preload & Rebound damping), มาตรฐาน มอก. หรือ Racing Certified
|
||||
7. การรองรับหลายภาษา (Multilingual):
|
||||
ระบบรองรับครบ 8 ภาษาตาม Language Code สากล:
|
||||
- "th": ภาษาไทย (ภาษาหลัก)
|
||||
- "en": English (สากล)
|
||||
- "ja": 日本語 (ญี่ปุ่น)
|
||||
- "zh": 简体中文 (จีนตัวย่อ)
|
||||
- "vi": Tiếng Việt (เวียดนาม)
|
||||
- "ko": 한국어 (เกาหลี)
|
||||
- "lo": ພາສາລາວ (ลาว)
|
||||
- "it": Italiano (อิตาลี)
|
||||
ในฟิลด์ "translations" ให้สร้าง Object สำหรับแต่ละรหัสภาษาที่มี "name", "description", "details" แปลอย่างเป็นธรรมชาติ ตรงตามศัพท์เทคนิควิศวกรรมยานยนต์และอะไหล่แต่ง
|
||||
8. โครงสร้างประเภทสินค้า:
|
||||
- สินค้ามีสีอะโนไดซ์ / ความยาว (Variable): ปั๊มเบรกบน, โช้คอัพ ต้องมี "options": [{"name": "สีอะโนไดซ์", "values": ["Gold", "Red", "Black"]}] และ "variants" ที่มี option1 ตรงตาม values ทุกประการ
|
||||
- สินค้าชิ้นเดียว (Simple): จานดิสก์เบรกแต่ง, สายเบรกถักหัวสแตนเลส (ใส่ price, stock, sku, barcode ที่ระดับบนสุด)
|
||||
|
||||
[ตัวอย่างรูปแบบ JSON ที่ต้องการ]:
|
||||
[
|
||||
{
|
||||
"name": "ชุดปั๊มเบรกบนเรเดียลมาสเตอร์ไซลินเดอร์ Radial Master Cylinder S1 14mm",
|
||||
"categoryName": "Master Cylinders & Levers",
|
||||
"brandName": "RCB",
|
||||
"description": "ปั๊มบนเรเดียลเกรดพรีเมียมจาก RCB รุ่น S1 ขนาดลูกสูบ 14 มม. ผลิตด้วยกระบวนการขึ้นรูป Forged Alloy แข็งแกร่งแต่น้ำหนักเบา ให้แรงกดเบรกที่นุ่มนวล แม่นยำ ฟีลลิ่งเบรกกระชับ รองรับรถสปอร์ตและบิ๊กสกู๊ตเตอร์ทุกรุ่น",
|
||||
"details": "• ลูกสูบ: Forged Alloy 14mm Piston\\n• วัสดุบอดี้: อลูมิเนียม Forged CNC ชุบผิว Hard Anodized ป้องกันสนิมและรอยขีดข่วน\\n• ก้านเบรก: ปรับระยะได้ 6 ระดับ พร้อมร่องระบายลม Aerodynamic ป้องกันลมพัดก้านเบรกดีด\\n• กระปุกน้ำมัน: กระปุกควัน Smokey Tank พร้อมขายึดอลูมิเนียมแต่ง\\n• รุ่นรถที่รองรับ: Universal (แฮนด์บาร์ 22mm เช่น XMAX 300, Forza 350, R15, MT-15)",
|
||||
"images": [
|
||||
"https://images.unsplash.com/photo-1558981403-c5f9899a28bc?w=800"
|
||||
],
|
||||
"options": [
|
||||
{
|
||||
"name": "สีอะโนไดซ์",
|
||||
"values": ["Black", "Gold", "Red"]
|
||||
}
|
||||
],
|
||||
"variants": [
|
||||
{
|
||||
"option1": "Black",
|
||||
"price": 3250,
|
||||
"stock": 30,
|
||||
"sku": "RCB-S1-14MM-BLK",
|
||||
"barcode": "8856230010013"
|
||||
},
|
||||
{
|
||||
"option1": "Gold",
|
||||
"price": 3250,
|
||||
"stock": 25,
|
||||
"sku": "RCB-S1-14MM-GLD",
|
||||
"barcode": "8856230010020"
|
||||
},
|
||||
{
|
||||
"option1": "Red",
|
||||
"price": 3250,
|
||||
"stock": 18,
|
||||
"sku": "RCB-S1-14MM-RED",
|
||||
"barcode": "8856230010037"
|
||||
}
|
||||
],
|
||||
"translations": {
|
||||
"th": {
|
||||
"name": "ชุดปั๊มเบรกบนเรเดียลมาสเตอร์ไซลินเดอร์ Radial Master Cylinder S1 14mm",
|
||||
"description": "ปั๊มบนเรเดียล Forged Alloy 14mm ปรับระยะได้ 6 ระดับ แรงเบรกนุ่มนวล แม่นยำ ทนทานสูง",
|
||||
"details": "• ลูกสูบ 14mm Forged CNC Anodized\\n• รองรับแฮนด์ 22mm สากล"
|
||||
},
|
||||
"en": {
|
||||
"name": "RCB S1 14mm Radial Master Cylinder Brake Pump",
|
||||
"description": "High-performance forged alloy radial master cylinder engineered for superior braking feel, precise hydraulic feedback and race-grade durability.",
|
||||
"details": "• Piston Size: 14mm Forged Alloy\\n• Finish: Hard Anodized Coating\\n• Fitment: Universal 22mm Handlebars"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
[คำสั่ง]:
|
||||
กรุณาสร้างรายการสินค้ากลุ่ม Motorcycle Parts & Accessories ตามข้อกำหนดด้านบน จำนวน 8 รายการ โดยครอบคลุมทั้ง Master Cylinder, Shock Absorber, Brake Caliper, Exhaust, Alloy Wheel จากแบรนด์ดังในสไตล์ RCB / Brembo / Ohlins ส่งผลลัพธ์เป็น Valid JSON Array เท่านั้น`
|
||||
|
||||
interface TabItem {
|
||||
id: string
|
||||
label: string
|
||||
shortLabel: string
|
||||
icon: any
|
||||
badge: string
|
||||
color: string
|
||||
demoDomain?: string
|
||||
brands: string
|
||||
content: string
|
||||
}
|
||||
|
||||
const TABS: TabItem[] = [
|
||||
{
|
||||
id: 'overview',
|
||||
label: 'คู่มือภาพรวม & Schema Rules',
|
||||
shortLabel: 'Overview',
|
||||
icon: BookOpen,
|
||||
badge: 'Universal Guide',
|
||||
color: 'from-cyan-500 to-blue-500',
|
||||
brands: 'Universal E-commerce Schema',
|
||||
content: GUIDE_OVERVIEW_MARKDOWN
|
||||
},
|
||||
{
|
||||
id: 'wellness',
|
||||
label: '1. Wellness & Luxury',
|
||||
shortLabel: 'Wellness',
|
||||
icon: Flower2,
|
||||
badge: 'Panpuri / Jo Malone',
|
||||
color: 'from-amber-500 to-emerald-500',
|
||||
demoDomain: 'wellness.kittisak.com',
|
||||
brands: 'Panpuri, Jo Malone, Diptyque, Aesop, HARNN',
|
||||
content: WELLNESS_PROMPT
|
||||
},
|
||||
{
|
||||
id: 'beauty',
|
||||
label: '2. Beauty & Multi-Brand',
|
||||
shortLabel: 'Beauty',
|
||||
icon: Sparkle,
|
||||
badge: 'EVEANDBOY / Beautrium',
|
||||
color: 'from-pink-500 to-rose-500',
|
||||
demoDomain: 'beauty.kittisak.com',
|
||||
brands: 'La Roche-Posay, CeraVe, Laneige, Rom&nd, 4U2, Jung Saem Mool',
|
||||
content: BEAUTY_PROMPT
|
||||
},
|
||||
{
|
||||
id: 'fashion',
|
||||
label: '3. Fashion & Lifestyle',
|
||||
shortLabel: 'Fashion',
|
||||
icon: Shirt,
|
||||
badge: 'Jaspal / Zara / CPS',
|
||||
color: 'from-purple-500 to-indigo-500',
|
||||
demoDomain: 'fashion.kittisak.com',
|
||||
brands: 'Jaspal, CPS CHAPS, CC Double O, Lyn Around, Zara, Gentlewoman',
|
||||
content: FASHION_PROMPT
|
||||
},
|
||||
{
|
||||
id: 'moto',
|
||||
label: '4. Motorcycle Parts',
|
||||
shortLabel: 'Moto Parts',
|
||||
icon: Wrench,
|
||||
badge: 'RCB / Brembo / Ohlins',
|
||||
color: 'from-orange-500 to-red-500',
|
||||
demoDomain: 'moto.kittisak.com',
|
||||
brands: 'RCB (Racing Boy), Brembo, Öhlins, YSS Suspension, Akrapovič',
|
||||
content: MOTO_PROMPT
|
||||
}
|
||||
]
|
||||
|
||||
export default function ProductJsonGuideModal({ isOpen, onClose, onOpenImport }: ProductJsonGuideModalProps) {
|
||||
const [activeTab, setActiveTab] = useState<string>('overview')
|
||||
const [copied, setCopied] = useState<boolean>(false)
|
||||
|
||||
if (!isOpen) return null
|
||||
|
||||
const currentTabItem = TABS.find(t => t.id === activeTab) || TABS[0]
|
||||
|
||||
const handleCopy = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(currentTabItem.content)
|
||||
setCopied(true)
|
||||
setTimeout(() => setCopied(false), 2500)
|
||||
} catch (err) {
|
||||
console.error('Failed to copy text:', err)
|
||||
alert('ไม่สามารถ Copy ได้อัตโนมัติ กรุณาเลือกข้อความแล้วกด Ctrl+C')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 bg-night-950/85 backdrop-blur-md flex items-center justify-center p-3 sm:p-5 animate-fade-in">
|
||||
<div className="w-full max-w-5xl bg-night-900 border border-white/10 rounded-3xl shadow-2xl flex flex-col max-h-[92vh] overflow-hidden animate-zoom-in">
|
||||
|
||||
{/* Header */}
|
||||
<div className="p-5 sm:p-6 border-b border-white/10 bg-white/[0.02] flex items-center justify-between gap-4">
|
||||
<div className="flex items-center gap-3.5">
|
||||
<div className="w-11 h-11 rounded-2xl bg-gradient-to-br from-purple-500/20 via-pink-500/10 to-cyan-500/20 border border-purple-500/30 flex items-center justify-center text-purple-300 shadow-inner">
|
||||
<Sparkles className="w-6 h-6 text-purple-300 animate-pulse" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="text-lg sm:text-xl font-bold text-white tracking-wide">
|
||||
AI Product JSON Generator Guide
|
||||
</h3>
|
||||
<span className="px-2 py-0.5 rounded-full text-[10px] font-bold bg-purple-500/20 text-purple-300 border border-purple-500/30 uppercase tracking-wider">
|
||||
8-Languages
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-slate-400 mt-0.5">
|
||||
คู่มือและชุด Prompt สำหรับส่งให้ LLM (ChatGPT / Claude / Gemini) เพื่อสร้างข้อมูล JSON นำเข้าสินค้า
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={handleCopy}
|
||||
className={`flex items-center gap-1.5 px-4 py-2 rounded-xl text-xs font-bold transition-all cursor-pointer shadow-lg ${
|
||||
copied
|
||||
? 'bg-emerald-500 text-night-950 shadow-emerald-500/20'
|
||||
: 'bg-gradient-to-r from-purple-500 to-indigo-500 hover:from-purple-400 hover:to-indigo-400 text-white shadow-purple-500/20'
|
||||
}`}
|
||||
title="คัดลอกข้อความในแท็บปัจจุบัน"
|
||||
>
|
||||
{copied ? (
|
||||
<>
|
||||
<Check className="w-4 h-4" />
|
||||
<span>คัดลอกสำเร็จ!</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Copy className="w-4 h-4" />
|
||||
<span>Copy {currentTabItem.id === 'overview' ? 'Guide' : 'Prompt'}</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-2 rounded-xl text-slate-400 hover:text-white hover:bg-white/10 transition-colors cursor-pointer"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tab Navigation */}
|
||||
<div className="px-5 sm:px-6 pt-3 pb-2 border-b border-white/5 bg-night-950/40 flex items-center gap-2 overflow-x-auto scrollbar-hide">
|
||||
{TABS.map((tab) => {
|
||||
const Icon = tab.icon
|
||||
const isActive = activeTab === tab.id
|
||||
return (
|
||||
<button
|
||||
key={tab.id}
|
||||
onClick={() => {
|
||||
setActiveTab(tab.id)
|
||||
setCopied(false)
|
||||
}}
|
||||
className={`flex items-center gap-2 px-3.5 py-2 rounded-xl text-xs font-semibold whitespace-nowrap transition-all cursor-pointer ${
|
||||
isActive
|
||||
? 'bg-white/10 text-white border border-white/15 shadow-md shadow-black/20'
|
||||
: 'text-slate-400 hover:text-slate-200 hover:bg-white/5 border border-transparent'
|
||||
}`}
|
||||
>
|
||||
<Icon className={`w-3.5 h-3.5 ${isActive ? 'text-cyan-glow' : 'text-slate-500'}`} />
|
||||
<span>{tab.label}</span>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Tab Content Header Info */}
|
||||
<div className="px-5 sm:px-6 py-3 bg-white/[0.015] border-b border-white/5 flex flex-wrap items-center justify-between gap-3 text-xs">
|
||||
<div className="flex items-center gap-2 text-slate-300">
|
||||
<span className="font-semibold text-white">{currentTabItem.badge}:</span>
|
||||
<span className="text-slate-400 truncate max-w-md">{currentTabItem.brands}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
{currentTabItem.demoDomain && (
|
||||
<span className="inline-flex items-center gap-1 px-2.5 py-1 rounded-lg bg-cyan-glow/10 text-cyan-glow border border-cyan-glow/20 text-[11px] font-mono">
|
||||
<Globe2 className="w-3 h-3" />
|
||||
<span>Demo: {currentTabItem.demoDomain}</span>
|
||||
</span>
|
||||
)}
|
||||
<span className="text-[11px] text-slate-400 font-mono">
|
||||
{currentTabItem.content.length.toLocaleString()} characters
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content Body */}
|
||||
<div className="flex-1 overflow-y-auto p-5 sm:p-6 space-y-4 font-sans text-sm text-slate-200 leading-relaxed">
|
||||
{/* Quick Tip Alert */}
|
||||
{activeTab !== 'overview' ? (
|
||||
<div className="p-3.5 sm:p-4 rounded-2xl bg-gradient-to-r from-purple-500/10 via-indigo-500/5 to-cyan-500/10 border border-purple-500/20 text-xs text-purple-200 flex items-start gap-3 shadow-inner">
|
||||
<div className="p-1 rounded-lg bg-purple-500/20 text-purple-300 shrink-0 mt-0.5">
|
||||
<Sparkles className="w-3.5 h-3.5" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="font-semibold text-white">
|
||||
คำแนะนำการนำไปใช้งาน:
|
||||
</p>
|
||||
<p className="text-slate-300 text-[11px] leading-relaxed">
|
||||
กดปุ่ม <strong>"Copy Prompt"</strong> ด้านบน แล้วนำไปวางใน <strong>ChatGPT, Claude 3.5 หรือ Gemini</strong> โดยสามารถพิมพ์คำสั่งต่อท้ายได้ เช่น <em>"ขอสินค้าจำนวน 20 รายการสำหรับเปิดร้านใหม่"</em> จากนั้นคัดลอก JSON ที่ได้กลับมากด <strong>"Import JSON"</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-3.5 sm:p-4 rounded-2xl bg-cyan-glow/5 border border-cyan-glow/20 text-xs text-cyan-200 flex items-start gap-3 shadow-inner">
|
||||
<div className="p-1 rounded-lg bg-cyan-glow/20 text-cyan-glow shrink-0 mt-0.5">
|
||||
<Layers className="w-3.5 h-3.5" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="font-semibold text-white">
|
||||
ระบบรองรับ Multi-language ครบ 8 ภาษา:
|
||||
</p>
|
||||
<p className="text-slate-300 text-[11px] leading-relaxed">
|
||||
TH (ไทย), EN (สากล), JA (ญี่ปุ่น), ZH (จีนตัวย่อ), VI (เวียดนาม), KO (เกาหลี), LO (ลาว), IT (อิตาลี) พร้อมระบบแปลง Simple / Variable Variant ให้อัตโนมัติ
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Text Area / Code Display */}
|
||||
<div className="relative group">
|
||||
<pre className="p-4 sm:p-5 rounded-2xl bg-night-950 border border-white/10 font-mono text-xs text-slate-300 leading-relaxed whitespace-pre-wrap select-all overflow-x-auto shadow-inner max-h-[48vh] focus:outline-none">
|
||||
{currentTabItem.content}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="p-4 sm:p-5 border-t border-white/10 bg-white/[0.015] flex flex-col sm:flex-row items-center justify-between gap-3 text-xs">
|
||||
<div className="flex items-center gap-2 text-slate-400">
|
||||
<CheckCircle2 className="w-4 h-4 text-emerald-400 shrink-0" />
|
||||
<span>พร้อมใช้งานร่วมกับเมนูนำเข้าสินค้า <strong>Import JSON</strong></span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2.5 w-full sm:w-auto justify-end">
|
||||
{onOpenImport && (
|
||||
<button
|
||||
onClick={() => {
|
||||
onClose()
|
||||
onOpenImport()
|
||||
}}
|
||||
className="flex items-center gap-1.5 px-4 py-2 rounded-xl bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 text-xs font-bold transition-all cursor-pointer"
|
||||
>
|
||||
<Code2 className="w-4 h-4" />
|
||||
<span>เปิดหน้าต่าง Import JSON</span>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={handleCopy}
|
||||
className="flex items-center gap-1.5 px-4 py-2 rounded-xl bg-white/5 hover:bg-white/10 text-slate-300 hover:text-white border border-white/10 text-xs font-semibold cursor-pointer transition-colors"
|
||||
>
|
||||
<Copy className="w-3.5 h-3.5" />
|
||||
<span>Copy ข้อความ</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 rounded-xl bg-white/10 hover:bg-white/15 text-white text-xs font-semibold cursor-pointer transition-colors"
|
||||
>
|
||||
ปิดหน้าต่าง
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -15,11 +15,13 @@ import {
|
||||
LayoutTemplate,
|
||||
FileJson,
|
||||
Download,
|
||||
CheckCircle2
|
||||
CheckCircle2,
|
||||
Sparkles
|
||||
} from 'lucide-react'
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { API_BASE, getCategoryImage, formatPrice, type Category, type Product } from '@homaroma/types'
|
||||
import ProductJsonGuideModal from '../components/ProductJsonGuideModal'
|
||||
|
||||
|
||||
interface PaginationMeta {
|
||||
@@ -51,8 +53,9 @@ export default function ProductsPage() {
|
||||
const limit = validLimits.includes(limitParam) ? limitParam : 10
|
||||
const [meta, setMeta] = useState<PaginationMeta | null>(null)
|
||||
|
||||
// JSON Import State
|
||||
// JSON Import & Guide State
|
||||
const [isImportModalOpen, setIsImportModalOpen] = useState(false)
|
||||
const [isGuideModalOpen, setIsGuideModalOpen] = useState(false)
|
||||
const [importJsonText, setImportJsonText] = useState('')
|
||||
const [importLoading, setImportLoading] = useState(false)
|
||||
const [importError, setImportError] = useState<string | null>(null)
|
||||
@@ -462,6 +465,14 @@ export default function ProductsPage() {
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
className="flex items-center gap-2 px-4 py-2.5 rounded-xl bg-purple-500/10 hover:bg-purple-500/20 text-purple-300 hover:text-white border border-purple-500/20 hover:border-purple-500/40 font-semibold text-sm transition-all cursor-pointer shadow-sm group"
|
||||
onClick={() => setIsGuideModalOpen(true)}
|
||||
title="ดูคู่มือและ Prompt สำหรับให้ AI / LLM สร้าง JSON"
|
||||
>
|
||||
<Sparkles className="w-4 h-4 text-purple-400 group-hover:scale-110 transition-transform" />
|
||||
<span>JSON Guide</span>
|
||||
</button>
|
||||
<button
|
||||
className="flex items-center gap-2 px-4 py-2.5 rounded-xl bg-white/5 hover:bg-white/10 text-slate-300 hover:text-white border border-white/10 font-semibold text-sm transition-all cursor-pointer shadow-sm group"
|
||||
onClick={() => setIsImportModalOpen(true)}
|
||||
@@ -935,20 +946,31 @@ export default function ProductsPage() {
|
||||
</div>
|
||||
|
||||
{/* Actions Bar */}
|
||||
<div className="flex items-center justify-between gap-3 text-xs">
|
||||
<label className="flex items-center gap-2 px-3 py-1.5 rounded-xl bg-white/5 hover:bg-white/10 text-slate-300 border border-white/10 cursor-pointer transition-colors">
|
||||
<UploadCloud className="w-4 h-4 text-cyan-glow" />
|
||||
<span>อัปโหลดไฟล์ .json</span>
|
||||
<input type="file" accept=".json,application/json" onChange={handleFileUpload} className="hidden" />
|
||||
</label>
|
||||
<div className="flex flex-wrap items-center justify-between gap-3 text-xs">
|
||||
<div className="flex items-center gap-2">
|
||||
<label className="flex items-center gap-2 px-3 py-1.5 rounded-xl bg-white/5 hover:bg-white/10 text-slate-300 border border-white/10 cursor-pointer transition-colors">
|
||||
<UploadCloud className="w-4 h-4 text-cyan-glow" />
|
||||
<span>อัปโหลดไฟล์ .json</span>
|
||||
<input type="file" accept=".json,application/json" onChange={handleFileUpload} className="hidden" />
|
||||
</label>
|
||||
|
||||
<button
|
||||
onClick={handleDownloadSampleJson}
|
||||
className="flex items-center gap-2 px-3 py-1.5 rounded-xl bg-white/5 hover:bg-white/10 text-emerald-400 border border-emerald-500/20 hover:border-emerald-500/40 cursor-pointer transition-colors"
|
||||
title="ดาวน์โหลดโครงสร้าง JSON ตัวอย่างสำหรับเป็นแบบพิมพ์"
|
||||
>
|
||||
<Download className="w-4 h-4" />
|
||||
<span>ดาวน์โหลด Template JSON</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleDownloadSampleJson}
|
||||
className="flex items-center gap-2 px-3 py-1.5 rounded-xl bg-white/5 hover:bg-white/10 text-emerald-400 border border-emerald-500/20 hover:border-emerald-500/40 cursor-pointer transition-colors"
|
||||
title="ดาวน์โหลดโครงสร้าง JSON ตัวอย่างสำหรับเป็นแบบพิมพ์"
|
||||
onClick={() => setIsGuideModalOpen(true)}
|
||||
className="flex items-center gap-2 px-3 py-1.5 rounded-xl bg-purple-500/10 hover:bg-purple-500/20 text-purple-300 hover:text-white border border-purple-500/20 hover:border-purple-500/40 cursor-pointer transition-colors"
|
||||
title="เปิดดู Prompt สำหรับให้ AI / LLM สร้าง JSON"
|
||||
>
|
||||
<Download className="w-4 h-4" />
|
||||
<span>ดาวน์โหลด Template JSON</span>
|
||||
<Sparkles className="w-4 h-4 text-purple-400" />
|
||||
<span>JSON Guide (AI Prompt)</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1024,6 +1046,13 @@ export default function ProductsPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Product JSON Guide Modal */}
|
||||
<ProductJsonGuideModal
|
||||
isOpen={isGuideModalOpen}
|
||||
onClose={() => setIsGuideModalOpen(false)}
|
||||
onOpenImport={() => setIsImportModalOpen(true)}
|
||||
/>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user