src/pages.json | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/pages/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/pages/sales/invoicingRegistration/add.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/pages/sales/invoicingRegistration/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/pages/sales/invoicingRegistration/view.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/pages/sales/salesAccount/detail.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/pages/sales/salesAccount/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/pages/sales/salesAccount/view.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/pages.json
@@ -71,6 +71,27 @@ } }, { "path": "pages/sales/invoicingRegistration/index", "style": { "navigationBarTitleText": "å¼ç¥¨ç»è®°", "navigationStyle": "custom" } }, { "path": "pages/sales/invoicingRegistration/add", "style": { "navigationBarTitleText": "æ°å¢å¼ç¥¨ç»è®°", "navigationStyle": "custom" } }, { "path": "pages/sales/invoicingRegistration/view", "style": { "navigationBarTitleText": "å¼ç¥¨ç»è®°è¯¦æ ", "navigationStyle": "custom" } }, { "path": "pages/common/webview/index", "style": { "navigationBarTitleText": "æµè§ç½é¡µ" @@ -82,7 +103,6 @@ "navigationBarTitleText": "æµè§ææ¬" } }, //ååå®¡æ¹ { "path": "pages/cooperativeOffice/collaborativeApproval/index", "style": { @@ -97,7 +117,6 @@ "navigationStyle": "custom" } }, //å®¢æ·æè®¿ { "path": "pages/cooperativeOffice/clientVisit/index", "style": { src/pages/index.vue
@@ -293,6 +293,11 @@ url: '/pages/sales/salesAccount/index' }); break; case 'å¼ç¥¨ç»è®°': uni.navigateTo({ url: '/pages/sales/invoicingRegistration/index' }); break; case 'åå审æ¹': uni.navigateTo({ url: '/pages/cooperativeOffice/collaborativeApproval/index' src/pages/sales/invoicingRegistration/add.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,537 @@ <template> <view class="account-detail"> <!-- 页é¢å¤´é¨ --> <van-nav-bar title="æ°å¢å¼ç¥¨ç»è®°" left-text="è¿å" left-arrow @click-left="goBack" fixed placeholder /> <!-- 表åå 容 --> <van-form @submit="submitForm" ref="formRef" label-width="110px" 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.salesContractNo" label="éå®ååå·" readonly placeholder="èªå¨å¡«å " /> <van-field v-model="form.customerName" label="客æ·åç§°" readonly placeholder="èªå¨å¡«å " /> <van-field v-model="form.salesman" label="ä¸å¡å" readonly placeholder="èªå¨å¡«å " /> <van-field v-model="form.projectName" label="项ç®åç§°" readonly placeholder="èªå¨å¡«å " /> <van-field v-model="form.createUer" label="å½å ¥äºº" readonly placeholder="请è¾å ¥å½å ¥äºº" /> <van-field v-model="form.createTime" label="å½å ¥æ¥æ" readonly placeholder="è¯·éæ©å½å ¥æ¥æ" @click="showCreateTimePicker = true" /> <van-field v-model="form.invoiceNo" label="å票å·ç " required placeholder="请è¾å ¥å票å·ç " :rules="[{ required: true, message: '请è¾å ¥å票å·ç ' }]" /> <van-field v-model="form.issueDate" label="å¼ç¥¨æ¥æ" readonly placeholder="è¯·éæ©å¼ç¥¨æ¥æ" required @click="showIssueDatePicker = true" :rules="[{ required: true, message: 'è¯·éæ©å¼ç¥¨æ¥æ' }]" /> </van-cell-group> <!-- 产åä¿¡æ¯ --> <view class="product-section"> <view class="section-header"> <text class="section-title">产åä¿¡æ¯</text> </view> <view v-if="productData.length === 0" class="empty-state"> <van-empty description="ææ äº§åæ°æ®" /> </view> <view v-else class="product-list"> <view v-for="(item, index) in productData" :key="index" class="product-card" > <!-- 产åå¤´é¨ --> <view class="product-header"> <view class="product-title"> <van-icon name="description" color="#2979ff" size="15" /> <text class="product-productCategory">产å {{ index + 1 }}</text> </view> </view> <!-- 产åä¿¡æ¯è¡¨å --> <view class="product-form"> <van-field v-model="item.productCategory" label="产å大类" readonly /> <van-field v-model="item.specificationModel" label="è§æ ¼åå·" readonly /> <van-field v-model="item.unit" label="åä½" readonly /> <van-field v-model="item.quantity" label="æ°é" readonly /> <van-field v-model="item.taxRate" label="ç¨ç(%)" readonly /> <van-field v-model="item.taxInclusiveUnitPrice" label="å«ç¨åä»·(å )" readonly /> <van-field v-model="item.taxInclusiveTotalPrice" label="å«ç¨æ»ä»·(å )" readonly /> <van-field v-model="item.taxExclusiveTotalPrice" label="ä¸å«ç¨æ»ä»·(å )" readonly /> <!-- æ¬æ¬¡å¼ç¥¨ä¿¡æ¯ --> <van-field v-model="item.currentInvoiceNum" label="æ¬æ¬¡å¼ç¥¨æ°" type="number" placeholder="请è¾å ¥å¼ç¥¨æ°é" @blur="invoiceNumBlur(item)" /> <van-field v-model="item.currentInvoiceAmount" label="æ¬æ¬¡å¼ç¥¨éé¢(å )" type="number" placeholder="请è¾å ¥å¼ç¥¨éé¢" @blur="invoiceAmountBlur(item)" /> <!-- æªå¼ç¥¨ä¿¡æ¯ --> <van-field v-model="item.noInvoiceNum" label="æªå¼ç¥¨æ°" readonly /> <van-field v-model="item.noInvoiceAmount" label="æªå¼ç¥¨éé¢(å )" readonly /> </view> </view> </view> </view> <!-- æäº¤æé® --> <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> <!-- æ¥æéæ©å¨ --> <van-popup v-model:show="showIssueDatePicker" position="bottom"> <van-date-picker v-model="currentIssueDate" title="éæ©å¼ç¥¨æ¥æ" @confirm="onIssueDateConfirm" @cancel="showIssueDatePicker = false" /> </van-popup> <van-popup v-model:show="showCreateTimePicker" position="bottom"> <van-date-picker v-model="currentCreateTime" title="éæ©å½å ¥æ¥æ" @confirm="onCreateTimeConfirm" @cancel="showCreateTimePicker = false" /> </van-popup> </view> </template> <script setup> import { ref, reactive, onMounted } from 'vue' import { showToast, showLoadingToast, closeToast } from 'vant' import { invoiceRegistrationSave } from '@/api/salesManagement/invoiceRegistration' import useUserStore from '@/store/modules/user' import {getSalesLedgerWithProducts} from "@/api/salesManagement/salesLedger"; const userStore = useUserStore() const editData = ref(null); // 表åå¼ç¨ const formRef = ref() // è¡¨åæ°æ® let form = ref({ salesContractNo: '', customerName: '', salesman: '', projectName: '', createUer: '', issueDate: '', createTime: '', invoiceNo: '' }) // äº§åæ°æ® const productData = ref([]) // æ¥æéæ©å¨ç¶æ const showIssueDatePicker = ref(false) const showCreateTimePicker = ref(false) const currentIssueDate = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()]) const currentCreateTime = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()]) // æäº¤ç¶æ const submitting = ref(false) // è¿åä¸ä¸é¡µ const goBack = () => { // æ¸ çæ¬å°åå¨çæ°æ® uni.removeStorageSync('editData'); uni.navigateBack() } // æ ¼å¼åæ°å const formatNumber = (value, precision = 2) => { if (!value && value !== 0) return '0.00' return Number(value).toFixed(precision) } // å¼ç¥¨æ°éååå¤ç const invoiceNumBlur = (row) => { if (!row.currentInvoiceNum) { row.currentInvoiceNum = 0; } if (row.currentInvoiceNum > row.tempNoInvoiceNum) { showToast('æ¬æ¬¡å¼ç¥¨æ°ä¸å¾å¤§äºæªå¼ç¥¨æ°') row.currentInvoiceNum = 0; } // è®¡ç®æ¬æ¬¡å¼ç¥¨éé¢ row.currentInvoiceAmount = ( row.currentInvoiceNum * row.taxInclusiveUnitPrice ).toFixed(2); // è®¡ç®æªå¼ç¥¨æ° row.noInvoiceNum = (row.originalNoInvoiceNum - row.currentInvoiceNum).toFixed( 2 ); // è®¡ç®æªå¼ç¥¨éé¢ row.noInvoiceAmount = ( row.tempnoInvoiceAmount - row.currentInvoiceAmount ).toFixed(2); } // å¼ç¥¨éé¢ååå¤ç const invoiceAmountBlur = (row) => { if (!row.currentInvoiceAmount) { row.currentInvoiceAmount = 0; } // è®¡ç®æ¯å¦è¶ è¿å¼ç¥¨æ»éé¢ if (row.currentInvoiceAmount > row.tempnoInvoiceAmount) { showToast('æ¬æ¬¡å¼ç¥¨éé¢ä¸å¾å¤§äºæªå¼ç¥¨éé¢') row.currentInvoiceAmount = 0; } // è®¡ç®æ¬æ¬¡å¼ç¥¨æ° row.currentInvoiceNum = ( row.currentInvoiceAmount / row.taxInclusiveUnitPrice ).toFixed(2); // è®¡ç®æªå¼ç¥¨æ° row.noInvoiceNum = (row.originalNoInvoiceNum - row.currentInvoiceNum).toFixed( 2 ); // è®¡ç®æªå¼ç¥¨éé¢ row.noInvoiceAmount = ( row.tempnoInvoiceAmount - row.currentInvoiceAmount ).toFixed(2); } // æ´æ°æªå¼ç¥¨æ°æ® const updateNoInvoiceData = (row) => { const totalQuantity = parseFloat(row.quantity) || 0 const currentInvoiceNum = parseFloat(row.currentInvoiceNum) || 0 const totalAmount = parseFloat(row.taxInclusiveTotalPrice) || 0 const currentInvoiceAmount = parseFloat(row.currentInvoiceAmount) || 0 row.noInvoiceNum = Math.max(0, totalQuantity - currentInvoiceNum).toFixed(2) row.noInvoiceAmount = Math.max(0, totalAmount - currentInvoiceAmount).toFixed(2) } // å¼ç¥¨æ¥æç¡®è®¤ const onIssueDateConfirm = ({ selectedValues }) => { console.log('selectedValues--', selectedValues) form.value.issueDate = selectedValues.join('-'); currentIssueDate.value = selectedValues; showIssueDatePicker.value = false; }; // å½å ¥æ¥æç¡®è®¤ const onCreateTimeConfirm = (value) => { try { // å¤çä¸åç弿 ¼å¼ let year, month, day; if (Array.isArray(value)) { // æ°ç»æ ¼å¼ [year, month, day] [year, month, day] = value; } else if (value && typeof value === 'object') { // Dateå¯¹è±¡æ ¼å¼ year = value.getFullYear(); month = value.getMonth() + 1; day = value.getDate(); } else { // å ¶ä»æ ¼å¼ï¼ä½¿ç¨å½åæ¥æ const now = new Date(); year = now.getFullYear(); month = now.getMonth() + 1; day = now.getDate(); } form.value.createTime = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`; showCreateTimePicker.value = false; } catch (error) { console.error('æ¥æå¤çé误:', error); showToast('æ¥æéæ©å¤±è´¥ï¼è¯·éè¯'); } } // æ ¼å¼åæ¥æ const formatDate = (date) => { const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0') return `${year}-${month}-${day}` } // è·å产åå表 const getProductList = async () => { try { showLoadingToast('å è½½ä¸...') const res = await getSalesLedgerWithProducts({ id: editData.value.id, type: 1 }) productData.value = res.productData; form.value = { ...res }; // 设置é»è®¤å½å ¥äºº form.value.createUer = userStore.name || '' // 设置é»è®¤æ¥æ const today = new Date() form.value.createTime = formatDate(today) closeToast() } catch (error) { closeToast() showToast('è·å产åå表失败') } } // æäº¤è¡¨å const submitForm = async () => { try { submitting.value = true // éªè¯äº§åæ°æ® if (productData.value.length === 0) { showToast('è¯·å æ·»å 产åä¿¡æ¯') return } // éªè¯å¼ç¥¨æ°æ® const hasInvoiceData = productData.value.some(item => { const num = parseFloat(item.currentInvoiceNum) || 0 const amount = parseFloat(item.currentInvoiceAmount) || 0 return num > 0 || amount > 0 }) if (!hasInvoiceData) { showToast('请è³å°è¾å ¥ä¸ä¸ªäº§åçå¼ç¥¨ä¿¡æ¯') return } const submitData = { ...form.value, productList: productData.value } await invoiceRegistrationSave(submitData) showToast('æäº¤æå') // è¿åä¸ä¸é¡µ setTimeout(() => { uni.navigateBack() }, 1500) } catch (error) { showToast('æäº¤å¤±è´¥ï¼è¯·éè¯') } finally { submitting.value = false } } // 页é¢å è½½æ¶åå§åæ°æ® onMounted(() => { // ä»é¡µé¢åæ°æç¼åä¸è·åéå®ååä¿¡æ¯ const contractInfo = uni.getStorageSync('editData') if (contractInfo) { editData.value = JSON.parse(contractInfo); const contract = JSON.parse(contractInfo) form.value.salesContractNo = contract.salesContractNo || '' form.value.customerName = contract.customerName || '' form.value.salesman = contract.salesman || '' form.value.projectName = contract.projectName || '' // è·å产åå表 getProductList() } }) </script> <style scoped lang="scss"> .account-detail { min-height: 100vh; background: #f8f9fa; padding-bottom: 5rem; } .empty-state { padding: 40px 0; } .product-section { background: #fff; margin-top: 1rem; padding: 1rem; box-shadow: 0 0.125rem 0.5rem rgba(0,0,0,0.04); } .section-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; } .section-title { font-size: 1rem; font-weight: 600; color: #333; } .product-list { .product-card { background: #FFFFFF; box-shadow: 0 0 1.25rem 0 rgba(0,57,117,0.08); border-radius: 0.5rem 0.5rem 0.5rem 0.5rem; padding: 1rem 0.5rem 0 0.5rem; position: relative; margin-bottom: 1rem; } } .product-header { display: flex; align-items: center; justify-content: space-between; padding: 0 0.5rem 0.75rem 0.5rem; border-bottom: 0.0625rem solid #e8e8e8; } .product-title { display: flex; align-items: center; } .product-productCategory { margin-left: 0.5rem; font-size: 0.875rem; font-weight: 500; color: #333; } .product-form { margin-bottom: 1rem; } .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; } // ååºå¼è°æ´ @media (max-width: 768px) { .submit-section { padding: 12px; } } </style> src/pages/sales/invoicingRegistration/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,448 @@ <template> <view class="sales-account"> <!-- 页é¢å¤´é¨ --> <van-nav-bar title="å¼ç¥¨ç»è®°" left-text="è¿å" left-arrow @click-left="goBack" fixed placeholder /> <!-- æç´¢åçéåºå --> <view class="search-filter-section"> <view class="search-bar"> <view class="search-input"> <input class="search-text" placeholder="请è¾å ¥éå®ååå·/客æ·åç§°" v-model="searchKeyword" /> </view> <view class="filter-button" @click="getList"> <up-icon name="search" size="24" color="#999"></up-icon> </view> </view> </view> <!-- éå®å°è´¦ç叿µ --> <view class="ledger-list" v-if="total > 0"> <view v-for="(item, index) in ledgerList" :key="index"> <view class="ledger-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> <!-- <view class="item-tag">--> <!-- <text class="tag-text">{{ item.recorder }}</text>--> <!-- </view>--> </view> <up-divider></up-divider> <view class="item-details"> <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> <text class="detail-value">{{ item.customerContractNo }}</text> </view> <view class="detail-row"> <text class="detail-label">ä¸å¡å</text> <text class="detail-value">{{ item.salesman }}</text> </view> <view class="detail-row"> <text class="detail-label">项ç®åç§°</text> <text class="detail-value">{{ item.projectName }}</text> </view> <view class="detail-row"> <text class="detail-label">ååéé¢(å )</text> <text class="detail-value highlight">{{ item.contractAmount }}</text> </view> <view class="detail-row"> <text class="detail-label">å·²å¼ç¥¨éé¢(å )</text> <text class="detail-value highlight">{{ item.invoiceTotal }}</text> </view> <view class="detail-row"> <text class="detail-label">æªå¼ç¥¨éé¢(å )</text> <text class="detail-value redlight">{{ item.noInvoiceAmountTotal }}</text> </view> </view> <!-- æä½æé®åºå --> <view class="action-buttons"> <van-button type="primary" size="small" @click="handleAddInvoice(item)" class="action-btn" :disabled="item.entryPerson != userStore.id || item.noInvoiceAmountTotal == 0" > æ°å¢å¼ç¥¨ </van-button> <van-button type="default" size="small" @click="handleViewDetail(item)" class="action-btn" > æ¥ç详æ </van-button> </view> </view> </view> </view> <view v-else class="no-data"> <text>ææ éå®å°è´¦æ°æ®</text> </view> <!-- æµ®å¨æä½æé® --> <!-- <view class="fab-button" @click="handleInfo('add')"> <up-icon name="plus" size="24" color="#ffffff"></up-icon> </view> --> </view> </template> <script setup> import { ref } from 'vue'; import { onShow } from '@dcloudio/uni-app'; import {ledgerListPage} from "@/api/salesManagement/salesLedger"; import useUserStore from "@/store/modules/user"; const userStore = useUserStore() // æç´¢å ³é®è¯ const searchKeyword = ref(''); // éå®å°è´¦æ°æ® const ledgerList = ref([]); const total = ref(0); // ååéæ©å¨ç¸å ³ const contractList = ref([]); const contractLoading = ref(false); const contractFinished = ref(false); // è¿åä¸ä¸é¡µ const goBack = () => { uni.navigateBack(); }; // æ¥è¯¢å表 const getList = () => { const page = { current: -1, size: -1 } ledgerListPage({...page}).then((res) => { ledgerList.value = res.records; total.value = res.total; }).catch(() => { // tableLoading.value = false; }); }; // å¤çæ°å¢å¼ç¥¨ const handleAddInvoice = (item) => { try { // æ£æ¥æéï¼åªæå½å ¥äººæè½æ°å¢å¼ç¥¨ if (item.entryPerson != userStore.id) { uni.showToast({ title: 'åªæå½å ¥äººæè½æ°å¢å¼ç¥¨', icon: 'none' }); return; } // åå¨éä¸çååä¿¡æ¯ uni.setStorageSync('editData', JSON.stringify(item)); // è·³è½¬å°æ°å¢å¼ç¥¨é¡µé¢ uni.navigateTo({ url: '/pages/sales/invoicingRegistration/add' }); } catch (error) { console.error('å¤çæ°å¢å¼ç¥¨å¤±è´¥:', error); uni.showToast({ title: 'æä½å¤±è´¥ï¼è¯·éè¯', icon: 'error' }); } }; // å¤çæ¥ç详æ const handleViewDetail = (item) => { try { // å卿°æ® uni.setStorageSync('editData', JSON.stringify(item)); // 跳转å°è¯¦æ é¡µé¢ uni.navigateTo({ url: '/pages/sales/invoicingRegistration/view' }); } catch (error) { console.error('å¤çæ¥ç详æ 失败:', error); uni.showToast({ title: 'æä½å¤±è´¥ï¼è¯·éè¯', icon: 'error' }); } }; onShow(() => { // 页颿¾ç¤ºæ¶å·æ°å表 getList(); }); </script> <style scoped lang="scss"> .u-divider { margin: 0 !important; } .sales-account { min-height: 100vh; background: #f8f9fa; position: relative; } .page-header { background: #ffffff; padding: 16px 20px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid #f0f0f0; position: sticky; /* å ¼å®¹ iOS åæµ·/çµå¨å²å®å ¨åº */ padding-top: env(safe-area-inset-top); top: 0; z-index: 100; } .header-left { display: flex; align-items: center; gap: 8px; } .nav-icon { width: 24px; height: 24px; background: #2979ff; border-radius: 4px; display: flex; align-items: center; justify-content: center; } .nav-text { font-size: 14px; color: #2979ff; font-weight: 500; } .header-center { flex: 1; text-align: center; } .page-title { font-size: 18px; font-weight: 600; color: #333; } .header-right { display: flex; align-items: center; } .status-bar { display: flex; align-items: center; gap: 4px; } .signal, .wifi, .battery { width: 16px; height: 8px; background: #333; border-radius: 2px; } .search-filter-section { padding: 10px 20px; background: #ffffff; } .search-bar { display: flex; align-items: center; gap: 12px; } .search-input { flex: 1; background: #f5f5f5; border-radius: 24px; padding: 10px 16px; display: flex; align-items: center; gap: 8px; } .search-text { flex: 1; font-size: 14px; color: #333; background: transparent; border: none; outline: none; } .search-text::placeholder { color: #999; } .filter-button { width: 40px; height: 40px; border-radius: 8px; display: flex; align-items: center; justify-content: center; } .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; } .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-tag { background: #4caf50; border-radius: 4px; padding: 2px 4px; } .tag-text { font-size: 11px; color: #ffffff; font-weight: 500; } .item-details { padding: 16px 0; } .detail-row { display: flex; align-items: flex-end; justify-content: space-between; margin-bottom: 8px; &:last-child { margin-bottom: 0; } } .detail-info { margin-top: 10px; display: flex; align-items: flex-start; justify-content: space-between; } .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; } .detail-value.highlight { color: #2979ff; font-weight: 500; } .detail-value.redlight { color: red; font-weight: 500; } .action-buttons { display: flex; gap: 12px; padding: 0 0 16px 0; justify-content: space-between; } .action-btn { flex: 1; } .no-data { padding: 40px 0; text-align: center; color: #999; } .fab-button { position: fixed; bottom: 30px; right: 30px; width: 56px; height: 56px; background: #2979ff; border-radius: 50%; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3); z-index: 1000; } </style> src/pages/sales/invoicingRegistration/view.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,325 @@ <template> <view class="account-view"> <!-- 顶鍿 颿 --> <van-nav-bar title="å¼ç¥¨ç»è®°è¯¦æ " left-text="è¿å" left-arrow @click-left="goBack" fixed placeholder /> <!-- åºæ¬ä¿¡æ¯å±ç¤º --> <view class="info-section"> <view class="section-title">åºæ¬ä¿¡æ¯</view> <view class="info-grid"> <view class="info-item"> <text class="info-label">éå®ååå·</text> <text class="info-value">{{ form.salesContractNo }}</text> </view> <view class="info-item"> <text class="info-label">客æ·ååå·</text> <text class="info-value">{{ form.customerContractNo }}</text> </view> <view class="info-item"> <text class="info-label">客æ·åç§°</text> <text class="info-value">{{ form.customerName }}</text> </view> <view class="info-item"> <text class="info-label">ä¸å¡å</text> <text class="info-value">{{ form.salesman }}</text> </view> <view class="info-item"> <text class="info-label">项ç®åç§°</text> <text class="info-value">{{ form.projectName }}</text> </view> <view class="info-item"> <text class="info-label">ååéé¢(å )</text> <text class="info-value highlight">{{ form.contractAmount }}</text> </view> <view class="info-item"> <text class="info-label">å·²å¼ç¥¨éé¢(å )</text> <text class="info-value highlight">{{ form.invoiceTotal }}</text> </view> <view class="info-item"> <text class="info-label">æªå¼ç¥¨éé¢(å )</text> <text class="info-value redlight">{{ form.noInvoiceAmountTotal }}</text> </view> </view> </view> <!-- 产åä¿¡æ¯å±ç¤º --> <view class="product-section" v-if="productData && productData.length > 0"> <view class="section-title">产åä¿¡æ¯</view> <view class="product-card" v-for="(product, idx) in productData" :key="idx"> <view class="product-header"> <view class="product-title"> <van-icon name="description" color="#2979ff" size="15" /> <text class="product-productCategory">产å {{ idx + 1 }}</text> </view> </view> <view class="product-info"> <view class="info-grid"> <view class="info-item"> <text class="info-label">产å大类</text> <text class="info-value">{{ product.productCategory }}</text> </view> <view class="info-item"> <text class="info-label">è§æ ¼åå·</text> <text class="info-value">{{ product.specificationModel }}</text> </view> <view class="info-item"> <text class="info-label">åä½</text> <text class="info-value">{{ product.unit }}</text> </view> <view class="info-item"> <text class="info-label">ç¨ç(%)</text> <text class="info-value">{{ product.taxRate }}</text> </view> <view class="info-item"> <text class="info-label">æ°é</text> <text class="info-value highlight">{{ product.quantity }}</text> </view> <view class="info-item"> <text class="info-label">å«ç¨åä»·(å )</text> <text class="info-value highlight">{{ product.taxInclusiveUnitPrice }}</text> </view> <view class="info-item"> <text class="info-label">å«ç¨æ»ä»·(å )</text> <text class="info-value highlight">{{ product.taxInclusiveTotalPrice }}</text> </view> <view class="info-item"> <text class="info-label">ä¸å«ç¨æ»ä»·(å )</text> <text class="info-value highlight">{{ product.taxExclusiveTotalPrice }}</text> </view> <view class="info-item"> <text class="info-label">å¼ç¥¨æ°</text> <text class="info-value highlight">{{ product.invoiceNum }}</text> </view> <view class="info-item"> <text class="info-label">å¼ç¥¨éé¢(å )</text> <text class="info-value highlight">{{ product.invoiceAmount }}</text> </view> <view class="info-item"> <text class="info-label">æªå¼ç¥¨æ°</text> <text class="info-value highlight">{{ product.noInvoiceNum }}</text> </view> <view class="info-item"> <text class="info-label">æªå¼ç¥¨éé¢(å )</text> <text class="info-value redlight">{{ product.noInvoiceAmount }}</text> </view> </view> </view> </view> </view> <!-- æ 产åä¿¡æ¯æç¤º --> <view class="no-product" v-else> <text>ææ äº§åä¿¡æ¯</text> </view> </view> </template> <script setup> import { onMounted, ref } from 'vue'; import { getSalesLedgerWithProducts } from "@/api/salesManagement/salesLedger"; // è¡¨åæ°æ® const form = ref({ id: '', salesContractNo: '', customerContractNo: '', customerId: '', customerName: '', projectName: '', executionDate: '', contractAmount: '', invoiceTotal: '', noInvoiceAmountTotal: '', salesman: '' }); // äº§åæ°æ® const productData = ref([]); // ç¼è¾æ°æ® const editData = ref(null); // è¿åä¸ä¸é¡µ const goBack = () => { // æ¸ çæ¬å°åå¨çæ°æ® uni.removeStorageSync('editData'); uni.navigateBack(); }; // å¡«å è¡¨åæ°æ® const fillFormData = () => { if (!editData.value) return; // è·å宿´ç产åä¿¡æ¯ getSalesLedgerWithProducts({ id: editData.value.id, type: 1 }).then((res) => { productData.value = res.productData || []; }); // å¡«å åºæ¬ä¿¡æ¯ form.value.salesContractNo = editData.value.salesContractNo || ''; form.value.customerContractNo = editData.value.customerContractNo || ''; form.value.customerName = editData.value.customerName || ''; form.value.projectName = editData.value.projectName || ''; form.value.executionDate = editData.value.executionDate || ''; form.value.contractAmount = editData.value.contractAmount || ''; form.value.salesman = editData.value.salesman || ''; form.value.invoiceTotal = editData.value.invoiceTotal || 0; form.value.noInvoiceAmountTotal = editData.value.noInvoiceAmountTotal || 0; form.value.id = editData.value.id || ''; form.value.customerId = editData.value.customerId || ''; }; onMounted(() => { // è·åç¼è¾æ°æ®å¹¶å¡«å 表å const editDataStr = uni.getStorageSync('editData'); if (editDataStr) { try { editData.value = JSON.parse(editDataStr); // ä½¿ç¨ nextTick ç¡®ä¿æ°æ®å è½½å®æååå¡«å setTimeout(() => { fillFormData(); }, 100); } catch (error) { console.error('è§£æç¼è¾æ°æ®å¤±è´¥:', error); } } }); </script> <style scoped lang="scss"> .account-view { min-height: 100vh; background: #f8f9fa; padding-bottom: 2rem; } .header { display: flex; align-items: center; background: #fff; padding: 1rem 1.25rem; border-bottom: 0.0625rem solid #f0f0f0; position: sticky; top: 0; z-index: 100; /* å ¼å®¹ iOS åæµ·/çµå¨å²å®å ¨åº */ padding-top: env(safe-area-inset-top); } .title { flex: 1; text-align: center; font-size: 1.125rem; font-weight: 600; color: #333; } .info-section { background: #fff; margin: 1rem; padding: 1rem; border-radius: 0.5rem; box-shadow: 0 0.125rem 0.5rem rgba(0,0,0,0.04); } .section-title { font-size: 1rem; font-weight: 600; color: #333; margin-bottom: 1rem; padding-bottom: 1rem; border-bottom: 0.0625rem solid #e8e8e8; } .info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; } .info-item { display: flex; flex-direction: column; gap: 0.25rem; } .info-label { font-size: 0.75rem; color: #666; font-weight: 400; } .info-value { font-size: 0.875rem; color: #333; font-weight: 500; } .info-value.highlight { color: #2979ff; font-weight: 600; } .info-value.redlight { color: red; font-weight: 600; } .product-section { background: #fff; margin: 1rem; padding: 1rem; border-radius: 0.5rem; box-shadow: 0 0.125rem 0.5rem rgba(0,0,0,0.04); } .product-card { background: #f8f9fa; border-radius: 0.5rem; padding: 1rem; margin-bottom: 1rem; } .product-card:last-child { margin-bottom: 0; } .product-header { display: flex; align-items: center; padding-bottom: 0.75rem; border-bottom: 0.0625rem solid #e8e8e8; margin-bottom: 1rem; } .product-title { display: flex; align-items: center; gap: 0.5rem; } .product-productCategory { font-size: 0.875rem; font-weight: 500; color: #333; } .product-info .info-grid { grid-template-columns: 1fr 1fr; gap: 0.5rem; } .no-product { text-align: center; padding: 2rem; color: #999; font-size: 0.875rem; } </style> src/pages/sales/salesAccount/detail.vue
@@ -1,10 +1,14 @@ <template> <view class="account-detail"> <!-- 顶鍿 颿 --> <view class="header"> <up-icon name="arrow-left" size="20" color="#333" @click="goBack" /> <text class="title">å°è´¦è¯¦æ </text> </view> <van-nav-bar title="å°è´¦è¯¦æ " left-text="è¿å" left-arrow @click-left="goBack" fixed placeholder /> <!-- 表ååºå --> <van-form @submit="onSubmit" label-width="110px" input-align="right" style="margin-top: 10px" error-message-align="right" scroll-to-error scroll-to-error-position="center"> src/pages/sales/salesAccount/index.vue
@@ -1,14 +1,14 @@ <template> <view class="sales-account"> <!-- 页é¢å¤´é¨ --> <view class="page-header"> <view class="header-left"> <up-icon name="arrow-left" size="20" color="#333" @click="goBack"></up-icon> </view> <view class="header-center"> <text class="page-title">éå®å°è´¦</text> </view> </view> <van-nav-bar title="éå®å°è´¦" left-text="è¿å" left-arrow @click-left="goBack" fixed placeholder /> <!-- æç´¢åçéåºå --> <view class="search-filter-section"> @@ -50,7 +50,7 @@ </view> <view class="detail-row"> <text class="detail-label">客æ·ååå·</text> <text class="detail-value highlight">{{ item.customerContractNo }}</text> <text class="detail-value">{{ item.customerContractNo }}</text> </view> <view class="detail-row"> <text class="detail-label">ä¸å¡å</text> @@ -148,7 +148,7 @@ } // æ£æ¥æéï¼åªæå½å ¥äººæè½ç¼è¾ if (row.entryPerson !== userStore.id) { if (row.entryPerson != userStore.id) { // éå½å ¥äººè·³è½¬å°åªè¯»è¯¦æ é¡µé¢ uni.setStorageSync('editData', JSON.stringify(row)); uni.navigateTo({ src/pages/sales/salesAccount/view.vue
@@ -1,10 +1,14 @@ <template> <view class="account-view"> <!-- 顶鍿 颿 --> <view class="header"> <up-icon name="arrow-left" size="20" color="#333" @click="goBack" /> <text class="title">å°è´¦è¯¦æ </text> </view> <van-nav-bar title="å°è´¦è¯¦æ " left-text="è¿å" left-arrow @click-left="goBack" fixed placeholder /> <!-- åºæ¬ä¿¡æ¯å±ç¤º --> <view class="info-section">