x
This commit is contained in:
+235
-20
@@ -1474,9 +1474,17 @@ const InventoryView = {
|
||||
activeTab: 'dashboard',
|
||||
dashboard: null,
|
||||
financeSummary: null,
|
||||
financePeriod: {
|
||||
year: new Date().getFullYear(),
|
||||
quarter: ''
|
||||
},
|
||||
financeTransactions: [],
|
||||
receivables: [],
|
||||
payables: [],
|
||||
customerFinanceStatement: [],
|
||||
supplierFinanceStatement: [],
|
||||
customerProductStatement: [],
|
||||
supplierProductStatement: [],
|
||||
products: [],
|
||||
suppliers: [],
|
||||
customers: [],
|
||||
@@ -1512,6 +1520,17 @@ const InventoryView = {
|
||||
}
|
||||
};
|
||||
|
||||
const loadWarehouses = async () => {
|
||||
state.loading = true;
|
||||
try {
|
||||
state.warehouses = await apiRequest('/api/warehouses');
|
||||
} catch (e) {
|
||||
handleApiError(e, '加载仓库');
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadSuppliers = async () => {
|
||||
state.loading = true;
|
||||
try {
|
||||
@@ -1559,16 +1578,39 @@ const InventoryView = {
|
||||
const loadFinance = async () => {
|
||||
state.loading = true;
|
||||
try {
|
||||
const [summary, transactions, receivables, payables] = await Promise.all([
|
||||
apiRequest('/api/finance/summary'),
|
||||
apiRequest('/api/finance/transactions?status=confirmed&limit=20'),
|
||||
apiRequest('/api/finance/receivables?limit=20'),
|
||||
apiRequest('/api/finance/payables?limit=20')
|
||||
const selectedYear = Number(state.financePeriod.year) || new Date().getFullYear();
|
||||
const selectedQuarter = state.financePeriod.quarter ? Number(state.financePeriod.quarter) : null;
|
||||
const periodQuery = selectedQuarter
|
||||
? `year=${selectedYear}&quarter=${selectedQuarter}`
|
||||
: `year=${selectedYear}`;
|
||||
|
||||
const [
|
||||
summary,
|
||||
transactions,
|
||||
receivables,
|
||||
payables,
|
||||
customerStatement,
|
||||
supplierStatement,
|
||||
customerProductStatement,
|
||||
supplierProductStatement
|
||||
] = await Promise.all([
|
||||
apiRequest(`/api/finance/summary?${periodQuery}`),
|
||||
apiRequest(`/api/finance/transactions?status=confirmed&limit=20&${periodQuery}`),
|
||||
apiRequest(`/api/finance/receivables?limit=20&${periodQuery}`),
|
||||
apiRequest(`/api/finance/payables?limit=20&${periodQuery}`),
|
||||
apiRequest(`/api/finance/partner-statement/customer?${periodQuery}`),
|
||||
apiRequest(`/api/finance/partner-statement/supplier?${periodQuery}`),
|
||||
apiRequest(`/api/finance/partner-product-statement/customer?${periodQuery}`),
|
||||
apiRequest(`/api/finance/partner-product-statement/supplier?${periodQuery}`)
|
||||
]);
|
||||
state.financeSummary = summary;
|
||||
state.financeTransactions = transactions;
|
||||
state.receivables = receivables;
|
||||
state.payables = payables;
|
||||
state.customerFinanceStatement = customerStatement.items || [];
|
||||
state.supplierFinanceStatement = supplierStatement.items || [];
|
||||
state.customerProductStatement = customerProductStatement.items || [];
|
||||
state.supplierProductStatement = supplierProductStatement.items || [];
|
||||
} catch (e) {
|
||||
handleApiError(e, '加载财务数据');
|
||||
} finally {
|
||||
@@ -1576,6 +1618,12 @@ const InventoryView = {
|
||||
}
|
||||
};
|
||||
|
||||
const refreshFinanceByPeriod = () => {
|
||||
if (state.activeTab === 'finance') {
|
||||
loadFinance();
|
||||
}
|
||||
};
|
||||
|
||||
const switchTab = (tab) => {
|
||||
state.activeTab = tab;
|
||||
switch (tab) {
|
||||
@@ -1589,13 +1637,26 @@ const InventoryView = {
|
||||
}
|
||||
};
|
||||
|
||||
const openModal = (type, item = null) => {
|
||||
const openModal = async (type, item = null) => {
|
||||
state.modalType = type;
|
||||
state.editingItem = item;
|
||||
if (item) {
|
||||
state.form = { ...item };
|
||||
} else {
|
||||
state.form = {};
|
||||
if (type === 'stockIn' || type === 'stockOut') {
|
||||
if (!state.products.length) {
|
||||
await loadProducts();
|
||||
}
|
||||
if (!state.warehouses.length) {
|
||||
await loadWarehouses();
|
||||
}
|
||||
state.form = {
|
||||
product_id: state.products[0]?.id || null,
|
||||
warehouse_id: state.warehouses.find(w => w.is_default)?.id || state.warehouses[0]?.id || null,
|
||||
quantity: 1
|
||||
};
|
||||
}
|
||||
}
|
||||
state.showModal = true;
|
||||
};
|
||||
@@ -1759,7 +1820,8 @@ const InventoryView = {
|
||||
saveCustomer,
|
||||
deleteCustomer,
|
||||
stockIn,
|
||||
stockOut
|
||||
stockOut,
|
||||
refreshFinanceByPeriod
|
||||
};
|
||||
},
|
||||
template: `
|
||||
@@ -1967,6 +2029,27 @@ const InventoryView = {
|
||||
</div>
|
||||
|
||||
<div v-else-if="state.activeTab === 'finance'">
|
||||
<div class="table-container" style="margin-bottom: 16px;">
|
||||
<div style="display:flex; gap:12px; align-items:center; flex-wrap:wrap;">
|
||||
<div>
|
||||
<label style="margin-right:8px;">年份</label>
|
||||
<input v-model.number="state.financePeriod.year" type="number" min="2000" max="2100" class="form-input" style="width:120px; display:inline-block;" />
|
||||
</div>
|
||||
<div>
|
||||
<label style="margin-right:8px;">季度</label>
|
||||
<select v-model="state.financePeriod.quarter" class="form-input" style="width:140px; display:inline-block;">
|
||||
<option value="">全年</option>
|
||||
<option value="1">Q1</option>
|
||||
<option value="2">Q2</option>
|
||||
<option value="3">Q3</option>
|
||||
<option value="4">Q4</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn btn-primary" @click="refreshFinanceByPeriod">刷新统计</button>
|
||||
<span style="color:var(--text-secondary);">统计周期:{{ state.financeSummary?.period_label || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">🧾</div>
|
||||
@@ -1985,19 +2068,135 @@ const InventoryView = {
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">💵</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value">{{ formatCurrency(state.financeSummary?.monthly_receipt_total || 0) }}</div>
|
||||
<div class="stat-label">本月收款</div>
|
||||
<div class="stat-value">{{ formatCurrency(state.financeSummary?.period_receipt_total || 0) }}</div>
|
||||
<div class="stat-label">周期收款</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">🏦</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value">{{ formatCurrency(state.financeSummary?.monthly_payment_total || 0) }}</div>
|
||||
<div class="stat-label">本月付款</div>
|
||||
<div class="stat-value">{{ formatCurrency(state.financeSummary?.period_payment_total || 0) }}</div>
|
||||
<div class="stat-label">周期付款</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-container" style="margin-top: 16px;">
|
||||
<h3 style="margin-bottom: 12px;">客户账款(周期)</h3>
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>客户</th>
|
||||
<th>订单数</th>
|
||||
<th>流水数</th>
|
||||
<th>订单金额</th>
|
||||
<th>订单已收</th>
|
||||
<th>实收流水</th>
|
||||
<th>应收余额</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in state.customerFinanceStatement" :key="'customer-' + item.partner_id">
|
||||
<td>{{ item.partner_name }}</td>
|
||||
<td>{{ item.order_count }}</td>
|
||||
<td>{{ item.transaction_count }}</td>
|
||||
<td>{{ formatCurrency(item.order_total) }}</td>
|
||||
<td>{{ formatCurrency(item.settled_total) }}</td>
|
||||
<td>{{ formatCurrency(item.transaction_total) }}</td>
|
||||
<td>{{ formatCurrency(item.outstanding_total) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="table-container" style="margin-top: 16px;">
|
||||
<h3 style="margin-bottom: 12px;">供应商账款(周期)</h3>
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>供应商</th>
|
||||
<th>订单数</th>
|
||||
<th>流水数</th>
|
||||
<th>订单金额</th>
|
||||
<th>订单已付</th>
|
||||
<th>实付流水</th>
|
||||
<th>应付余额</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in state.supplierFinanceStatement" :key="'supplier-' + item.partner_id">
|
||||
<td>{{ item.partner_name }}</td>
|
||||
<td>{{ item.order_count }}</td>
|
||||
<td>{{ item.transaction_count }}</td>
|
||||
<td>{{ formatCurrency(item.order_total) }}</td>
|
||||
<td>{{ formatCurrency(item.settled_total) }}</td>
|
||||
<td>{{ formatCurrency(item.transaction_total) }}</td>
|
||||
<td>{{ formatCurrency(item.outstanding_total) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="table-container" style="margin-top: 16px;">
|
||||
<h3 style="margin-bottom: 12px;">客户-商品追溯(周期)</h3>
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>客户</th>
|
||||
<th>SKU</th>
|
||||
<th>商品</th>
|
||||
<th>订单数</th>
|
||||
<th>数量</th>
|
||||
<th>订单金额</th>
|
||||
<th>已结款</th>
|
||||
<th>未结款</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in state.customerProductStatement" :key="'customer-product-' + item.partner_id + '-' + item.product_id">
|
||||
<td>{{ item.partner_name }}</td>
|
||||
<td>{{ item.product_sku || '-' }}</td>
|
||||
<td>{{ item.product_name }}</td>
|
||||
<td>{{ item.order_count }}</td>
|
||||
<td>{{ formatNumber(item.order_quantity) }}</td>
|
||||
<td>{{ formatCurrency(item.order_amount) }}</td>
|
||||
<td>{{ formatCurrency(item.settled_amount) }}</td>
|
||||
<td>{{ formatCurrency(item.outstanding_amount) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="table-container" style="margin-top: 16px;">
|
||||
<h3 style="margin-bottom: 12px;">供应商-商品追溯(周期)</h3>
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>供应商</th>
|
||||
<th>SKU</th>
|
||||
<th>商品</th>
|
||||
<th>订单数</th>
|
||||
<th>数量</th>
|
||||
<th>订单金额</th>
|
||||
<th>已结款</th>
|
||||
<th>未结款</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in state.supplierProductStatement" :key="'supplier-product-' + item.partner_id + '-' + item.product_id">
|
||||
<td>{{ item.partner_name }}</td>
|
||||
<td>{{ item.product_sku || '-' }}</td>
|
||||
<td>{{ item.product_name }}</td>
|
||||
<td>{{ item.order_count }}</td>
|
||||
<td>{{ formatNumber(item.order_quantity) }}</td>
|
||||
<td>{{ formatCurrency(item.order_amount) }}</td>
|
||||
<td>{{ formatCurrency(item.settled_amount) }}</td>
|
||||
<td>{{ formatCurrency(item.outstanding_amount) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="table-container" style="margin-top: 16px;">
|
||||
<h3 style="margin-bottom: 12px;">最近财务流水</h3>
|
||||
<table class="data-table">
|
||||
@@ -2039,7 +2238,7 @@ const InventoryView = {
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="movement in state.movements" :key="movement.id">
|
||||
<td>{{ movement.product_name }}</td>
|
||||
<td>{{ movement.product_name }}{{ movement.product_sku ? ' (' + movement.product_sku + ')' : '' }}</td>
|
||||
<td>
|
||||
<span :class="['badge', movement.movement_type === 'in' ? 'badge-success' : movement.movement_type === 'out' ? 'badge-error' : 'badge-warning']">
|
||||
{{ movement.movement_type === 'in' ? '入库' : movement.movement_type === 'out' ? '出库' : '调整' }}
|
||||
@@ -2158,12 +2357,20 @@ const InventoryView = {
|
||||
<!-- 入库表单 -->
|
||||
<form v-else-if="state.modalType === 'stockIn'" @submit.prevent="stockIn">
|
||||
<div class="form-group">
|
||||
<label class="form-label">产品ID *</label>
|
||||
<input v-model.number="state.form.product_id" type="number" class="form-input" required placeholder="产品ID" />
|
||||
<label class="form-label">产品 *</label>
|
||||
<select v-model.number="state.form.product_id" class="form-input" required>
|
||||
<option v-for="product in state.products" :key="'stockin-product-' + product.id" :value="product.id">
|
||||
{{ product.sku }} - {{ product.name }}(ID: {{ product.id }})
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">仓库ID *</label>
|
||||
<input v-model.number="state.form.warehouse_id" type="number" class="form-input" required placeholder="仓库ID (默认1)" />
|
||||
<label class="form-label">仓库 *</label>
|
||||
<select v-model.number="state.form.warehouse_id" class="form-input" required>
|
||||
<option v-for="warehouse in state.warehouses" :key="'stockin-warehouse-' + warehouse.id" :value="warehouse.id">
|
||||
{{ warehouse.name }}{{ warehouse.code ? ' (' + warehouse.code + ')' : '' }}{{ warehouse.is_default ? ' [默认]' : '' }}(ID: {{ warehouse.id }})
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">数量 *</label>
|
||||
@@ -2186,12 +2393,20 @@ const InventoryView = {
|
||||
<!-- 出库表单 -->
|
||||
<form v-else-if="state.modalType === 'stockOut'" @submit.prevent="stockOut">
|
||||
<div class="form-group">
|
||||
<label class="form-label">产品ID *</label>
|
||||
<input v-model.number="state.form.product_id" type="number" class="form-input" required placeholder="产品ID" />
|
||||
<label class="form-label">产品 *</label>
|
||||
<select v-model.number="state.form.product_id" class="form-input" required>
|
||||
<option v-for="product in state.products" :key="'stockout-product-' + product.id" :value="product.id">
|
||||
{{ product.sku }} - {{ product.name }}(ID: {{ product.id }})
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">仓库ID *</label>
|
||||
<input v-model.number="state.form.warehouse_id" type="number" class="form-input" required placeholder="仓库ID (默认1)" />
|
||||
<label class="form-label">仓库 *</label>
|
||||
<select v-model.number="state.form.warehouse_id" class="form-input" required>
|
||||
<option v-for="warehouse in state.warehouses" :key="'stockout-warehouse-' + warehouse.id" :value="warehouse.id">
|
||||
{{ warehouse.name }}{{ warehouse.code ? ' (' + warehouse.code + ')' : '' }}{{ warehouse.is_default ? ' [默认]' : '' }}(ID: {{ warehouse.id }})
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">数量 *</label>
|
||||
|
||||
Reference in New Issue
Block a user