@@ -0,0 +1,61 @@
< template >
< div class = "app-container product-page" >
< h2 > Shopee 商品 < / h2 >
< p class = "hint" > 输入 Shopee 商品 ID , 从货憨憨同步并保存商品信息 。 < / p >
< div class = "toolbar" >
< el-input v-model = "searchId" placeholder="Shopee ID" clearable maxlength="128" aria-label="Shopee ID" @keyup.enter="search" / >
< el-button type = "primary" :loading = "syncing" @click ="sync" > 查询并同步 < / el -button >
< el-button :loading = "loading" @click ="load" > 刷新已保存商品 < / el -button >
< / div >
< el-alert v-if = "error" :title="error" type="error" show-icon :closable="false" / >
< el-table v-loading = "loading" :data="rows" border row-key="id" :empty-text="error ? '数据暂不可用' : '暂无已保存商品'" >
< el -table -column prop = "shopeeId" label = "Shopee ID" min -width = " 150 " / >
< el-table-column prop = "itemName" label = "商品标题" min -width = " 240 " show -overflow -tooltip / >
< el-table-column prop = "shopName" label = "店铺" min -width = " 140 " show -overflow -tooltip / >
< el-table-column prop = "status" label = "状态" width = "120" / >
< el-table-column label = "更新时间" min -width = " 180 " > < template # default = "{ row }" > { { formatDate ( row . updatedAt ) } } < / template > < / el-table-column >
< el-table-column label = "操作" width = "110" fixed = "right" > < template # default = "{ row }" > < el-button size = "small" @click ="showDetail(row)" > 详情 < / el -button > < / template > < / el-table-column >
< / el-table >
< el-dialog v-model = "detailOpen" title="商品详情" width="min(760px, 94vw)" top="5vh" >
< template v-if = "selected" >
< el -descriptions :column = "2" border >
< el-descriptions-item label = "Shopee ID" > { { selected . shopeeId } } < / el-descriptions-item >
< el-descriptions-item label = "状态" > { { selected . status || '—' } } < / el-descriptions-item >
< el-descriptions-item label = "店铺" > { { selected . shopName || '—' } } < / el-descriptions-item >
< el-descriptions-item label = "标题" :span = "2" > { { selected . itemName || '—' } } < / el-descriptions-item >
< el-descriptions-item label = "更新时间" :span = "2" > { { formatDate ( selected . updatedAt ) } } < / el-descriptions-item >
< / el-descriptions >
< h4 > 原始 JSON < / h4 >
< pre class = "json" > { { prettyPayload ( selected . payload ) } } < / pre >
< / template >
< / el-dialog >
< / div >
< / template >
< script >
import { listProducts , syncProduct } from '@/api/admin/shopee-product'
import { ElMessage } from 'element-plus'
export default {
name : 'ShopeeProductManagement' ,
data : ( ) => ( { rows : [ ] , searchId : '' , loading : false , syncing : false , error : '' , detailOpen : false , selected : null } ) ,
mounted ( ) { this . load ( ) } ,
methods : {
formatDate ( value ) { if ( ! value ) return '—' ; const d = new Date ( value ) ; return Number . isNaN ( d . getTime ( ) ) ? '—' : d . toLocaleString ( 'zh-CN' , { hour12 : false } ) } ,
prettyPayload ( value ) { try { return JSON . stringify ( JSON . parse ( value ) , null , 2 ) } catch ( _ ) { return value || '—' } } ,
async load ( ) { this . loading = true ; this . error = '' ; try { const r = await listProducts ( this . searchId . trim ( ) ) ; this . rows = r . data || [ ] } catch ( _ ) { this . error = '读取商品失败,请点击刷新重试' } finally { this . loading = false } } ,
async sync ( ) { const id = this . searchId . trim ( ) ; if ( ! id ) { ElMessage . warning ( '请输入 Shopee ID' ) ; return } ; this . syncing = true ; this . error = '' ; try { const r = await syncProduct ( id ) ; ElMessage . success ( '商品同步成功' ) ; await this . load ( ) ; const found = this . rows . find ( row => row . shopeeId === id ) ; if ( found ) this . showDetail ( found ) ; else if ( r . data ) this . selected = r . data } catch ( _ ) { this . error = '商品查询失败,请检查 API Key、登录状态和 Shopee ID' } finally { this . syncing = false } } ,
showDetail ( row ) { this . selected = row ; this . detailOpen = true }
}
}
< / script >
< style scoped >
. product - page { padding : 24 px ; }
. hint { color : var ( -- el - text - color - regular ) ; line - height : 1.6 ; }
. toolbar { display : flex ; flex - wrap : wrap ; gap : 12 px ; margin : 20 px 0 ; }
. toolbar . el - input { width : 300 px ; max - width : 100 % ; }
. toolbar . el - button { margin - left : 0 ; }
. el - alert { margin - bottom : 12 px ; }
. json { max - height : 360 px ; overflow : auto ; padding : 16 px ; background : var ( -- el - fill - color - light ) ; border - radius : 4 px ; white - space : pre - wrap ; word - break : break - word ; }
@ media ( max - width : 600 px ) { . product - page { padding : 12 px ; } . toolbar . el - input { width : 100 % ; } }
< / style >