| | |
| | | <PageHeader title="新增开票登记" @back="goBack" /> |
| | | |
| | | <!-- 表单内容 --> |
| | | <van-form @submit="submitForm" ref="formRef" label-width="110px" input-align="right" error-message-align="right" scroll-to-error scroll-to-error-position="center"> |
| | | <up-form @submit="submitForm" ref="formRef" label-width="130" :rules="rules" :model="form"> |
| | | <!-- 基本信息 --> |
| | | <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 |
| | | <view class="form-section"> |
| | | <up-form-item label="销售合同号" prop="salesContractNo"> |
| | | <up-input v-model="form.salesContractNo" placeholder="自动填充" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="客户名称" prop="customerName"> |
| | | <up-input v-model="form.customerName" placeholder="自动填充" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="业务员" prop="salesman"> |
| | | <up-input v-model="form.salesman" placeholder="自动填充" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="项目名称" prop="projectName"> |
| | | <up-input v-model="form.projectName" placeholder="自动填充" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="录入人" prop="createUer"> |
| | | <up-input v-model="form.createUer" placeholder="请输入录入人" disabled /> |
| | | </up-form-item> |
| | | <up-form-item |
| | | label="录入日期" |
| | | prop="createTime" |
| | | @click="showCreateTimePicker = true" |
| | | > |
| | | <up-input |
| | | v-model="form.createTime" |
| | | placeholder="请选择录入日期" |
| | | readonly |
| | | @click="showCreateTimePicker = true" |
| | | /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" @click="showCreateTimePicker = true"></up-icon> |
| | | </template> |
| | | </up-form-item> |
| | | <up-form-item label="发票号码" prop="invoiceNo" required> |
| | | <up-input v-model="form.invoiceNo" placeholder="请输入发票号码" /> |
| | | </up-form-item> |
| | | <up-form-item |
| | | label="开票日期" |
| | | prop="issueDate" |
| | | required |
| | | @click="showIssueDatePicker = true" |
| | | :rules="[{ required: true, message: '请选择开票日期' }]" |
| | | /> |
| | | </van-cell-group> |
| | | > |
| | | <up-input |
| | | v-model="form.issueDate" |
| | | placeholder="请选择开票日期" |
| | | readonly |
| | | @click="showIssueDatePicker = true" |
| | | /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" @click="showIssueDatePicker = true"></up-icon> |
| | | </template> |
| | | </up-form-item> |
| | | </view> |
| | | |
| | | <!-- 产品信息 --> |
| | | <view class="product-section"> |
| | | <view class="section-header"> |
| | | <text class="section-title">产品信息</text> |
| | | <view> |
| | | <text class="section-title">产品信息</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <view v-if="productData.length === 0" class="empty-state"> |
| | | <van-empty description="暂无产品数据" /> |
| | | <view class="empty-text">暂无产品数据</view> |
| | | </view> |
| | | |
| | | <view v-else class="product-list"> |
| | |
| | | <!-- 产品头部 --> |
| | | <view class="product-header"> |
| | | <view class="product-title"> |
| | | <van-icon name="description" color="#2979ff" size="15" /> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | </view> |
| | | <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 |
| | | /> |
| | | <up-form-item label="产品大类" prop="productCategory"> |
| | | <up-input v-model="item.productCategory" placeholder="" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="规格型号" prop="specificationModel"> |
| | | <up-input v-model="item.specificationModel" placeholder="" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="单位" prop="unit"> |
| | | <up-input v-model="item.unit" placeholder="" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="数量" prop="quantity"> |
| | | <up-input v-model="item.quantity" placeholder="" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="税率(%)" prop="taxRate"> |
| | | <up-input v-model="item.taxRate" placeholder="" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="含税单价(元)" prop="taxInclusiveUnitPrice"> |
| | | <up-input v-model="item.taxInclusiveUnitPrice" placeholder="" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="含税总价(元)" prop="taxInclusiveTotalPrice"> |
| | | <up-input v-model="item.taxInclusiveTotalPrice" placeholder="" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="不含税总价(元)" prop="taxExclusiveTotalPrice"> |
| | | <up-input v-model="item.taxExclusiveTotalPrice" placeholder="" disabled /> |
| | | </up-form-item> |
| | | |
| | | <!-- 本次开票信息 --> |
| | | <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)" |
| | | /> |
| | | <up-form-item label="本次开票数" prop="currentInvoiceNum"> |
| | | <up-input |
| | | v-model="item.currentInvoiceNum" |
| | | type="number" |
| | | placeholder="请输入开票数量" |
| | | @blur="invoiceNumBlur(item)" |
| | | /> |
| | | </up-form-item> |
| | | <up-form-item label="本次开票金额(元)" prop="currentInvoiceAmount"> |
| | | <up-input |
| | | v-model="item.currentInvoiceAmount" |
| | | type="number" |
| | | placeholder="请输入开票金额" |
| | | @blur="invoiceAmountBlur(item)" |
| | | /> |
| | | </up-form-item> |
| | | |
| | | <!-- 未开票信息 --> |
| | | <van-field |
| | | v-model="item.noInvoiceNum" |
| | | label="未开票数" |
| | | readonly |
| | | /> |
| | | <van-field |
| | | v-model="item.noInvoiceAmount" |
| | | label="未开票金额(元)" |
| | | readonly |
| | | /> |
| | | <up-form-item label="未开票数" prop="noInvoiceNum"> |
| | | <up-input v-model="item.noInvoiceNum" placeholder="" disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="未开票金额(元)" prop="noInvoiceAmount"> |
| | | <up-input v-model="item.noInvoiceAmount" placeholder="" disabled /> |
| | | </up-form-item> |
| | | </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> |
| | | <!-- 使用公共底部按钮组件 --> |
| | | <FooterButtons |
| | | show |
| | | cancelText="取消" |
| | | confirmText="保存" |
| | | @cancel="goBack" |
| | | @confirm="submitForm" |
| | | /> |
| | | </up-form> |
| | | |
| | | <!-- 日期选择器 --> |
| | | <van-popup v-model:show="showIssueDatePicker" position="bottom"> |
| | | <van-date-picker |
| | | v-model="currentIssueDate" |
| | | title="选择开票日期" |
| | | <up-popup :show="showIssueDatePicker" mode="bottom" @close="showIssueDatePicker = false"> |
| | | <up-datetime-picker |
| | | :show="true" |
| | | v-model="pickerIssueDateValue" |
| | | @confirm="onIssueDateConfirm" |
| | | @cancel="showIssueDatePicker = false" |
| | | mode="date" |
| | | /> |
| | | </van-popup> |
| | | </up-popup> |
| | | |
| | | <van-popup v-model:show="showCreateTimePicker" position="bottom"> |
| | | <van-date-picker |
| | | v-model="currentCreateTime" |
| | | title="选择录入日期" |
| | | <up-popup :show="showCreateTimePicker" mode="bottom" @close="showCreateTimePicker = false"> |
| | | <up-datetime-picker |
| | | :show="true" |
| | | v-model="pickerCreateTimeValue" |
| | | @confirm="onCreateTimeConfirm" |
| | | @cancel="showCreateTimePicker = false" |
| | | mode="date" |
| | | /> |
| | | </van-popup> |
| | | </up-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue' |
| | | import { ref, onMounted } from 'vue' |
| | | // 替换 toast 方法 |
| | | const showToast = (message) => { |
| | | uni.showToast({ |
| | |
| | | import { invoiceRegistrationSave } from '@/api/salesManagement/invoiceRegistration' |
| | | import useUserStore from '@/store/modules/user' |
| | | import {getSalesLedgerWithProducts} from "@/api/salesManagement/salesLedger"; |
| | | import FooterButtons from '@/components/FooterButtons.vue'; |
| | | import { formatDateToYMD } from '@/utils/ruoyi' |
| | | |
| | | const userStore = useUserStore() |
| | | const editData = ref(null); |
| | |
| | | invoiceNo: '' |
| | | }) |
| | | |
| | | // 表单校验规则 |
| | | const rules = { |
| | | invoiceNo: [ |
| | | { required: true, message: '请输入发票号码', trigger: 'blur' } |
| | | ], |
| | | issueDate: [ |
| | | { required: true, message: '请选择开票日期', trigger: 'blur' } |
| | | ] |
| | | }; |
| | | |
| | | // 产品数据 |
| | | 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 pickerIssueDateValue = ref(Date.now()) |
| | | const pickerCreateTimeValue = ref(Date.now()) |
| | | |
| | | // 提交状态 |
| | | const submitting = ref(false) |
| | |
| | | } |
| | | |
| | | // 开票日期确认 |
| | | const onIssueDateConfirm = ({ selectedValues }) => { |
| | | console.log('selectedValues--', selectedValues) |
| | | form.value.issueDate = selectedValues.join('-'); |
| | | currentIssueDate.value = selectedValues; |
| | | const onIssueDateConfirm = (e) => { |
| | | form.value.issueDate = formatDateToYMD(e.value) |
| | | pickerIssueDateValue.value = e.value |
| | | 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 onCreateTimeConfirm = (e) => { |
| | | form.value.createTime = formatDateToYMD(e.value) |
| | | pickerCreateTimeValue.value = e.value |
| | | showCreateTimePicker.value = false; |
| | | }; |
| | | |
| | | |
| | | |
| | | // 格式化日期 |
| | | const formatDate = (date) => { |
| | |
| | | }) |
| | | </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 lang="scss"> |
| | | @import '@/static/scss/form-common.scss'; |
| | | </style> |