2
This commit is contained in:
194
frontend/pages/product/submissions.vue
Normal file
194
frontend/pages/product/submissions.vue
Normal file
@@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="hero">
|
||||
<text class="title">我的配件提交</text>
|
||||
<text class="desc">查看待审核、已通过、已驳回的记录</text>
|
||||
</view>
|
||||
|
||||
<view class="tabs">
|
||||
<view class="tab" :class="{ active: status === '' }" @click="switchStatus('')">全部</view>
|
||||
<view class="tab" :class="{ active: status === 'pending' }" @click="switchStatus('pending')">待审核</view>
|
||||
<view class="tab" :class="{ active: status === 'approved' }" @click="switchStatus('approved')">已通过</view>
|
||||
<view class="tab" :class="{ active: status === 'rejected' }" @click="switchStatus('rejected')">已驳回</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="list" @scrolltolower="loadMore">
|
||||
<view v-if="items.length" class="cards">
|
||||
<view class="card" v-for="item in items" :key="item.id">
|
||||
<view class="card-header">
|
||||
<text class="model">{{ item.model || '-' }}</text>
|
||||
<text :class="['status', statusClass(item.status)]">{{ statusLabel(item.status) }}</text>
|
||||
</view>
|
||||
<view class="card-body">
|
||||
<text class="name">{{ item.name || '未填写名称' }}</text>
|
||||
<text class="brand">品牌:{{ item.brand || '-' }}</text>
|
||||
<text class="time">提交:{{ formatTime(item.createdAt) }}</text>
|
||||
<text class="time" v-if="item.reviewedAt">审核:{{ formatTime(item.reviewedAt) }}</text>
|
||||
</view>
|
||||
<view class="card-footer">
|
||||
<button size="mini" @click="viewDetail(item.id)">详情</button>
|
||||
<button size="mini" type="primary" v-if="item.status === 'pending'" @click="notifyPending">等待审核</button>
|
||||
<button size="mini" type="warn" v-else-if="item.status === 'rejected'" @click="resubmit(item)">重新提交</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="empty">
|
||||
<text>暂无提交记录,快去提交新的配件吧</text>
|
||||
<button size="mini" class="primary" @click="goSubmit">立即提交</button>
|
||||
</view>
|
||||
<view v-if="loading" class="loading">加载中...</view>
|
||||
<view v-else-if="finished && items.length" class="finished">没有更多了</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="fab" @click="goSubmit">+</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get } from '../../common/http.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
status: '',
|
||||
items: [],
|
||||
page: 1,
|
||||
size: 20,
|
||||
total: 0,
|
||||
loading: false,
|
||||
finished: false,
|
||||
cacheUnitsLoaded: false,
|
||||
cacheCategoriesLoaded: false
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
this.preloadDictionaries()
|
||||
this.reload()
|
||||
},
|
||||
methods: {
|
||||
async preloadDictionaries() {
|
||||
try {
|
||||
const [units, categories] = await Promise.all([
|
||||
this.cacheUnitsLoaded ? Promise.resolve(null) : get('/api/product-units'),
|
||||
this.cacheCategoriesLoaded ? Promise.resolve(null) : get('/api/product-categories')
|
||||
])
|
||||
if (units) {
|
||||
const list = Array.isArray(units?.list) ? units.list : (Array.isArray(units) ? units : [])
|
||||
uni.setStorageSync('CACHE_UNITS', list)
|
||||
this.cacheUnitsLoaded = true
|
||||
}
|
||||
if (categories) {
|
||||
const list = Array.isArray(categories?.list) ? categories.list : (Array.isArray(categories) ? categories : [])
|
||||
uni.setStorageSync('CACHE_CATEGORIES', list)
|
||||
this.cacheCategoriesLoaded = true
|
||||
}
|
||||
} catch (_) {
|
||||
// 忽略缓存失败
|
||||
}
|
||||
},
|
||||
switchStatus(s) {
|
||||
if (this.status === s) return
|
||||
this.status = s
|
||||
this.reload()
|
||||
},
|
||||
async reload() {
|
||||
this.page = 1
|
||||
this.items = []
|
||||
this.finished = false
|
||||
await this.loadMore()
|
||||
},
|
||||
async loadMore() {
|
||||
if (this.loading || this.finished) return
|
||||
this.loading = true
|
||||
try {
|
||||
const params = { page: this.page, size: this.size }
|
||||
if (this.status) params.status = this.status
|
||||
const res = await get('/api/products/submissions', params)
|
||||
const list = Array.isArray(res?.list) ? res.list : []
|
||||
this.items = this.items.concat(list)
|
||||
this.total = Number(res?.total || this.items.length)
|
||||
if (list.length < this.size) this.finished = true
|
||||
this.page += 1
|
||||
} catch (e) {
|
||||
console.warn('加载提交记录失败', e)
|
||||
const msg = e?.message || '加载失败'
|
||||
uni.showToast({ title: msg, icon: 'none' })
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
statusLabel(s) {
|
||||
if (s === 'approved') return '已通过'
|
||||
if (s === 'rejected') return '已驳回'
|
||||
return '待审核'
|
||||
},
|
||||
statusClass(s) {
|
||||
if (s === 'approved') return 'approved'
|
||||
if (s === 'rejected') return 'rejected'
|
||||
return 'pending'
|
||||
},
|
||||
formatTime(value) {
|
||||
if (!value) return '-'
|
||||
try {
|
||||
const d = new Date(value)
|
||||
if (!Number.isFinite(d.getTime())) return value
|
||||
const y = d.getFullYear()
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
const hh = String(d.getHours()).padStart(2, '0')
|
||||
const mm = String(d.getMinutes()).padStart(2, '0')
|
||||
return `${y}-${m}-${day} ${hh}:${mm}`
|
||||
} catch (_) { return value }
|
||||
},
|
||||
viewDetail(id) {
|
||||
uni.navigateTo({ url: `/pages/product/submission-detail?id=${id}` })
|
||||
},
|
||||
notifyPending() {
|
||||
uni.showToast({ title: '审核中,请耐心等待', icon: 'none' })
|
||||
},
|
||||
resubmit(item) {
|
||||
const payload = {
|
||||
model: item.model,
|
||||
name: item.name,
|
||||
brand: item.brand,
|
||||
spec: item.spec,
|
||||
origin: item.origin,
|
||||
unitId: item.unitId,
|
||||
categoryId: item.categoryId,
|
||||
remark: item.remark
|
||||
}
|
||||
const query = encodeURIComponent(JSON.stringify(payload))
|
||||
uni.navigateTo({ url: `/pages/product/submit?prefill=${query}` })
|
||||
},
|
||||
goSubmit() {
|
||||
uni.navigateTo({ url: '/pages/product/submit' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page { display: flex; flex-direction: column; height: 100vh; background: #f6f7fb; padding-bottom: 140rpx; }
|
||||
.hero { padding: 24rpx; background: #fff; box-shadow: 0 10rpx 30rpx rgba(0,0,0,0.04); }
|
||||
.title { font-size: 34rpx; font-weight: 700; color: #2d3a4a; }
|
||||
.desc { font-size: 24rpx; color: #7a8899; margin-top: 8rpx; }
|
||||
.tabs { display: flex; background: #fff; margin: 16rpx; border-radius: 999rpx; overflow: hidden; box-shadow: inset 0 0 0 1rpx rgba(76,141,255,0.1); }
|
||||
.tab { flex: 1; text-align: center; padding: 20rpx 0; font-size: 28rpx; color: #7a8899; }
|
||||
.tab.active { background: linear-gradient(135deg, #4c8dff, #6ab7ff); color: #fff; font-weight: 600; }
|
||||
.list { flex: 1; padding: 0 20rpx; }
|
||||
.cards { display: flex; flex-direction: column; gap: 20rpx; padding-bottom: 40rpx; }
|
||||
.card { background: #fff; border-radius: 18rpx; padding: 22rpx; box-shadow: 0 10rpx 30rpx rgba(0,0,0,0.05); }
|
||||
.card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12rpx; }
|
||||
.model { font-size: 30rpx; font-weight: 700; color: #2d3a4a; }
|
||||
.status { font-size: 24rpx; padding: 6rpx 18rpx; border-radius: 999rpx; }
|
||||
.status.pending { background: rgba(246, 190, 0, 0.15); color: #c47f00; }
|
||||
.status.approved { background: rgba(103,194,58,0.15); color: #409eff; }
|
||||
.status.rejected { background: rgba(255,87,115,0.18); color: #f56c6c; }
|
||||
.card-body { display: flex; flex-direction: column; gap: 6rpx; color: #4f5969; font-size: 26rpx; }
|
||||
.name { font-weight: 600; color: #2d3a4a; }
|
||||
.card-footer { display: flex; gap: 12rpx; margin-top: 16rpx; }
|
||||
.empty { height: 60vh; display: flex; flex-direction: column; align-items: center; justify-content: center; color: #8894a3; gap: 20rpx; }
|
||||
.empty .primary { background: #4c8dff; color: #fff; border-radius: 999rpx; padding: 12rpx 30rpx; }
|
||||
.loading, .finished { text-align: center; padding: 20rpx 0; color: #7a8899; }
|
||||
.fab { position: fixed; right: 30rpx; bottom: 120rpx; width: 100rpx; height: 100rpx; background: linear-gradient(135deg, #4c8dff, #6ab7ff); color: #fff; border-radius: 50rpx; display: flex; align-items: center; justify-content: center; font-size: 48rpx; box-shadow: 0 20rpx 40rpx rgba(0,0,0,0.2); }
|
||||
</style>
|
||||
Reference in New Issue
Block a user