Files
PartsInquiry/frontend/pages/product/list.vue
2025-09-24 20:35:15 +08:00

150 lines
5.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page">
<view class="tabs">
<view class="tab" :class="{active: tab==='all'}" @click="switchTab('all')">全部</view>
<view class="tab" :class="{active: tab==='category'}" @click="switchTab('category')">按类别</view>
</view>
<view class="search">
<input v-model.trim="query.kw" placeholder="输入名称/条码/规格查询" @confirm="reload" />
<picker mode="selector" :range="categoryNames" v-if="tab==='category'" @change="onPickCategory">
<view class="picker">{{ categoryLabel }}</view>
</picker>
<button size="mini" @click="reload">查询</button>
</view>
<scroll-view scroll-y class="list" @scrolltolower="loadMore">
<block v-if="items.length">
<view class="item" v-for="it in items" :key="it.id" @click="openForm(it.id)">
<image v-if="it.cover" :src="it.cover" class="thumb" mode="aspectFill" />
<view class="content">
<view class="name">{{ it.name }}</view>
<view class="meta">{{ it.brand || '-' }} {{ it.model || '' }} {{ it.spec || '' }}</view>
<view class="meta">库存{{ it.stock ?? 0 }}
<text class="price">零售价¥{{ (it.retailPrice ?? it.price ?? 0).toFixed(2) }}</text>
</view>
</view>
</view>
</block>
<view v-else class="empty">
<text>暂无数据点击右上角新增</text>
</view>
</scroll-view>
<view class="fab" @click="openForm()"></view>
</view>
</template>
<script>
import { get } from '../../common/http.js'
export default {
data() {
return {
items: [],
query: { kw: '', page: 1, size: 20, categoryId: '' },
finished: false,
loading: false,
tab: 'all',
categories: []
}
},
onLoad() {
const hasToken = (() => { try { return !!uni.getStorageSync('TOKEN') } catch(e){ return false } })()
if (!hasToken) {
this.items = []
this.categories = []
uni.showToast({ title: '请登录使用该功能', icon: 'none' })
return
}
this.fetchCategories()
this.reload()
},
onShow() {
const hasToken = (() => { try { return !!uni.getStorageSync('TOKEN') } catch(e){ return false } })()
if (!hasToken) return
// 从创建/编辑页返回时,确保刷新最新列表
this.reload()
},
computed: {
categoryNames() { return this.categories.map(c => c.name) },
categoryLabel() {
const c = this.categories.find(x => String(x.id) === String(this.query.categoryId))
return c ? '类别:' + c.name : '选择类别'
}
},
methods: {
switchTab(t) {
this.tab = t
this.query.categoryId = ''
this.reload()
},
onPickCategory(e) {
const idx = Number(e.detail.value)
const c = this.categories[idx]
this.query.categoryId = c ? c.id : ''
this.reload()
},
async fetchCategories() {
try {
const res = await get('/api/product-categories', {})
this.categories = Array.isArray(res?.list) ? res.list : (Array.isArray(res) ? res : [])
} catch (_) {}
},
reload() {
this.items = []
this.query.page = 1
this.finished = false
this.loadMore()
},
async loadMore() {
if (this.loading || this.finished) return
this.loading = true
try {
const params = { kw: this.query.kw, page: this.query.page, size: this.query.size }
if (this.tab === 'category' && this.query.categoryId) params.categoryId = this.query.categoryId
const res = await get('/api/products', params)
const list = Array.isArray(res?.list) ? res.list : (Array.isArray(res) ? res : [])
this.items = this.items.concat(list)
if (list.length < this.query.size) this.finished = true
this.query.page += 1
} catch (e) {
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
this.loading = false
}
},
openForm(id) {
const url = '/pages/product/form' + (id ? ('?id=' + id) : '')
uni.navigateTo({ url })
}
}
}
</script>
<style lang="scss">
.page { display:flex; flex-direction: column; height: 100vh; }
.tabs { display:flex; background:$uni-bg-color-grey; }
.tab { flex:1; text-align:center; padding: 20rpx 0; color:$uni-text-color-grey; }
.tab.active { color:$uni-color-primary; font-weight: 600; }
.search { display:flex; gap: 12rpx; padding: 16rpx; background:$uni-bg-color-grey; align-items: center; }
.search input { flex:1; background:$uni-bg-color-hover; border-radius: 12rpx; padding: 12rpx; color: $uni-text-color; }
.picker { padding: 8rpx 12rpx; background:$uni-bg-color-hover; border-radius: 10rpx; color:$uni-text-color-grey; }
.list { flex:1; }
.item { display:flex; padding: 20rpx; background:$uni-bg-color-grey; border-bottom: 1rpx solid $uni-border-color; }
.thumb { width: 120rpx; height: 120rpx; border-radius: 12rpx; margin-right: 16rpx; background:$uni-bg-color-hover; }
.content { flex:1; }
.name { color:$uni-text-color; margin-bottom: 6rpx; font-weight: 600; }
.meta { color:$uni-text-color-grey; font-size: 24rpx; }
.price { margin-left: 20rpx; color:$uni-color-primary; }
.empty { height: 60vh; display:flex; align-items:center; justify-content:center; color:$uni-text-color-grey; }
.fab { position: fixed; right: 30rpx; bottom: 120rpx; width: 100rpx; height: 100rpx; background:$uni-color-primary; color:#fff; border-radius: 50rpx; text-align:center; line-height: 100rpx; font-size: 48rpx; box-shadow: 0 8rpx 20rpx rgba(0,0,0,0.15); }
</style>