This commit is contained in:
2025-09-20 12:05:53 +08:00
parent bff3d0414d
commit 9b107d665a
73 changed files with 2903 additions and 140 deletions

View File

@@ -89,6 +89,11 @@
<!-- 其它收入/支出 表单 -->
<view v-else>
<!-- 往来单位类型切换 -->
<view class="subtabs">
<button class="subbtn" :class="{ active: counterpartyType==='customer' }" @click="setCounterparty('customer')">客户</button>
<button class="subbtn" :class="{ active: counterpartyType==='supplier' }" @click="setCounterparty('supplier')">供应商</button>
</view>
<view class="chips">
<view v-for="c in (biz==='income' ? incomeCategories : expenseCategories)" :key="c.key" class="chip" :class="{ active: activeCategory===c.key }" @click="activeCategory=c.key">{{ c.label }}</view>
</view>
@@ -139,8 +144,8 @@
</template>
<script>
import { get, post } from '../../common/http.js'
import { INCOME_CATEGORIES, EXPENSE_CATEGORIES } from '../../common/constants.js'
import { get, post } from '../../common/http.js'
import { INCOME_CATEGORIES, EXPENSE_CATEGORIES } from '../../common/constants.js'
function todayString() {
const d = new Date()
@@ -151,7 +156,7 @@
export default {
data() {
return {
return {
biz: 'sale',
saleType: 'out',
purchaseType: 'in',
@@ -168,6 +173,7 @@
supplierName: '',
items: [],
activeCategory: 'sale_income',
counterpartyType: 'customer',
trxAmount: 0,
selectedAccountId: null,
selectedAccountName: '',
@@ -185,16 +191,19 @@
},
customerLabel() { return this.customerName || '零售客户' },
supplierLabel() { return this.supplierName || '零散供应商' },
incomeCategories() { return INCOME_CATEGORIES },
expenseCategories() { return EXPENSE_CATEGORIES },
incomeCategories() { return this._incomeCategories || INCOME_CATEGORIES },
expenseCategories() { return this._expenseCategories || EXPENSE_CATEGORIES },
accountLabel() { return this.selectedAccountName || '现金' },
counterpartyLabel() { return this.customerName || this.supplierName || '—' },
counterpartyLabel() { return this.counterpartyType==='customer' ? (this.customerName || '—') : (this.supplierName || '—') },
// 收款/付款合计
payTotal() {
const p = this.payments || { cash:0, bank:0, wechat:0 }
return Number(p.cash||0) + Number(p.bank||0) + Number(p.wechat||0)
}
},
onLoad() {
this.fetchCategories()
},
onShow() {
if (this.biz === 'sale') {
if (this.order.customerId && this.order.customerId !== this._lastCustomerId) {
@@ -207,6 +216,20 @@
}
},
methods: {
async fetchCategories() {
try {
const res = await get('/api/finance/categories')
if (res && Array.isArray(res.incomeCategories)) this._incomeCategories = res.incomeCategories
if (res && Array.isArray(res.expenseCategories)) this._expenseCategories = res.expenseCategories
this.ensureActiveCategory()
} catch (_) { this.ensureActiveCategory() }
},
ensureActiveCategory() {
const list = this.biz==='income' ? (this.incomeCategories||[]) : (this.expenseCategories||[])
if (!list.length) return
const exists = list.some(it => it && it.key === this.activeCategory)
if (!exists) this.activeCategory = list[0].key
},
async loadCustomerLevel(customerId) {
try {
const d = await get(`/api/customers/${customerId}`)
@@ -235,7 +258,7 @@
this.recalc()
},
onPriceInput(it) { if (it) { it._autoPrice = false; this.recalc() } },
switchBiz(type) { this.biz = type },
switchBiz(type) { this.biz = type; this.ensureActiveCategory() },
onDateChange(e) { this.order.orderTime = e.detail.value },
chooseCustomer() {
uni.navigateTo({ url: '/pages/customer/select' })
@@ -244,12 +267,13 @@
chooseProduct() {
uni.navigateTo({ url: '/pages/product/select' })
},
chooseAccount() { uni.navigateTo({ url: '/pages/account/select' }) },
chooseAccount() { uni.navigateTo({ url: '/pages/account/select?mode=pick' }) },
chooseCounterparty() {
if (this.biz==='income' || this.biz==='expense') {
uni.navigateTo({ url: '/pages/customer/select' })
}
if (!(this.biz==='income' || this.biz==='expense')) return
if (this.counterpartyType==='customer') { uni.navigateTo({ url: '/pages/customer/select' }) }
else { uni.navigateTo({ url: '/pages/supplier/select' }) }
},
setCounterparty(t) { this.counterpartyType = t; this.ensureActiveCategory() },
recalc() { this.$forceUpdate() },
recalcPay() { this.$forceUpdate() },
async submit() {
@@ -262,7 +286,7 @@
const invalid = this.items.find(it => !it.productId || Number(it.quantity||0) <= 0)
if (invalid) { uni.showToast({ title: '数量需大于0', icon: 'none' }); return }
}
const payload = isSaleOrPurchase ? (isCollectOrPay ? [
const payload = isSaleOrPurchase ? (isCollectOrPay ? [
{ method: 'cash', amount: Number(this.payments.cash||0) },
{ method: 'bank', amount: Number(this.payments.bank||0) },
{ method: 'wechat', amount: Number(this.payments.wechat||0) }
@@ -276,7 +300,8 @@
}) : {
type: this.biz,
category: this.activeCategory,
counterpartyId: this.order.customerId || null,
counterpartyType: this.counterpartyType,
counterpartyId: this.counterpartyType==='customer' ? (this.order.customerId || null) : (this.order.supplierId || null),
accountId: this.selectedAccountId || null,
amount: Number(this.trxAmount||0),
txTime: this.order.orderTime,
@@ -328,6 +353,10 @@
.textarea { position: relative; padding: 16rpx 24rpx; background:#fff; border-top: 1rpx solid #eee; }
.amount-badge { position: absolute; right: 24rpx; top: -36rpx; background: #d1f0ff; color:#107e9b; padding: 8rpx 16rpx; border-radius: 12rpx; font-size: 24rpx; }
.date-mini { position: absolute; right: 24rpx; bottom: 20rpx; color:#666; font-size: 24rpx; }
/* 分类chips样式选中后文字变红 */
.chips { display:flex; flex-wrap: wrap; gap: 12rpx; padding: 12rpx 24rpx; }
.chip { padding: 10rpx 20rpx; border-radius: 999rpx; background: #f4f4f4; color:#666; }
.chip.active { color: #e54d42; }
</style>