feat:上书记录对接shop/list和product/shop-detail接口,平台+店铺联动,分页
This commit is contained in:
parent
5a4968881a
commit
d64c9aad01
@ -5,30 +5,19 @@
|
|||||||
<view class="filter-card">
|
<view class="filter-card">
|
||||||
<view class="filter-row">
|
<view class="filter-row">
|
||||||
<view class="filter-item">
|
<view class="filter-item">
|
||||||
<text class="filter-label">账号</text>
|
<text class="filter-label">平台</text>
|
||||||
<picker class="filter-picker" @change="handleAccountChange" :value="accountIndex" :range="accountList">
|
<picker class="filter-picker" @change="handlePlatformChange" :value="platformIndex" :range="platformList">
|
||||||
<view class="picker-value">
|
<view class="picker-value">
|
||||||
<text class="picker-text">{{ accountList[accountIndex] }}</text>
|
<text class="picker-text">{{ platformList[platformIndex] }}</text>
|
||||||
<text class="picker-arrow">▼</text>
|
<text class="picker-arrow">▼</text>
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
</picker>
|
||||||
</view>
|
</view>
|
||||||
<view class="filter-item">
|
<view class="filter-item">
|
||||||
<text class="filter-label">店铺</text>
|
<text class="filter-label">店铺</text>
|
||||||
<picker class="filter-picker" @change="handleShopChange" :value="shopIndex" :range="shopList">
|
<picker class="filter-picker" @change="handleShopChange" :value="shopIndex" :range="shopNames">
|
||||||
<view class="picker-value">
|
<view class="picker-value">
|
||||||
<text class="picker-text">{{ shopList[shopIndex] }}</text>
|
<text class="picker-text">{{ shopNames[shopIndex] }}</text>
|
||||||
<text class="picker-arrow">▼</text>
|
|
||||||
</view>
|
|
||||||
</picker>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="filter-row">
|
|
||||||
<view class="filter-item full-width">
|
|
||||||
<text class="filter-label">日期</text>
|
|
||||||
<picker class="filter-picker" mode="date" @change="handleDateChange" :value="selectedDate">
|
|
||||||
<view class="picker-value">
|
|
||||||
<text class="picker-text">{{ selectedDate }}</text>
|
|
||||||
<text class="picker-arrow">▼</text>
|
<text class="picker-arrow">▼</text>
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
</picker>
|
||||||
@ -40,210 +29,300 @@
|
|||||||
<!-- 统计信息 -->
|
<!-- 统计信息 -->
|
||||||
<view class="stats-section">
|
<view class="stats-section">
|
||||||
<view class="stats-card">
|
<view class="stats-card">
|
||||||
<text class="stats-icon">📊</text>
|
<view class="stats-item">
|
||||||
<text class="stats-label">总记录数</text>
|
<text class="stats-num success">{{ stats.successCount }}</text>
|
||||||
<text class="stats-value">{{ recordList.length }} 条</text>
|
<text class="stats-label">已发送</text>
|
||||||
|
</view>
|
||||||
|
<view class="stats-divider"></view>
|
||||||
|
<view class="stats-item">
|
||||||
|
<text class="stats-num pending">{{ stats.notSentCount }}</text>
|
||||||
|
<text class="stats-label">未发送</text>
|
||||||
|
</view>
|
||||||
|
<view class="stats-divider"></view>
|
||||||
|
<view class="stats-item">
|
||||||
|
<text class="stats-num failed">{{ stats.failedCount }}</text>
|
||||||
|
<text class="stats-label">失败</text>
|
||||||
|
</view>
|
||||||
|
<view class="stats-divider"></view>
|
||||||
|
<view class="stats-item">
|
||||||
|
<text class="stats-num total">{{ stats.total }}</text>
|
||||||
|
<text class="stats-label">总计</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 记录列表 -->
|
<!-- 记录列表 -->
|
||||||
<view class="record-list">
|
<scroll-view class="record-scroll" scroll-y :refresher-enabled="true" :refresher-triggered="isRefreshing" @refresherrefresh="onRefresh" @scrolltolower="loadMore">
|
||||||
<view class="record-item" v-for="(item, index) in recordList" :key="index">
|
<view class="record-list">
|
||||||
<view class="record-main">
|
<view class="record-item" v-for="(item, index) in recordList" :key="index">
|
||||||
<!-- 图片 -->
|
<view class="record-main">
|
||||||
<view class="record-image" @click="previewImage(item.image)">
|
<!-- 图片 -->
|
||||||
<image class="book-image" :src="item.image" mode="aspectFill"></image>
|
<view class="record-image" @click="previewImage(item.live_image)">
|
||||||
<view class="image-overlay">
|
<image class="book-image" :src="getFirstImage(item.live_image)" mode="aspectFill"></image>
|
||||||
<text class="zoom-icon">🔍</text>
|
</view>
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<view class="record-info">
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="book-name">{{ item.name }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">ISBN:</text>
|
||||||
|
<text class="info-value">{{ item.barcode || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">波次:</text>
|
||||||
|
<text class="info-value">{{ item.wave_no || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">货位:</text>
|
||||||
|
<text class="info-value">{{ item.warehouse_name }}{{ item.location_code ? ' - ' + item.location_code : '' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">时间:</text>
|
||||||
|
<text class="info-value">{{ formatTime(item.created_at) }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 基本信息 -->
|
<!-- 价格和库存 -->
|
||||||
<view class="record-info">
|
<view class="record-detail">
|
||||||
<view class="info-row">
|
<view class="detail-row">
|
||||||
<text class="book-name">{{ item.name }}</text>
|
<view class="detail-item">
|
||||||
</view>
|
<text class="detail-label">定价</text>
|
||||||
<view class="info-row">
|
<text class="detail-value">¥{{ formatPrice(item.price) }}</text>
|
||||||
<text class="info-label">ISBN:</text>
|
</view>
|
||||||
<text class="info-value">{{ item.isbn }}</text>
|
<view class="detail-item">
|
||||||
</view>
|
<text class="detail-label">售价</text>
|
||||||
<view class="info-row">
|
<text class="detail-value price">¥{{ formatPrice(item.sale_price) }}</text>
|
||||||
<text class="info-label">品相:</text>
|
</view>
|
||||||
<text class="condition-badge" :class="getConditionClass(item.condition)">{{ item.condition }}</text>
|
<view class="detail-item">
|
||||||
</view>
|
<text class="detail-label">库存</text>
|
||||||
<view class="info-row">
|
<text class="detail-value">{{ item.quantity }}本</text>
|
||||||
<text class="info-label">上书时间:</text>
|
</view>
|
||||||
<text class="info-value">{{ item.uploadTime }}</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
<!-- 状态 -->
|
||||||
<!-- 价格和库存 -->
|
<view class="publish-status">
|
||||||
<view class="record-detail">
|
<view class="status-row">
|
||||||
<view class="detail-row">
|
<text class="status-tag" :class="getStatusClass(item.status_in_shop)">{{ item.msg || getStatusText(item.status_in_shop) }}</text>
|
||||||
<view class="detail-item">
|
|
||||||
<text class="detail-label">库存</text>
|
|
||||||
<text class="detail-value">{{ item.stock }}本</text>
|
|
||||||
</view>
|
|
||||||
<view class="detail-item">
|
|
||||||
<text class="detail-label">价格</text>
|
|
||||||
<text class="detail-value price">¥{{ item.price }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<!-- 发布状态 -->
|
|
||||||
<view class="publish-status">
|
|
||||||
<view class="status-row">
|
|
||||||
<view class="status-item" :class="{ published: item.pddPublished }">
|
|
||||||
<text class="status-icon">{{ item.pddPublished ? '✓' : '✗' }}</text>
|
|
||||||
<text class="status-text">拼多多:{{ item.pddPublished ? '已发布' : '未发布' }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="status-item" :class="{ published: item.kfzPublished }">
|
|
||||||
<text class="status-icon">{{ item.kfzPublished ? '✓' : '✗' }}</text>
|
|
||||||
<text class="status-text">孔夫子:{{ item.kfzPublished ? '已发布' : '未发布' }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="status-item" :class="{ published: item.xianyuPublished }">
|
|
||||||
<text class="status-icon">{{ item.xianyuPublished ? '✓' : '✗' }}</text>
|
|
||||||
<text class="status-text">闲鱼:{{ item.xianyuPublished ? '已发布' : '未发布' }}</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 空状态 -->
|
<!-- 加载更多 -->
|
||||||
<view class="empty-state" v-if="recordList.length === 0">
|
<view class="load-more" v-if="loadingMore">
|
||||||
<text class="empty-icon">📭</text>
|
<view class="loading-spinner"></view>
|
||||||
<text class="empty-text">暂无上书记录</text>
|
<text class="load-more-text">加载中...</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="load-more" v-if="!hasMore && recordList.length > 0">
|
||||||
|
<text class="no-more-text">— 已全部加载 —</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<view class="empty-state" v-if="recordList.length === 0 && !isLoading">
|
||||||
|
<text class="empty-icon">📭</text>
|
||||||
|
<text class="empty-text">暂无上书记录</text>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { getShopList, getShopDetail } from '@/utils/api.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// 筛选条件
|
// 平台筛选
|
||||||
accountIndex: 0,
|
platformIndex: 0,
|
||||||
accountList: ['全部账号', '账号A', '账号B', '账号C'],
|
platformList: ['全部平台', '拼多多', '孔夫子', '闲鱼'],
|
||||||
shopIndex: 0,
|
platformTypes: [0, 1, 2, 5],
|
||||||
shopList: ['全部店铺', '店铺1', '店铺2', '店铺3'],
|
|
||||||
selectedDate: this.getTodayDate(),
|
|
||||||
|
|
||||||
// 记录列表
|
// 店铺筛选
|
||||||
recordList: [
|
shopIndex: 0,
|
||||||
{
|
shopList: [],
|
||||||
image: 'https://picsum.photos/200/280?random=1',
|
shopNames: ['全部店铺'],
|
||||||
name: '红楼梦',
|
|
||||||
isbn: '9787020002207',
|
// 分页
|
||||||
condition: '全新',
|
page: 1,
|
||||||
uploadTime: '2024-01-15 14:30',
|
pageSize: 10,
|
||||||
stock: 5,
|
hasMore: true,
|
||||||
price: '45.00',
|
isLoading: false,
|
||||||
pddPublished: true,
|
loadingMore: false,
|
||||||
kfzPublished: true,
|
isRefreshing: false,
|
||||||
xianyuPublished: false
|
|
||||||
},
|
// 数据
|
||||||
{
|
recordList: [],
|
||||||
image: 'https://picsum.photos/200/280?random=2',
|
stats: { successCount: 0, notSentCount: 0, failedCount: 0, total: 0 }
|
||||||
name: '西游记',
|
|
||||||
isbn: '9787020002214',
|
|
||||||
condition: '九成新',
|
|
||||||
uploadTime: '2024-01-15 15:20',
|
|
||||||
stock: 3,
|
|
||||||
price: '38.00',
|
|
||||||
pddPublished: true,
|
|
||||||
kfzPublished: false,
|
|
||||||
xianyuPublished: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: 'https://picsum.photos/200/280?random=3',
|
|
||||||
name: '水浒传',
|
|
||||||
isbn: '9787020002221',
|
|
||||||
condition: '八成新',
|
|
||||||
uploadTime: '2024-01-15 16:45',
|
|
||||||
stock: 2,
|
|
||||||
price: '32.00',
|
|
||||||
pddPublished: false,
|
|
||||||
kfzPublished: true,
|
|
||||||
xianyuPublished: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: 'https://picsum.photos/200/280?random=4',
|
|
||||||
name: '三国演义',
|
|
||||||
isbn: '9787020002238',
|
|
||||||
condition: '全新',
|
|
||||||
uploadTime: '2024-01-15 17:10',
|
|
||||||
stock: 8,
|
|
||||||
price: '52.00',
|
|
||||||
pddPublished: true,
|
|
||||||
kfzPublished: true,
|
|
||||||
xianyuPublished: true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
uni.setNavigationBarTitle({
|
uni.setNavigationBarTitle({ title: '上书记录' })
|
||||||
title: '上书记录'
|
this.loadShopList()
|
||||||
})
|
this.fetchRecords()
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
// 获取今天日期
|
// 加载店铺列表
|
||||||
getTodayDate() {
|
async loadShopList() {
|
||||||
const today = new Date()
|
try {
|
||||||
const year = today.getFullYear()
|
const platformType = this.platformTypes[this.platformIndex]
|
||||||
const month = String(today.getMonth() + 1).padStart(2, '0')
|
const params = { pageNum: 1, pageSize: 100 }
|
||||||
const day = String(today.getDate()).padStart(2, '0')
|
if (platformType > 0) params.shop_type = String(platformType)
|
||||||
return `${year}-${month}-${day}`
|
const res = await getShopList(params)
|
||||||
|
this.shopList = res.list || []
|
||||||
|
this.updateShopNames()
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载店铺列表失败:', e)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 账号筛选变化
|
// 更新店铺名下拉列表
|
||||||
handleAccountChange(e) {
|
updateShopNames() {
|
||||||
this.accountIndex = e.detail.value
|
const names = ['全部店铺']
|
||||||
this.filterRecords()
|
this.shopList.forEach(function(s) {
|
||||||
|
names.push(s.shop_alias_name || s.shop_name || '未命名')
|
||||||
|
})
|
||||||
|
this.shopNames = names
|
||||||
|
if (this.shopIndex >= names.length) {
|
||||||
|
this.shopIndex = 0
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 店铺筛选变化
|
// 平台切换
|
||||||
|
handlePlatformChange(e) {
|
||||||
|
this.platformIndex = e.detail.value
|
||||||
|
this.shopIndex = 0
|
||||||
|
this.loadShopList()
|
||||||
|
this.resetAndFetch()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 店铺切换
|
||||||
handleShopChange(e) {
|
handleShopChange(e) {
|
||||||
this.shopIndex = e.detail.value
|
this.shopIndex = e.detail.value
|
||||||
this.filterRecords()
|
this.resetAndFetch()
|
||||||
},
|
},
|
||||||
|
|
||||||
// 日期筛选变化
|
// 重置分页并加载
|
||||||
handleDateChange(e) {
|
resetAndFetch() {
|
||||||
this.selectedDate = e.detail.value
|
this.page = 1
|
||||||
this.filterRecords()
|
this.hasMore = true
|
||||||
|
this.recordList = []
|
||||||
|
this.stats = { successCount: 0, notSentCount: 0, failedCount: 0, total: 0 }
|
||||||
|
this.fetchRecords()
|
||||||
},
|
},
|
||||||
|
|
||||||
// 筛选记录
|
// 获取当前选中的店铺ID
|
||||||
filterRecords() {
|
getSelectedShopId() {
|
||||||
// TODO: 根据筛选条件调用接口获取数据
|
if (this.shopIndex <= 0) return ''
|
||||||
uni.showToast({
|
const shop = this.shopList[this.shopIndex - 1]
|
||||||
title: '筛选条件已更新',
|
return shop ? shop.id : ''
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取品相样式类
|
// 获取上书记录
|
||||||
getConditionClass(condition) {
|
async fetchRecords() {
|
||||||
const classMap = {
|
if (this.isLoading || this.loadingMore) return
|
||||||
'全新': 'condition-new',
|
this.isLoading = true
|
||||||
'九成新': 'condition-good',
|
try {
|
||||||
'八成新': 'condition-fair',
|
const shopId = this.getSelectedShopId()
|
||||||
'七成新': 'condition-poor'
|
if (!shopId) {
|
||||||
|
this.isLoading = false
|
||||||
|
this.recordList = []
|
||||||
|
this.hasMore = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const params = {
|
||||||
|
page: this.page,
|
||||||
|
page_size: this.pageSize,
|
||||||
|
shop_id: shopId
|
||||||
|
}
|
||||||
|
const res = await getShopDetail(params)
|
||||||
|
const products = res.products || []
|
||||||
|
if (this.page === 1) {
|
||||||
|
this.recordList = products
|
||||||
|
} else {
|
||||||
|
this.recordList = this.recordList.concat(products)
|
||||||
|
}
|
||||||
|
this.hasMore = products.length >= this.pageSize
|
||||||
|
this.stats = {
|
||||||
|
successCount: res.success_count || 0,
|
||||||
|
notSentCount: res.not_sent_count || 0,
|
||||||
|
failedCount: res.failed_count || 0,
|
||||||
|
total: res.total || 0
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('获取上书记录失败:', e)
|
||||||
|
} finally {
|
||||||
|
this.isLoading = false
|
||||||
|
this.loadingMore = false
|
||||||
|
this.isRefreshing = false
|
||||||
}
|
}
|
||||||
return classMap[condition] || 'condition-default'
|
},
|
||||||
|
|
||||||
|
// 下拉刷新
|
||||||
|
onRefresh() {
|
||||||
|
this.isRefreshing = true
|
||||||
|
this.page = 1
|
||||||
|
this.hasMore = true
|
||||||
|
this.fetchRecords()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上拉加载更多
|
||||||
|
loadMore() {
|
||||||
|
if (this.loadingMore || !this.hasMore) return
|
||||||
|
this.loadingMore = true
|
||||||
|
this.page++
|
||||||
|
this.fetchRecords()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取第一张图片
|
||||||
|
getFirstImage(images) {
|
||||||
|
if (!images) return ''
|
||||||
|
if (typeof images === 'string') return images
|
||||||
|
return images[0] || ''
|
||||||
|
},
|
||||||
|
|
||||||
|
// 格式化价格(分→元)
|
||||||
|
formatPrice(price) {
|
||||||
|
if (!price && price !== 0) return '0.00'
|
||||||
|
return (parseFloat(price) / 100).toFixed(2)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 格式化时间(时间戳→日期)
|
||||||
|
formatTime(timestamp) {
|
||||||
|
if (!timestamp) return '-'
|
||||||
|
const date = new Date(parseInt(timestamp) * 1000)
|
||||||
|
const y = date.getFullYear()
|
||||||
|
const m = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
|
const d = String(date.getDate()).padStart(2, '0')
|
||||||
|
const h = String(date.getHours()).padStart(2, '0')
|
||||||
|
const mi = String(date.getMinutes()).padStart(2, '0')
|
||||||
|
return y + '-' + m + '-' + d + ' ' + h + ':' + mi
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取状态CSS类
|
||||||
|
getStatusClass(status) {
|
||||||
|
if (status === 1) return 'status-success'
|
||||||
|
if (status === 0) return 'status-pending'
|
||||||
|
return 'status-failed'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取状态文字
|
||||||
|
getStatusText(status) {
|
||||||
|
if (status === 1) return '已发布到店铺'
|
||||||
|
if (status === 0) return '未发送到店铺'
|
||||||
|
return '发布失败'
|
||||||
},
|
},
|
||||||
|
|
||||||
// 预览图片
|
// 预览图片
|
||||||
previewImage(imageUrl) {
|
previewImage(images) {
|
||||||
|
if (!images) return
|
||||||
|
const urls = typeof images === 'string' ? [images] : images
|
||||||
|
if (urls.length === 0) return
|
||||||
uni.previewImage({
|
uni.previewImage({
|
||||||
urls: [imageUrl],
|
urls: urls,
|
||||||
current: imageUrl,
|
current: urls[0]
|
||||||
longPressActions: {
|
|
||||||
itemList: ['发送给朋友', '保存图片', '收藏']
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,10 +365,6 @@ export default {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-item.full-width {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-label {
|
.filter-label {
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
color: #4e5969;
|
color: #4e5969;
|
||||||
@ -328,30 +403,47 @@ export default {
|
|||||||
.stats-card {
|
.stats-card {
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
padding: 24rpx;
|
padding: 20rpx 24rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stats-icon {
|
.stats-item {
|
||||||
font-size: 40rpx;
|
display: flex;
|
||||||
margin-right: 16rpx;
|
flex-direction: column;
|
||||||
}
|
align-items: center;
|
||||||
|
gap: 6rpx;
|
||||||
.stats-label {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #4e5969;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stats-value {
|
.stats-num {
|
||||||
font-size: 36rpx;
|
font-size: 36rpx;
|
||||||
color: #1d2129;
|
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 记录列表 */
|
.stats-num.success { color: #67c23a; }
|
||||||
|
.stats-num.pending { color: #e6a23c; }
|
||||||
|
.stats-num.failed { color: #f56c6c; }
|
||||||
|
.stats-num.total { color: #409eff; }
|
||||||
|
|
||||||
|
.stats-label {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-divider {
|
||||||
|
width: 1px;
|
||||||
|
height: 48rpx;
|
||||||
|
background: #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动列表 */
|
||||||
|
.record-scroll {
|
||||||
|
height: calc(100vh - 300rpx);
|
||||||
|
}
|
||||||
|
|
||||||
.record-list {
|
.record-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -377,7 +469,6 @@ export default {
|
|||||||
height: 180rpx;
|
height: 180rpx;
|
||||||
border-radius: 12rpx;
|
border-radius: 12rpx;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,34 +477,12 @@ export default {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-overlay {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 60rpx;
|
|
||||||
background: linear-gradient(transparent, rgba(0, 0, 0, 0.5));
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.record-image:active .image-overlay {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.zoom-icon {
|
|
||||||
font-size: 28rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 基本信息 */
|
/* 基本信息 */
|
||||||
.record-info {
|
.record-info {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10rpx;
|
gap: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-row {
|
.info-row {
|
||||||
@ -422,14 +491,17 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.book-name {
|
.book-name {
|
||||||
font-size: 32rpx;
|
font-size: 30rpx;
|
||||||
color: #1d2129;
|
color: #1d2129;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
lines: 1;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-label {
|
.info-label {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #86909c;
|
color: #86909c;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-value {
|
.info-value {
|
||||||
@ -437,38 +509,6 @@ export default {
|
|||||||
color: #4e5969;
|
color: #4e5969;
|
||||||
}
|
}
|
||||||
|
|
||||||
.condition-badge {
|
|
||||||
font-size: 22rpx;
|
|
||||||
padding: 4rpx 12rpx;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-new {
|
|
||||||
background: #e1f3d8;
|
|
||||||
color: #67c23a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-good {
|
|
||||||
background: #d9ecff;
|
|
||||||
color: #409eff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-fair {
|
|
||||||
background: #faecd8;
|
|
||||||
color: #e6a23c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-poor {
|
|
||||||
background: #fde2e2;
|
|
||||||
color: #f56c6c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-default {
|
|
||||||
background: #f4f4f5;
|
|
||||||
color: #909399;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 价格和库存 */
|
/* 价格和库存 */
|
||||||
.record-detail {
|
.record-detail {
|
||||||
background: #f5f6fa;
|
background: #f5f6fa;
|
||||||
@ -504,7 +544,7 @@ export default {
|
|||||||
color: #f56c6c;
|
color: #f56c6c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 发布状态 */
|
/* 状态 */
|
||||||
.publish-status {
|
.publish-status {
|
||||||
border-top: 1rpx solid #ebeef5;
|
border-top: 1rpx solid #ebeef5;
|
||||||
padding-top: 16rpx;
|
padding-top: 16rpx;
|
||||||
@ -512,40 +552,63 @@ export default {
|
|||||||
|
|
||||||
.status-row {
|
.status-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-icon {
|
|
||||||
font-size: 20rpx;
|
|
||||||
width: 28rpx;
|
|
||||||
height: 28rpx;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #c0c4cc;
|
|
||||||
color: #ffffff;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-item.published .status-icon {
|
.status-tag {
|
||||||
background: #67c23a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-text {
|
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
color: #86909c;
|
padding: 6rpx 20rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-item.published .status-text {
|
.status-success {
|
||||||
|
background: #e1f3d8;
|
||||||
color: #67c23a;
|
color: #67c23a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status-pending {
|
||||||
|
background: #faecd8;
|
||||||
|
color: #e6a23c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-failed {
|
||||||
|
background: #fde2e2;
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载更多 */
|
||||||
|
.load-more {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 30rpx 0;
|
||||||
|
gap: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-more-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-more-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #c0c4cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
border: 3rpx solid #e4e7ed;
|
||||||
|
border-top-color: #409eff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
/* 空状态 */
|
/* 空状态 */
|
||||||
.empty-state {
|
.empty-state {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -199,8 +199,9 @@
|
|||||||
|
|
||||||
<!-- 上书记录 -->
|
<!-- 上书记录 -->
|
||||||
<view class="form-section">
|
<view class="form-section">
|
||||||
<view class="section-title">
|
<view class="section-title" @click="goRecordPage">
|
||||||
<text class="title-text">上书记录</text>
|
<text class="title-text">上书记录</text>
|
||||||
|
<text class="title-more">查看全部 ›</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="history-list">
|
<view class="history-list">
|
||||||
<view class="history-item" v-for="(item, index) in historyList" :key="index">
|
<view class="history-item" v-for="(item, index) in historyList" :key="index">
|
||||||
@ -505,8 +506,9 @@
|
|||||||
|
|
||||||
<!-- ===== 上书记录 ===== -->
|
<!-- ===== 上书记录 ===== -->
|
||||||
<view class="form-section" v-if="noIsbnHistoryList.length > 0">
|
<view class="form-section" v-if="noIsbnHistoryList.length > 0">
|
||||||
<view class="section-title">
|
<view class="section-title" @click="goRecordPage">
|
||||||
<text class="title-text">上书记录</text>
|
<text class="title-text">上书记录</text>
|
||||||
|
<text class="title-more">查看全部 ›</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="history-list">
|
<view class="history-list">
|
||||||
<view class="history-item" v-for="(item, index) in noIsbnHistoryList" :key="index">
|
<view class="history-item" v-for="(item, index) in noIsbnHistoryList" :key="index">
|
||||||
@ -2595,6 +2597,11 @@ export default {
|
|||||||
this.pendingCount = 0
|
this.pendingCount = 0
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 跳转到上书记录页面
|
||||||
|
goRecordPage() {
|
||||||
|
uni.navigateTo({ url: '/pages/record/record' })
|
||||||
|
},
|
||||||
|
|
||||||
// 带自动重试的请求封装(网络抖动时自动重试2次)
|
// 带自动重试的请求封装(网络抖动时自动重试2次)
|
||||||
requestWithRetry(options, maxRetries) {
|
requestWithRetry(options, maxRetries) {
|
||||||
if (maxRetries === undefined) maxRetries = 2
|
if (maxRetries === undefined) maxRetries = 2
|
||||||
@ -3851,6 +3858,12 @@ export default {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title-more {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #409eff;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.photo-count {
|
.photo-count {
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
color: #909399;
|
color: #909399;
|
||||||
|
|||||||
74
utils/api.js
74
utils/api.js
@ -360,6 +360,76 @@ function buildFormBodyWithImages(params, imageUrls, imageKey) {
|
|||||||
|
|
||||||
export { buildFormBodyWithImages }
|
export { buildFormBodyWithImages }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取店铺列表(上书记录用)
|
||||||
|
* @param {Object} params - { pageNum, pageSize, shop_type }
|
||||||
|
*/
|
||||||
|
export function getShopList(params = {}) {
|
||||||
|
return requestWithRetry((token) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const url = generateSignedUrl(`${BASE_URL}/api/shop/list`, params)
|
||||||
|
console.log('【店铺列表】请求URL:', url)
|
||||||
|
uni.request({
|
||||||
|
url: url,
|
||||||
|
method: 'GET',
|
||||||
|
header: {
|
||||||
|
'Authorization': 'Bearer ' + token
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
console.log('【店铺列表】响应:', JSON.stringify(res.data))
|
||||||
|
if (res.statusCode === 200 && res.data && res.data.code === 0) {
|
||||||
|
resolve(res.data.data)
|
||||||
|
} else {
|
||||||
|
resolve({ list: [], total: 0 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('【店铺列表】请求失败:', err)
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, '店铺列表')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取店铺上书详情(上书记录列表)
|
||||||
|
* @param {Object} params - { page, page_size, shop_id }
|
||||||
|
*/
|
||||||
|
export function getShopDetail(params = {}) {
|
||||||
|
return requestWithRetry((token) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const url = generateSignedUrl(`${BASE_URL}/api/product/shop-detail`, params)
|
||||||
|
console.log('【上书详情】请求URL:', url)
|
||||||
|
uni.request({
|
||||||
|
url: url,
|
||||||
|
method: 'GET',
|
||||||
|
header: {
|
||||||
|
'Authorization': 'Bearer ' + token
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
console.log('【上书详情】响应:', JSON.stringify(res.data))
|
||||||
|
if (res.statusCode === 200 && res.data) {
|
||||||
|
if (res.data.code === 200 && res.data.data) {
|
||||||
|
resolve(res.data.data)
|
||||||
|
} else if (res.data.data) {
|
||||||
|
resolve(res.data.data)
|
||||||
|
} else {
|
||||||
|
resolve({ products: [], total: 0, page: 1, page_size: 10 })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resolve({ products: [], total: 0, page: 1, page_size: 10 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('【上书详情】请求失败:', err)
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, '上书详情')
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
calculateSign,
|
calculateSign,
|
||||||
buildFormBodyWithImages,
|
buildFormBodyWithImages,
|
||||||
@ -367,5 +437,7 @@ export default {
|
|||||||
getLocationList,
|
getLocationList,
|
||||||
psiLogin,
|
psiLogin,
|
||||||
searchBookByIsbn,
|
searchBookByIsbn,
|
||||||
generateSignedUrl
|
generateSignedUrl,
|
||||||
|
getShopList,
|
||||||
|
getShopDetail
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user