From 2067eae94e40c990f3c7c5160a46c7f8954d04a7 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 25 八月 2025 18:01:12 +0800
Subject: [PATCH] 1.回款流水开发联调

---
 src/pages/procurementManagement/procurementInvoiceLedger/detail.vue |  292 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 292 insertions(+), 0 deletions(-)

diff --git a/src/pages/procurementManagement/procurementInvoiceLedger/detail.vue b/src/pages/procurementManagement/procurementInvoiceLedger/detail.vue
new file mode 100644
index 0000000..ec31d69
--- /dev/null
+++ b/src/pages/procurementManagement/procurementInvoiceLedger/detail.vue
@@ -0,0 +1,292 @@
+<template>
+	<view class="account-detail">
+		<!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+		<PageHeader title="缂栬緫鏉ョエ鍙拌处" @back="goBack" />
+
+		<van-form @submit="submitForm" ref="formRef" label-width="120px" input-align="right" error-message-align="right" scroll-to-error scroll-to-error-position="center">
+			<van-cell-group title="鍩烘湰淇℃伅" inset>
+				<van-field v-model="form.purchaseContractNumber" label="閲囪喘鍚堝悓鍙�" readonly />
+				<van-field v-model="form.salesContractNo" label="閿�鍞悎鍚屽彿" readonly />
+				<van-field v-model="form.taxInclusiveUnitPrice" label="鍚◣鍗曚环(鍏�)" readonly />
+				<van-field v-model="form.createdAt" label="鍒涘缓鏃堕棿" readonly />
+				<van-field v-model="form.invoiceNumber" label="鍙戠エ鍙�" placeholder="璇疯緭鍏�" readonly />
+				<van-field v-model="form.ticketsNum" label="鏉ョエ鏁�" type="number" placeholder="璇疯緭鍏�" required :rules="[{ required: true, message: '璇疯緭鍏ユ潵绁ㄦ暟' }]" @change="inputTicketsNum"/>
+				<van-field v-model="form.ticketsAmount" label="鏈鏉ョエ閲戦(鍏�)" type="number" placeholder="璇疯緭鍏�" required :rules="[{ required: true, message: '璇疯緭鍏ユ湰娆℃潵绁ㄩ噾棰�' }]" @change="inputTicketsAmount"/>
+				<view class="tip-text">鏈潵绁ㄦ暟锛歿{ formatAmount(form.futureTickets) }} 鍏�</view>
+<!--				<van-field v-model="form.invoicePerson" label="鏈潵绁ㄦ暟" readonly />-->
+			</van-cell-group>
+
+<!--			<van-cell-group title="闄勪欢鏉愭枡锛堜粎鏀寔 pdf锛�" inset>-->
+<!--				<van-uploader-->
+<!--					accept=".pdf"-->
+<!--					multiple-->
+<!--					:after-read="afterReadUpload"-->
+<!--					:before-read="beforeReadPdf"-->
+<!--				>-->
+<!--					<van-button class="upload-btn" icon="plus" type="primary" block>涓婁紶鏂囦欢</van-button>-->
+<!--				</van-uploader>-->
+<!--				<view class="uploaded-list" v-if="fileList.length">-->
+<!--					<view class="uploaded-item" v-for="(f, idx) in fileList" :key="idx">-->
+<!--						<text class="file-name">{{ f.name || getFileNameFromUrl(f.url) }}</text>-->
+<!--						<van-button size="mini" type="danger" plain @click="removeUploaded(idx)">绉婚櫎</van-button>-->
+<!--					</view>-->
+<!--				</view>-->
+<!--			</van-cell-group>-->
+
+			<view class="footer-btns">
+				<van-button class="cancel-btn" @click="goBack">鍙栨秷</van-button>
+				<van-button class="save-btn" native-type="submit" form-type="submit">淇濆瓨</van-button>
+			</view>
+		</van-form>
+	</view>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { showToast, showLoadingToast, closeToast } from 'vant'
+import dayjs from 'dayjs'
+import useUserStore from '@/store/modules/user'
+import { getToken } from '@/utils/auth'
+import { invoiceLedgerSaveOrUpdate } from '@/api/salesManagement/invoiceLedger.js'
+import config from '@/config.js'
+import {getProductRecordById, updateRegistration} from "@/api/procurementManagement/procurementInvoiceLedger";
+
+const userStore = useUserStore()
+
+const formRef = ref()
+let form = ref({
+	salesLedgerId: '',
+	customerId: '',
+	invoiceNo: '',
+	invoiceTotal: '',
+	taxRate: '',
+	invoicePerson: '',
+	invoiceDate: '',
+	customerName: '',
+	fileList: [],
+	createTime: '',
+	taxInclusiveTotalPrice: '',
+	taxInclusiveUnitPrice: ''
+})
+const fileList = ref([])
+const currentId = ref('')
+const temFutureTickets = ref(0)
+
+// 鏃ユ湡閫夋嫨
+const currentInvoiceDate = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()])
+
+const goBack = () => {
+	uni.removeStorageSync('invoiceLedgerEditRow');
+	uni.navigateBack()
+}
+const inputTicketsNum = (val) => {
+	// 纭繚鍚◣鍗曚环瀛樺湪涓斾笉涓洪浂
+	if (!form.value.taxInclusiveUnitPrice || Number(form.value.taxInclusiveUnitPrice) === 0) {
+		showToast("鍚◣鍗曚环涓嶈兘涓洪浂鎴栨湭瀹氫箟");
+		return;
+	}
+	if (Number(form.value.ticketsNum) > Number(temFutureTickets.value)) {
+		showToast("鏉ョエ鏁颁笉寰楀ぇ浜庢湭鏉ョエ鏁�");
+		form.value.ticketsNum = temFutureTickets.value
+	}
+	
+	// 纭繚鎵�鏈夋暟鍊奸兘杞崲涓烘暟瀛楃被鍨嬭繘琛岃绠�
+	const ticketsAmount = Number(form.value.ticketsNum) * Number(form.value.taxInclusiveUnitPrice);
+	const futureTickets = Number(temFutureTickets.value) - Number(form.value.ticketsNum);
+	form.value.futureTickets = Number(futureTickets.toFixed(2));
+	form.value.ticketsAmount = Number(ticketsAmount.toFixed(2));
+};
+const inputTicketsAmount = (val) => {
+	// 纭繚鍚◣鍗曚环瀛樺湪涓斾笉涓洪浂
+	if (!form.value.taxInclusiveUnitPrice || Number(form.value.taxInclusiveUnitPrice) === 0) {
+		showToast("鍚◣鍗曚环涓嶈兘涓洪浂鎴栨湭瀹氫箟");
+		return;
+	}
+	
+	if (Number(val) > Number(form.value.futureTickets*form.value.taxInclusiveUnitPrice)) {
+		showToast("鏈鏉ョエ閲戦涓嶅緱澶т簬鎬婚噾棰�");
+		form.value.ticketsAmount = (form.value.futureTickets*form.value.taxInclusiveUnitPrice).toFixed(2)
+		const ticketsNum = Number(form.value.ticketsAmount) / Number(form.value.taxInclusiveUnitPrice);
+		form.value.ticketsNum = Number(ticketsNum.toFixed(2))
+		return;
+	}
+	
+	// 纭繚鎵�鏈夋暟鍊奸兘杞崲涓烘暟瀛楃被鍨嬭繘琛岃绠�
+	const ticketsNum = Number(val) / Number(form.value.taxInclusiveUnitPrice);
+	form.value.ticketsNum = Number(ticketsNum.toFixed(2));
+};
+const formatAmount = (val) => {
+	if (val === undefined || val === null || val === '') return '0.00'
+	const num = Number(val)
+	if (Number.isNaN(num)) return '0.00'
+	return num.toFixed(2)
+}
+
+// 涓婁紶鍓嶆牎楠岋紙鍏煎 Vant Uploader 鐨� file/fileList 缁撴瀯锛�
+const beforeReadPdf = (file) => {
+	const items = Array.isArray(file) ? file : [file]
+	for (const it of items) {
+		const raw = it?.file || it
+		const fileName = raw?.name || it?.name || ''
+		const ext = fileName.split('.').pop()?.toLowerCase()
+		const sizeOk = (raw?.size || 0) <= 10 * 1024 * 1024
+		if (ext !== 'pdf') {
+			showToast('浠呮敮鎸乸df鏂囦欢')
+			return false
+		}
+		if (!sizeOk) {
+			showToast('涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃10MB')
+			return false
+		}
+	}
+	return true
+}
+
+const uploadSingleFile = async (fileObj) => {
+	return new Promise((resolve, reject) => {
+		showLoadingToast({ message: '姝e湪涓婁紶...' })
+		const baseUrl = config.baseUrl + '/invoiceLedger/uploadFile'
+
+		const filePath = fileObj?.url || fileObj?.tempFilePath || fileObj?.file?.path
+		if (filePath) {
+			uni.uploadFile({
+				url: baseUrl,
+				filePath,
+				name: 'file',
+				header: { Authorization: 'Bearer ' + getToken() },
+				success: (res) => {
+					closeToast()
+					try {
+						const data = JSON.parse(res.data || '{}')
+						if (data.code === 200) {
+							resolve(data.data)
+						} else {
+							reject(new Error(data.msg || '涓婁紶澶辫触'))
+						}
+					} catch (err) {
+						reject(err)
+					}
+				},
+				fail: (err) => {
+					closeToast()
+					reject(err)
+				}
+			})
+			return
+		}
+
+		// H5: 浣跨敤鍘熷 File锛坕nput 閫夋嫨锛�
+		const rawFile = fileObj?.file
+		if (rawFile) {
+			// uni.uploadFile 鍦� H5 涓嶆敮鎸佸師鐢� File 瀵硅薄锛岃繖閲岀敤 fetch 鍙戦�� FormData
+			const formData = new FormData()
+			formData.append('file', rawFile, rawFile.name || 'file.pdf')
+			formData.append('salesLedgerId', form.value.salesLedgerId || currentId.value || '')
+			fetch(baseUrl, {
+				method: 'POST',
+				headers: { Authorization: 'Bearer ' + getToken() },
+				body: formData
+			}).then(async (res) => {
+				closeToast()
+				const data = await res.json()
+				if (data.code === 200) {
+					resolve(data.data)
+				} else {
+					reject(new Error(data.msg || '涓婁紶澶辫触'))
+				}
+			}).catch((err) => {
+				closeToast()
+				reject(err)
+			})
+			return
+		}
+
+		closeToast()
+		reject(new Error('鏈壘鍒板彲涓婁紶鐨勬枃浠�'))
+	})
+}
+
+const afterReadUpload = async (file) => {
+	try {
+		const files = Array.isArray(file) ? file : file?.file ? [file] : [file]
+		for (const f of files) {
+			const uploaded = await uploadSingleFile(f)
+			fileList.value.push(uploaded)
+		}
+		showToast('涓婁紶鎴愬姛')
+	} catch (e) {
+		showToast('涓婁紶澶辫触')
+	}
+}
+
+const removeUploaded = (index) => {
+	fileList.value.splice(index, 1)
+}
+
+const getFileNameFromUrl = (url) => {
+	try { if (!url) return ''; return decodeURIComponent(url.split('/').pop()) } catch (e) { return url }
+}
+
+const loadDetail = async (id) => {
+	try {
+		showLoadingToast({ message: '鍔犺浇涓�...' })
+		const res = await getProductRecordById({ id })
+		const data = res?.data || res
+		form.value = { ...data }
+		temFutureTickets.value = data.futureTickets;
+		fileList.value = data?.fileList || []
+		if (!form.value.invoicePerson) {
+			form.value.invoicePerson = userStore.nickName
+		}
+		if (!form.value.invoiceDate) {
+			form.value.invoiceDate = dayjs().format('YYYY-MM-DD')
+		}
+		closeToast()
+	} catch (e) {
+		closeToast()
+		showToast('鍔犺浇澶辫触')
+	}
+}
+
+const submitForm = async () => {
+	try {
+		showLoadingToast({ message: '鎻愪氦涓�...' })
+		await updateRegistration(form.value)
+		closeToast()
+		showToast('鎻愪氦鎴愬姛')
+		setTimeout(() => { goBack() }, 800)
+	} catch (e) {
+		closeToast()
+		showToast('鎻愪氦澶辫触锛岃閲嶈瘯')
+	}
+}
+
+onMounted(() => {
+	const rowStr = uni.getStorageSync('invoiceLedgerEditRow')
+	if (rowStr) {
+		try {
+			const row = JSON.parse(rowStr)
+			currentId.value = row.id
+			loadDetail(currentId.value)
+		} catch (e) {
+			// ignore
+		}
+	}
+})
+</script>
+
+<style scoped lang="scss">
+.account-detail {
+	min-height: 100vh;
+	background: #f8f9fa;
+	padding-bottom: 5rem;
+}
+.uploaded-list { padding: 8px 16px 0 16px; }
+.uploaded-item { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #f5f5f5; }
+.file-name { font-size: 12px; color: #333; margin-right: 8px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.tip-text { padding: 4px 16px 0 16px; font-size: 12px; color: #888; }
+.footer-btns { position: fixed; left: 0; right: 0; bottom: 0; background: #fff; display: flex; justify-content: space-around; align-items: center; padding: 0.75rem 0; box-shadow: 0 -0.125rem 0.5rem rgba(0,0,0,0.05); z-index: 1000; }
+.cancel-btn { font-weight: 400; font-size: 1rem; color: #FFFFFF; width: 6.375rem; background: #C7C9CC; box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; }
+.save-btn { font-weight: 400; font-size: 1rem; color: #FFFFFF; width: 14rem; background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%); box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2); border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; }
+</style>
+

--
Gitblit v1.9.3