Files
PartsInquiry/frontend/pages/detail/index.vue
2025-09-20 22:09:15 +08:00

165 lines
7.9 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="seg">
<view :class="['seg-item', range==='custom' && 'active']" @click="switchRange('custom')">自定义</view>
<view :class="['seg-item', range==='week' && 'active']" @click="switchRange('week')">本周</view>
<view :class="['seg-item', range==='today' && 'active']" @click="switchRange('today')">今日</view>
<view :class="['seg-item', range==='month' && 'active']" @click="switchRange('month')">本月</view>
<view :class="['seg-item', range==='year' && 'active']" @click="switchRange('year')">本年</view>
</view>
<!-- 业务类型侧边切换销售/进货/收款/资金/盘点 -->
<view class="content">
<view class="biz-tabs">
<view v-for="b in bizList" :key="b.key" :class="['biz', biz===b.key && 'active']" @click="switchBiz(b.key)">{{ b.name }}</view>
</view>
<view class="panel">
<!-- 搜索框与期间显示总额 -->
<view class="toolbar">
<view class="search">
<input class="search-input" v-model.trim="query.kw" :placeholder="placeholder" @confirm="reload" />
</view>
<view class="period">{{ periodLabel }}</view>
<button size="mini" @click="reload">查询</button>
</view>
<view class="total">合计¥{{ totalAmount.toFixed(2) }}</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="openDetail(it)">
<view class="item-left">
<view class="date">{{ formatDate(it.orderTime || it.txTime || it.createdAt) }}</view>
<view class="name">{{ it.customerName || it.supplierName || it.accountName || it.remark || '-' }}</view>
<view class="no">{{ it.orderNo || it.code || it.id }}</view>
</view>
<view class="amount" :class="{ in: Number(it.amount||0) >= 0, out: Number(it.amount||0) < 0 }">¥ {{ (it.amount || 0).toFixed(2) }}</view>
<view class="arrow"></view>
</view>
</block>
<view v-else class="empty">暂无数据</view>
</scroll-view>
<!-- 右下角新增按钮根据业务类型跳转对应开单页或创建页 -->
<view class="fab" @click="onCreate"></view>
</view>
</view>
</view>
</template>
<script>
import { get } from '../../common/http.js'
const API_OF = {
sale: '/api/orders',
purchase: '/api/purchase-orders',
collect: '/api/payments',
fund: '/api/other-transactions',
stock: '/api/inventories/logs'
}
export default {
data() {
return {
biz: 'sale',
bizList: [
{ key: 'sale', name: '出货' },
{ key: 'purchase', name: '进货' },
{ key: 'collect', name: '收款' },
{ key: 'fund', name: '资金' },
{ key: 'stock', name: '盘点' }
],
range: 'month',
query: { kw: '' },
items: [],
page: 1,
size: 20,
finished: false,
loading: false,
startDate: '',
endDate: ''
}
},
computed: {
placeholder() { return '单据号/客户名称/品名规格/备注' },
periodLabel() { return this.startDate && this.endDate ? `${this.startDate}~${this.endDate}` : '' },
totalAmount() { return this.items.reduce((s, it) => s + Number(it.amount || 0), 0) }
},
onLoad() {
try { console.log('[detail] onLoad route = pages/detail/index') } catch(e){}
this.computeRange()
this.reload()
},
methods: {
switchBiz(k) { if (this.biz === k) return; this.biz = k; this.reload() },
switchRange(r) { this.range = r; this.computeRange(); this.reload() },
computeRange() {
const now = new Date()
const pad = n => String(n).padStart(2, '0')
const fmt = d => `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`
let start = now, end = now
if (this.range === 'today') { start = end = now }
else if (this.range === 'week') { const day = now.getDay() || 7; start = new Date(now.getFullYear(), now.getMonth(), now.getDate() - day + 1); end = now }
else if (this.range === 'month') { start = new Date(now.getFullYear(), now.getMonth(), 1); end = new Date(now.getFullYear(), now.getMonth() + 1, 0) }
else if (this.range === 'year') { start = new Date(now.getFullYear(), 0, 1); end = new Date(now.getFullYear(), 11, 31) }
else { start = new Date(now.getFullYear(), now.getMonth(), 1); end = new Date(now.getFullYear(), now.getMonth() + 1, 0) }
this.startDate = fmt(start); this.endDate = fmt(end)
},
reload() { this.items = []; this.page = 1; this.finished = false; this.loadMore() },
async loadMore() {
if (this.loading || this.finished) return
this.loading = true
try {
const path = API_OF[this.biz] || '/api/orders'
const params = { kw: this.query.kw, page: this.page, size: this.size, startDate: this.startDate, endDate: this.endDate, biz: this.biz }
if (this.biz === 'sale') params.type = 'out'
const res = await get(path, params)
const list = Array.isArray(res?.list) ? res.list : (Array.isArray(res) ? res : [])
this.items = this.items.concat(list)
if (list.length < this.size) this.finished = true
this.page += 1
} catch (e) {
uni.showToast({ title: '加载失败', icon: 'none' })
} finally { this.loading = false }
},
formatDate(s) { if (!s) return ''; try { const d = new Date(s); const pad = n => String(n).padStart(2, '0'); return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}` } catch (_) { return String(s).slice(0,10) } },
onCreate() { if (this.biz === 'sale') { uni.switchTab({ url: '/pages/order/create' }); return } uni.showToast({ title: '该类型创建页待实现', icon: 'none' }) },
openDetail(it) { uni.showToast({ title: '详情开发中', icon: 'none' }) }
}
}
</script>
<style lang="scss">
.page { display:flex; flex-direction: column; height: 100vh; }
.seg { display:flex; background:#fff; border-bottom:2rpx solid $uni-border-color; }
.seg-item { flex:1; padding: 18rpx 0; text-align:center; color:$uni-text-color-grey; }
.seg-item.active { color:#fff; background:$uni-color-primary; border-radius: 12rpx; margin: 8rpx; }
.content { display:flex; flex:1; min-height: 0; }
.biz-tabs { width: 140rpx; background:#fff; border-right:2rpx solid $uni-border-color; display:flex; flex-direction: column; }
.biz { flex:0 0 120rpx; display:flex; align-items:center; justify-content:center; color:$uni-color-primary; }
.biz.active { background:rgba(76,141,255,0.10); color:$uni-color-primary; font-weight:700; }
.panel { flex:1; display:flex; flex-direction: column; background:#fff; margin: 16rpx; border-radius: 16rpx; padding: 12rpx; border:2rpx solid $uni-border-color; }
.toolbar { display:flex; align-items: center; gap: 12rpx; padding: 8rpx 6rpx; border-bottom:2rpx solid $uni-border-color; }
.search { flex:1; }
.search-input { width:100%; background:$uni-bg-color-hover; border-radius: 12rpx; padding: 12rpx; color:$uni-text-color; }
.period { color:$uni-text-color-grey; font-size: 24rpx; padding: 0 6rpx; }
.total { color:$uni-color-primary; font-weight: 700; padding: 10rpx 6rpx 12rpx; background:#fff; }
.list { flex:1; }
.item { display:grid; grid-template-columns: 1fr auto auto; align-items:center; gap: 8rpx; padding: 18rpx 12rpx; border-bottom: 1rpx solid $uni-border-color; }
.item-left { display:flex; flex-direction: column; }
.date { color:$uni-text-color-grey; font-size: 24rpx; }
.name { color:$uni-text-color; margin: 4rpx 0; font-weight: 600; }
.no { color:#99a2b3; font-size: 22rpx; }
.amount { color:$uni-text-color; font-weight: 700; text-align:right; }
.amount.in { color:#16a34a; }
.amount.out { color:#dc2626; }
.arrow { color:#8c99b0; font-size: 40rpx; margin-left: 8rpx; }
.empty { height: 50vh; 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:#fff; color:$uni-color-primary; border:2rpx solid $uni-color-primary; border-radius: 50rpx; text-align:center; line-height: 100rpx; font-size: 48rpx; box-shadow: 0 8rpx 20rpx rgba(76,141,255,0.18); }
</style>