From e449a5408265e4bd1f6c66f5be28a42efac444ee Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期日, 20 九月 2026 15:22:46 +0800
Subject: [PATCH] 天津豹鸣app 1.需求修改
---
src/pages/sales/receiptPaymentLedger/index.vue | 300 +++++++++++++++++++++++++++++++++++++++--------------------
1 files changed, 197 insertions(+), 103 deletions(-)
diff --git a/src/pages/sales/receiptPaymentLedger/index.vue b/src/pages/sales/receiptPaymentLedger/index.vue
index 7daa076..e038083 100644
--- a/src/pages/sales/receiptPaymentLedger/index.vue
+++ b/src/pages/sales/receiptPaymentLedger/index.vue
@@ -1,167 +1,261 @@
<template>
<view class="sales-account">
- <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
<PageHeader title="瀹㈡埛寰�鏉�"
@back="goBack" />
+
+ <!-- 缁熻鏉★紙闇�姹備竷锛氬簲鏀舵憳瑕侊級 -->
+ <view class="summary-strip">
+ <view class="summary-cell">
+ <text class="summary-num">{{ summary.totalProjects || 0 }}</text>
+ <text class="summary-cap">椤圭洰</text>
+ </view>
+ <view class="summary-cell">
+ <text class="summary-num">{{ summary.totalCustomers || 0 }}</text>
+ <text class="summary-cap">瀹㈡埛</text>
+ </view>
+ <view class="summary-cell">
+ <text class="summary-num">{{ summary.totalContracts || 0 }}</text>
+ <text class="summary-cap">鍚堝悓</text>
+ </view>
+ <view class="summary-cell">
+ <text class="summary-num">{{ fmtMoney(summary.totalAmount) }}</text>
+ <text class="summary-cap">绛剧害鎬婚</text>
+ </view>
+ <view class="summary-cell overdue">
+ <text class="summary-num">{{ summary.totalOverdueCount || 0 }}</text>
+ <text class="summary-cap">瓒�30澶╂湭鍥炴</text>
+ </view>
+ </view>
+
<!-- 鎼滅储鍖哄煙 -->
<view class="search-section">
<view class="search-bar">
<view class="search-input">
- <up-input class="search-text"
- placeholder="璇疯緭鍏ュ鎴峰悕绉�"
- v-model="searchForm.searchText"
- @change="searchChange"
- clearable />
+ <up-input v-model="query.projectName"
+ class="search-text"
+ placeholder="璇疯緭鍏ラ」鐩悕绉版悳绱�"
+ clearable
+ @change="getList" />
</view>
- <view class="search-button"
- @click="handleQuery">
- <up-icon name="search"
+ <view class="filter-button"
+ @click="showFilter = true">
+ <up-icon name="list"
size="24"
- color="#999"></up-icon>
+ color="#999" />
</view>
</view>
</view>
- <!-- 瀹㈡埛鍒楄〃 -->
- <view class="customer-list-container">
- <view class="customer-list"
- v-if="tableData.length > 0">
- <view v-for="(item, index) in tableData"
- :key="item.id"
- class="customer-item"
- @click="rowClickMethod(item)">
- <view class="item-header">
- <view class="item-left">
- <view class="customer-icon">
- <up-icon name="file-text"
- size="16"
- color="#ffffff"></up-icon>
- </view>
- <text class="customer-name">{{ item.customerName }}</text>
- </view>
- <view class="item-right">
- <up-icon name="arrow-right"
+
+ <!-- 椤圭洰鍒楄〃 -->
+ <view v-if="projectList.length > 0"
+ class="ledger-list">
+ <view v-for="item in projectList"
+ :key="item.projectId"
+ class="ledger-item"
+ @click="goDetail(item)">
+ <view class="item-header">
+ <view class="item-left">
+ <view class="document-icon">
+ <up-icon name="file-text"
size="16"
- color="#999"></up-icon>
+ color="#ffffff" />
</view>
+ <text class="item-id">{{ item.projectName || "-" }}</text>
</view>
- <up-divider></up-divider>
- <view class="item-details">
- <view class="detail-row">
- <text class="detail-label">寮�绁ㄩ噾棰�(鍏�)</text>
- <text class="detail-value">{{ formattedNumber(item.invoiceTotal) }}</text>
- </view>
- <view class="detail-row">
- <text class="detail-label">鍥炴閲戦(鍏�)</text>
- <text class="detail-value">{{ formattedNumber(item.receiptPaymentAmount) }}</text>
- </view>
- <view class="detail-row">
- <text class="detail-label">搴旀敹閲戦(鍏�)</text>
- <text class="detail-value highlight danger">{{ formattedNumber(item.unReceiptPaymentAmount) }}</text>
- </view>
+ <up-tag :text="overdueText(item.overdueCount)"
+ :type="item.overdueCount > 0 ? 'error' : 'success'"
+ size="mini"
+ shape="circle" />
+ </view>
+ <up-divider></up-divider>
+ <view class="item-details">
+ <view class="detail-row">
+ <text class="detail-label">椤圭洰缂栧彿</text>
+ <text class="detail-value">{{ item.projectCode || "-" }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">绛剧害鎬婚</text>
+ <text class="detail-value highlight">{{ fmtMoney(item.contractAmounts) }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">寮�绁ㄩ噾棰�</text>
+ <text class="detail-value">{{ fmtMoney(item.invoiceAmount) }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍥炴閲戦</text>
+ <text class="detail-value highlight">{{ fmtMoney(item.receiptPaymentAmount) }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">搴旀敹閲戦</text>
+ <text class="detail-value danger">{{ fmtMoney(item.receiptableAmount) }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">閫�璐ч噾棰�</text>
+ <text class="detail-value">{{ fmtMoney(item.returnAmount) }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍥炴杩涘害</text>
+ <text class="detail-value"
+ :class="{ danger: item.overdueCount > 0 }">
+ {{ calcRate(item.receiptPaymentAmount, item.contractAmounts) }}%
+ </text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">瀹㈡埛 / 鍚堝悓</text>
+ <text class="detail-value">{{ item.customerCount || 0 }} 瀹� / {{ item.contractCount || 0 }} 浠�</text>
</view>
</view>
- </view>
- <view v-else
- class="no-data">
- <text>鏆傛棤瀹㈡埛鏁版嵁</text>
+ <view class="action-buttons">
+ <up-button class="action-btn"
+ size="small"
+ type="primary"
+ @click.stop="goDetail(item)">鏌ョ湅瀹㈡埛寰�鏉�</up-button>
+ </view>
</view>
</view>
+ <view v-else
+ class="no-data">
+ <text>鏆傛棤椤圭洰寰�鏉ユ暟鎹�</text>
+ </view>
+
+ <FilterPanel v-model:show="showFilter"
+ :model-value="query"
+ title="瀹㈡埛寰�鏉ョ瓫閫�"
+ :fields="filterFields"
+ @search="onFilterSearch"
+ @reset="onFilterSearch" />
</view>
</template>
<script setup>
- import { onMounted, ref, reactive, toRefs } from "vue";
+ import { reactive, ref, onMounted } from "vue";
import { onShow } from "@dcloudio/uni-app";
- import { invoiceLedgerSalesAccount } from "@/api/salesManagement/invoiceLedger";
+ import PageHeader from "@/components/PageHeader.vue";
+ import FilterPanel from "@/components/FilterPanel.vue";
+ import {
+ projectTransactions,
+ transactionsSummary,
+ } from "@/api/salesManagement/indicatorStats";
+ import { unwrapList } from "@/utils/list";
- const tableData = ref([]);
+ const projectList = ref([]);
+ const summary = ref({});
+ const showFilter = ref(false);
- const page = reactive({
- current: -1,
- size: -1,
+ const query = reactive({
+ projectName: "",
+ customerName: "",
+ contractName: "",
});
- const data = reactive({
- searchForm: {
- searchText: "",
- invoiceDate: "",
- },
- });
+ const filterFields = [
+ { prop: "customerName", label: "瀹㈡埛鍚嶇О", type: "input", placeholder: "璇疯緭鍏ュ鎴峰悕绉�" },
+ { prop: "contractName", label: "鍚堝悓鍚嶇О", type: "input", placeholder: "璇疯緭鍏ュ悎鍚屽悕绉�" },
+ ];
- const { searchForm } = toRefs(data);
-
- // 杩斿洖涓婁竴椤�
const goBack = () => {
uni.navigateBack();
};
- // 鎼滅储妗嗗彉鍖栨椂瑙﹀彂
- const searchChange = val => {
- searchForm.value.searchText = val;
- getList();
- };
- // 鏌ヨ鍒楄〃
- const handleQuery = () => {
- getList();
- };
const getList = () => {
- showLoadingToast("鍔犺浇涓�...");
- invoiceLedgerSalesAccount({ ...searchForm.value, ...page })
+ uni.showLoading({ title: "鍔犺浇涓�...", mask: true });
+ const params = { ...query, current: -1, size: -1 };
+ projectTransactions(params)
.then(res => {
- tableData.value = res.data.records;
- closeToast();
+ projectList.value = unwrapList(res);
+ uni.hideLoading();
})
.catch(() => {
- closeToast();
- uni.showToast({
- title: "鏌ヨ澶辫触",
- icon: "error",
- });
+ uni.hideLoading();
+ uni.showToast({ title: "鏌ヨ澶辫触", icon: "none" });
});
};
- const formattedNumber = value => {
- return parseFloat(value || 0).toFixed(2);
+ const getSummary = () => {
+ transactionsSummary()
+ .then(res => {
+ summary.value = res.data || {};
+ })
+ .catch(() => {});
};
- // 鏄剧ず鍔犺浇鎻愮ず
- const showLoadingToast = message => {
- uni.showLoading({
- title: message,
- mask: true,
- });
+ const onFilterSearch = values => {
+ Object.assign(query, values || {});
+ getList();
};
- // 鍏抽棴鎻愮ず
- const closeToast = () => {
- uni.hideLoading();
- };
-
- const rowClickMethod = row => {
- // 浣跨敤 uni.setStorageSync 瀛樺偍瀹㈡埛淇℃伅
- uni.setStorageSync("customerId", row.id);
- // 璺宠浆鍒板洖娆捐褰曟槑缁嗛〉闈�
+ const goDetail = item => {
+ if (!item?.projectId) return;
uni.navigateTo({
- url: "/pages/sales/receiptPaymentLedger/detail",
+ url: `/pages/sales/receiptPaymentLedger/detail?projectId=${item.projectId}`
+ + `&projectName=${encodeURIComponent(item.projectName || "")}`,
});
+ };
+
+ const overdueText = count => (count > 0 ? `${count} 浠借秴鏈焋 : "姝e父灞ョ害");
+
+ const fmtMoney = value => {
+ const num = Number(value);
+ if (!Number.isFinite(num)) return "楼 0.00";
+ return "楼 " + num.toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
+ };
+
+ const calcRate = (paid, amount) => {
+ const total = Number(amount);
+ if (!Number.isFinite(total) || total === 0) return "0.0";
+ return (((Number(paid) || 0) / total) * 100).toFixed(1);
};
onShow(() => {
- // 椤甸潰鏄剧ず鏃跺埛鏂板垪琛�
getList();
+ getSummary();
});
onMounted(() => {
getList();
+ getSummary();
});
</script>
<style scoped lang="scss">
@import "@/styles/sales-common.scss";
- // 瀹㈡埛寰�鏉ョ壒鏈夋牱寮�
+ .summary-strip {
+ display: flex;
+ flex-wrap: wrap;
+ background: #ffffff;
+ margin: 12px 12px 0;
+ border-radius: 12px;
+ padding: 12px 8px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+ }
+
+ .summary-cell {
+ flex: 1 0 33%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 6px 0;
+ }
+
+ .summary-num {
+ font-size: 16px;
+ font-weight: 600;
+ color: #333333;
+ }
+
+ .summary-cap {
+ font-size: 11px;
+ color: #909399;
+ margin-top: 2px;
+ }
+
+ .summary-cell.overdue .summary-num {
+ color: #ff4757;
+ }
+
.detail-value.danger {
- color: #ff4757; // 涓庡叕鍏辨牱寮忎腑鐨� #ee0a24 涓嶅悓
+ color: #ff4757;
font-weight: 500;
}
-</style>
\ No newline at end of file
+</style>
--
Gitblit v1.9.3