From abb1971cd5eeab76736dcf402f804098929ac7bc Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 17 三月 2026 16:59:06 +0800
Subject: [PATCH] 军泰伟业app 1.添加营销管理模块和采购管理模块并联调 2.添加协同办公模块
---
src/pages/sales/deliveryLedger/index.vue | 785 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 785 insertions(+), 0 deletions(-)
diff --git a/src/pages/sales/deliveryLedger/index.vue b/src/pages/sales/deliveryLedger/index.vue
new file mode 100644
index 0000000..e968aa9
--- /dev/null
+++ b/src/pages/sales/deliveryLedger/index.vue
@@ -0,0 +1,785 @@
+<template>
+ <view class="delivery-ledger">
+ <!-- 椤甸潰澶撮儴 -->
+ <PageHeader title="鍙戣揣鍙拌处" @back="goBack" />
+
+ <!-- 鎼滅储鍖哄煙 -->
+ <view class="search-section">
+ <view class="search-bar">
+ <view class="search-input">
+ <up-input
+ class="search-text"
+ placeholder="璇疯緭鍏ラ攢鍞鍗曞彿"
+ v-model="searchForm.salesContractNo"
+ @change="handleQuery"
+ clearable
+ />
+ </view>
+ <view class="search-input">
+ <up-input
+ class="search-text"
+ placeholder="璇疯緭鍏ュ鎴峰悕绉�"
+ v-model="searchForm.customerName"
+ @change="handleQuery"
+ clearable
+ />
+ </view>
+ <view class="filter-button" @click="handleQuery">
+ <up-icon name="search" size="24" color="#999"></up-icon>
+ </view>
+ </view>
+ </view>
+
+ <!-- 鍙戣揣鍙拌处鍒楄〃 -->
+ <view class="ledger-list" v-if="tableData.length > 0">
+ <view v-for="(item, index) in tableData" :key="index">
+ <view class="ledger-item" @click="openDetail(item)">
+ <view class="item-header">
+ <view class="item-left">
+ <view class="document-icon">
+ <up-icon name="file-text" size="16" color="#ffffff"></up-icon>
+ </view>
+ <text class="item-id">{{ item.salesContractNo }}</text>
+ </view>
+ <u-tag
+ size="mini"
+ :type="getApprovalStatusType(item.status)"
+ >{{ getApprovalStatusText(item.status) }}</u-tag>
+ </view>
+ <up-divider></up-divider>
+ <view class="item-details">
+ <view class="detail-row">
+ <text class="detail-label">鍙戣揣璁㈠崟鍙�</text>
+ <text class="detail-value">{{ item.shippingNo || '--' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">瀹㈡埛鍚嶇О</text>
+ <text class="detail-value">{{ item.customerName }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍙戣揣杩涘害</text>
+ <view class="progress-wrapper">
+ <up-line-progress
+ :percentage="getShippingProgress(item)"
+ :active-color="getProgressColor(item)"
+ height="8"
+ ></up-line-progress>
+ <text class="progress-text">{{ getShippingProgress(item) }}%</text>
+ </view>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鎬诲彂璐ф暟閲�</text>
+ <text class="detail-value">{{ item.shippingTotal || 0 }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">宸插彂璐ф暟閲�</text>
+ <text class="detail-value success">{{ item.shippingSuccessTotal || 0 }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">寰呭彂璐ф暟閲�</text>
+ <text class="detail-value warning">{{ item.waitShippingTotal || 0 }}</text>
+ </view>
+ </view>
+ </view>
+ </view>
+ </view>
+ <view v-else class="no-data">
+ <up-empty mode="list" text="鏆傛棤鍙戣揣鍙拌处鏁版嵁"></up-empty>
+ </view>
+
+ <!-- 鍙戣揣璇︽儏寮圭獥 -->
+ <u-popup
+ :show="dialogFormVisible"
+ mode="bottom"
+ :round="16"
+ :closeable="true"
+ @close="closeDia"
+ >
+ <view class="popup-content">
+ <view class="popup-header">
+ <text class="popup-title">鍙戣揣鍙拌处璇︽儏</text>
+ </view>
+ <scroll-view scroll-y class="popup-body">
+ <view v-if="currentShippingOrder" class="shipping-container">
+ <!-- 璁㈠崟淇℃伅鍗$墖 -->
+ <view class="info-card">
+ <view class="card-header">
+ <text class="card-title">璁㈠崟淇℃伅</text>
+ <u-tag
+ size="mini"
+ :type="getProgressColor(currentShippingOrder) === '#67C23A' ? 'success' : 'warning'"
+ >{{ getShippingProgress(currentShippingOrder) }}%</u-tag>
+ </view>
+ <view class="card-body">
+ <view class="info-row">
+ <text class="info-label">閿�鍞鍗�</text>
+ <text class="info-value">{{ currentShippingOrder.salesContractNo || '--' }}</text>
+ </view>
+ <view class="info-row">
+ <text class="info-label">瀹㈡埛鍚嶇О</text>
+ <text class="info-value">{{ currentShippingOrder.customerName || '--' }}</text>
+ </view>
+ <view class="info-row">
+ <text class="info-label">鍙戣揣璁㈠崟鍙�</text>
+ <text class="info-value">{{ currentShippingOrder.shippingNo || '--' }}</text>
+ </view>
+ <up-divider></up-divider>
+ <view class="quantity-summary">
+ <view class="summary-item">
+ <text class="summary-label">鎬诲彂璐ф暟閲�</text>
+ <text class="summary-value total">{{ currentShippingOrder.shippingTotal || 0 }}</text>
+ </view>
+ <view class="summary-item">
+ <text class="summary-label">宸插彂璐ф暟閲�</text>
+ <text class="summary-value shipped">{{ currentShippingOrder.shippingSuccessTotal || 0 }}</text>
+ </view>
+ <view class="summary-item">
+ <text class="summary-label">寰呭彂璐ф暟閲�</text>
+ <text class="summary-value waiting">{{ currentShippingOrder.waitShippingTotal || 0 }}</text>
+ </view>
+ </view>
+ <view class="progress-wrapper">
+ <up-line-progress
+ :percentage="getShippingProgress(currentShippingOrder)"
+ :active-color="getProgressColor(currentShippingOrder)"
+ height="12"
+ ></up-line-progress>
+ </view>
+ </view>
+ </view>
+
+ <!-- 鍙戣揣璁板綍鍗$墖 -->
+ <view class="records-card">
+ <view class="card-header">
+ <text class="card-title">鍙戣揣璁板綍</text>
+ <text class="record-count">鍏� {{ shippingRecords.length }} 鏉¤褰�</text>
+ </view>
+ <view class="card-body">
+ <view v-if="shippingRecords.length === 0" class="empty-state">
+ <up-empty mode="list" text="鏆傛棤鍙戣揣璁板綍"></up-empty>
+ </view>
+ <view v-else class="records-list">
+ <view
+ v-for="(record, index) in shippingRecords"
+ :key="record.id || index"
+ class="record-item"
+ >
+ <view class="record-header">
+ <u-tag
+ size="mini"
+ :type="record.type === '璐ц溅' ? 'primary' : 'success'"
+ >{{ record.type }}</u-tag>
+ <text class="record-date">{{ record.shippingDate }}</text>
+ </view>
+ <view class="record-body">
+ <view class="record-info-row">
+ <text class="record-info-label">鍙戣揣鏁伴噺</text>
+ <text class="record-info-value quantity">{{ record.shippingNum }}</text>
+ </view>
+ <view class="record-info-row" v-if="record.type === '璐ц溅'">
+ <text class="record-info-label">杞︾墝鍙�</text>
+ <text class="record-info-value">{{ record.shippingCarNumber || '--' }}</text>
+ </view>
+ <view class="record-info-row" v-else>
+ <text class="record-info-label">蹇�掑叕鍙�</text>
+ <text class="record-info-value">{{ record.expressCompany || '--' }}</text>
+ </view>
+ <view class="record-info-row" v-if="record.type === '蹇��'">
+ <text class="record-info-label">蹇�掑崟鍙�</text>
+ <text class="record-info-value">{{ record.expressNumber || '--' }}</text>
+ </view>
+ <view class="record-info-row" v-if="record.commonFileList && record.commonFileList.length > 0">
+ <text class="record-info-label">鍙戣揣鍥剧墖</text>
+ <view class="record-images">
+ <image
+ v-for="(file, imgIndex) in record.commonFileList"
+ :key="imgIndex"
+ :src="normalizeFileUrl(file?.url)"
+ mode="aspectFill"
+ class="record-image"
+ @click="previewImage(record.commonFileList, imgIndex)"
+ />
+ </view>
+ </view>
+ </view>
+ </view>
+ </view>
+ </view>
+ </view>
+ </view>
+ </scroll-view>
+ <view class="popup-footer">
+ <u-button @click="closeDia">鍏抽棴</u-button>
+ </view>
+ </view>
+ </u-popup>
+ </view>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import { onShow } from "@dcloudio/uni-app";
+import PageHeader from "@/components/PageHeader.vue";
+import {
+ deliveryLedgerListPage,
+ shippingInfoDetailListPage,
+} from "@/api/salesManagement/deliveryLedger.js";
+
+// 琛ㄦ牸鏁版嵁
+const tableData = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+ current: 1,
+ size: 100,
+});
+const total = ref(0);
+const javaApi = import.meta.env.VITE_APP_BASE_API;
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+ salesContractNo: "",
+ customerName: "",
+});
+
+// 鍙戣揣璇︽儏寮规
+const dialogFormVisible = ref(false);
+const currentShippingOrder = ref(null);
+const shippingRecords = ref([]);
+const shippingRecordsLoading = ref(false);
+
+// 杩斿洖涓婁竴椤�
+const goBack = () => {
+ uni.navigateBack();
+};
+
+// 鏄剧ず鍔犺浇鎻愮ず
+const showLoadingToast = (message) => {
+ uni.showLoading({
+ title: message,
+ mask: true,
+ });
+};
+
+// 鍏抽棴鎻愮ず
+const closeToast = () => {
+ uni.hideLoading();
+};
+
+// 鏌ヨ鍒楄〃
+const handleQuery = () => {
+ page.current = 1;
+ getList();
+};
+
+const getList = () => {
+ tableLoading.value = true;
+ showLoadingToast("鍔犺浇涓�...");
+ deliveryLedgerListPage({ ...searchForm, ...page })
+ .then((res) => {
+ tableData.value = res.data.records || [];
+ total.value = res.data.total || 0;
+ closeToast();
+ tableLoading.value = false;
+ })
+ .catch(() => {
+ closeToast();
+ tableLoading.value = false;
+ });
+};
+
+// 鎵撳紑璇︽儏寮规
+const openDetail = async (row) => {
+ currentShippingOrder.value = row;
+ await loadShippingRecords(row.id);
+ dialogFormVisible.value = true;
+};
+
+// 鍔犺浇鍙戣揣璁板綍
+const loadShippingRecords = async (shippingInfoId) => {
+ shippingRecordsLoading.value = true;
+ try {
+ const res = await shippingInfoDetailListPage({ shippingInfoId, current: 1, size: 100 });
+ shippingRecords.value = res.data.records || [];
+ } catch (error) {
+ shippingRecords.value = [];
+ } finally {
+ shippingRecordsLoading.value = false;
+ }
+};
+
+// 鍏抽棴寮规
+const closeDia = () => {
+ dialogFormVisible.value = false;
+ currentShippingOrder.value = null;
+ shippingRecords.value = [];
+};
+
+// 鏂囦欢URL澶勭悊
+const normalizeFileUrl = (rawUrl = '') => {
+ let fileUrl = rawUrl || '';
+ if (fileUrl && fileUrl.indexOf('\\') > -1) {
+ const uploadsIndex = fileUrl.toLowerCase().indexOf('uploads');
+ if (uploadsIndex > -1) {
+ const relativePath = fileUrl.substring(uploadsIndex).replace(/\\/g, '/');
+ fileUrl = '/' + relativePath;
+ } else {
+ const parts = fileUrl.split('\\');
+ const fileName = parts[parts.length - 1];
+ fileUrl = '/uploads/' + fileName;
+ }
+ }
+ if (fileUrl && !fileUrl.startsWith('http')) {
+ if (!fileUrl.startsWith('/')) fileUrl = '/' + fileUrl;
+ fileUrl = javaApi + fileUrl;
+ }
+ return fileUrl;
+};
+
+// 棰勮鍥剧墖
+const previewImage = (fileList, currentIndex) => {
+ const urls = fileList.map((f) => normalizeFileUrl(f?.url));
+ uni.previewImage({
+ urls: urls,
+ current: currentIndex,
+ });
+};
+
+// 鑾峰彇鍙戣揣杩涘害鐧惧垎姣�
+const getShippingProgress = (row) => {
+ const shipped = row.shippingSuccessTotal || 0;
+ const total = shipped + (row.waitShippingTotal || 0);
+ if (total === 0) return 0;
+ return Math.round((shipped / total) * 100);
+};
+
+// 鑾峰彇杩涘害鏉¢鑹�
+const getProgressColor = (row) => {
+ const progress = getShippingProgress(row);
+ if (progress === 100) return '#67C23A';
+ if (progress >= 50) return '#E6A23C';
+ return '#2979ff';
+};
+
+// 鑾峰彇瀹℃牳鐘舵�佹枃鏈�
+const getApprovalStatusText = (status) => {
+ if (status === null || status === undefined || status === '') {
+ return '寰呭鏍�';
+ }
+ if (typeof status === 'number') {
+ const statusMap = {
+ 0: '寰呭鏍�',
+ 1: '瀹℃牳涓�',
+ 2: '瀹℃牳鎷掔粷',
+ 3: '瀹℃牳閫氳繃'
+ };
+ return statusMap[status] || '寰呭鏍�';
+ }
+ const statusStr = String(status).trim();
+ const statusTextMap = {
+ '寰呭鏍�': '寰呭鏍�',
+ '瀹℃牳涓�': '瀹℃牳涓�',
+ '瀹℃牳鎷掔粷': '瀹℃牳鎷掔粷',
+ '瀹℃牳閫氳繃': '瀹℃牳閫氳繃',
+ '0': '寰呭鏍�',
+ '1': '瀹℃牳涓�',
+ '2': '瀹℃牳鎷掔粷',
+ '3': '瀹℃牳閫氳繃'
+ };
+ return statusTextMap[statusStr] || statusStr || '寰呭鏍�';
+};
+
+// 鑾峰彇瀹℃牳鐘舵�佹爣绛剧被鍨�
+const getApprovalStatusType = (status) => {
+ if (status === null || status === undefined || status === '') {
+ return 'info';
+ }
+ if (typeof status === 'number') {
+ const typeMap = {
+ 0: 'info',
+ 1: 'warning',
+ 2: 'error',
+ 3: 'success'
+ };
+ return typeMap[status] || 'info';
+ }
+ const statusStr = String(status).trim();
+ const typeTextMap = {
+ '寰呭鏍�': 'info',
+ '瀹℃牳涓�': 'warning',
+ '瀹℃牳鎷掔粷': 'error',
+ '瀹℃牳閫氳繃': 'success',
+ '0': 'info',
+ '1': 'warning',
+ '2': 'error',
+ '3': 'success'
+ };
+ return typeTextMap[statusStr] || 'info';
+};
+
+onShow(() => {
+ getList();
+});
+</script>
+
+<style scoped lang="scss">
+.delivery-ledger {
+ min-height: 100vh;
+ background: #f8f9fa;
+ position: relative;
+}
+
+// 鎼滅储鍖哄煙
+.search-section {
+ padding: 10px 20px;
+ background: #ffffff;
+}
+
+.search-bar {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ flex-wrap: wrap;
+}
+
+.search-input {
+ flex: 1;
+ min-width: 140px;
+ background: #f5f5f5;
+ border-radius: 24px;
+ padding: 0 16px;
+ display: flex;
+ align-items: center;
+}
+
+.search-text {
+ flex: 1;
+ font-size: 14px;
+ color: #333;
+ background: transparent;
+ border: none;
+ outline: none;
+
+ &::placeholder {
+ color: #999;
+ }
+}
+
+.filter-button {
+ width: 40px;
+ height: 40px;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #f5f5f5;
+}
+
+// 鍒楄〃鍖哄煙
+.ledger-list {
+ padding: 20px;
+}
+
+.ledger-item {
+ background: #ffffff;
+ border-radius: 12px;
+ margin-bottom: 16px;
+ overflow: hidden;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+ padding: 0 16px;
+
+ &:active {
+ transform: scale(0.98);
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+ }
+}
+
+.item-header {
+ padding: 16px 0;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.item-left {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.document-icon {
+ width: 24px;
+ height: 24px;
+ background: #2979ff;
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.item-id {
+ font-size: 14px;
+ color: #333;
+ font-weight: 500;
+}
+
+.item-details {
+ padding: 16px 0;
+}
+
+.detail-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 8px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+}
+
+.detail-label {
+ font-size: 12px;
+ color: #777777;
+ min-width: 60px;
+}
+
+.detail-value {
+ font-size: 12px;
+ color: #000000;
+ text-align: right;
+ flex: 1;
+ margin-left: 16px;
+
+ &.success {
+ color: #67C23A;
+ font-weight: 500;
+ }
+
+ &.warning {
+ color: #E6A23C;
+ font-weight: 500;
+ }
+}
+
+.progress-wrapper {
+ flex: 1;
+ margin-left: 16px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+
+ .progress-text {
+ font-size: 12px;
+ color: #666;
+ min-width: 36px;
+ text-align: right;
+ }
+}
+
+.no-data {
+ padding: 40px 20px;
+ text-align: center;
+ color: #999;
+}
+
+// 寮圭獥鏍峰紡
+.popup-content {
+ max-height: 80vh;
+ display: flex;
+ flex-direction: column;
+}
+
+.popup-header {
+ padding: 16px;
+ border-bottom: 1px solid #eee;
+ text-align: center;
+
+ .popup-title {
+ font-size: 16px;
+ font-weight: 500;
+ color: #333;
+ }
+}
+
+.popup-body {
+ flex: 1;
+ padding: 16px;
+ max-height: 60vh;
+}
+
+.popup-footer {
+ padding: 16px;
+ border-top: 1px solid #eee;
+ display: flex;
+ gap: 12px;
+
+ :deep(.u-button) {
+ flex: 1;
+ }
+}
+
+// 鍗$墖鏍峰紡
+.info-card,
+.records-card {
+ background: #ffffff;
+ border-radius: 12px;
+ margin-bottom: 16px;
+ overflow: hidden;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+}
+
+.card-header {
+ padding: 16px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px solid #f5f5f5;
+
+ .card-title {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+ }
+
+ .record-count {
+ font-size: 12px;
+ color: #999;
+ }
+}
+
+.card-body {
+ padding: 16px;
+}
+
+// 璁㈠崟淇℃伅
+.info-row {
+ display: flex;
+ justify-content: space-between;
+ padding: 8px 0;
+
+ .info-label {
+ color: #666;
+ font-size: 14px;
+ }
+
+ .info-value {
+ color: #333;
+ font-weight: 500;
+ font-size: 14px;
+ }
+}
+
+.quantity-summary {
+ display: flex;
+ justify-content: space-between;
+ margin: 16px 0;
+
+ .summary-item {
+ text-align: center;
+ flex: 1;
+
+ .summary-label {
+ font-size: 12px;
+ color: #999;
+ margin-bottom: 8px;
+ display: block;
+ }
+
+ .summary-value {
+ font-size: 20px;
+ font-weight: bold;
+
+ &.total {
+ color: #2979ff;
+ }
+
+ &.shipped {
+ color: #67C23A;
+ }
+
+ &.waiting {
+ color: #E6A23C;
+ }
+ }
+ }
+}
+
+// 鍙戣揣璁板綍
+.empty-state {
+ padding: 40px 0;
+}
+
+.records-list {
+ .record-item {
+ border: 1px solid #eee;
+ border-radius: 8px;
+ padding: 12px;
+ margin-bottom: 12px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+
+ .record-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 12px;
+ padding-bottom: 12px;
+ border-bottom: 1px solid #f5f5f5;
+
+ .record-date {
+ font-size: 12px;
+ color: #999;
+ }
+ }
+
+ .record-body {
+ .record-info-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 8px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .record-info-label {
+ font-size: 12px;
+ color: #999;
+ }
+
+ .record-info-value {
+ font-size: 14px;
+ color: #333;
+
+ &.quantity {
+ font-weight: bold;
+ color: #2979ff;
+ font-size: 16px;
+ }
+ }
+ }
+
+ .record-images {
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
+ margin-top: 8px;
+
+ .record-image {
+ width: 60px;
+ height: 60px;
+ border-radius: 4px;
+ }
+ }
+ }
+}
+
+// 闅愯棌uview-plus鐨勬煇浜涢粯璁ゆ牱寮�
+:deep(.u-divider) {
+ margin: 8px 0 !important;
+}
+</style>
--
Gitblit v1.9.3