gaoluyang
6 天以前 adeb8b768926ed50a3fb0857f366d6a0308d2cc0
src/pages/sales/salesAccount/detail.vue
@@ -4,80 +4,104 @@
      <PageHeader title="台账详情" @back="goBack" />
         <!-- 表单区域 -->
      <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">
         <van-field label="销售合同号" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="自动生成" disabled>
         </van-field>
         <van-field
            v-model="form.salesman"
            is-link
            readonly
            name="salesman"
      <u-form @submit="onSubmit" label-width="110" input-align="right" style="margin-top: 10px" error-message-align="right">
         <u-form-item label="销售合同号" prop="salesContractNo" border-bottom>
            <u-input v-model="form.salesContractNo" placeholder="自动生成" disabled />
         </u-form-item>
         <u-form-item
            label="业务员"
            prop="salesman"
            required
            placeholder="点击选择业务员"
            :rules="[{ required: true, message: '请选择业务员' }]"
            @click="showPicker = true"
         />
         <van-field label="客户合同号" name="customerContractNo" borderBottom="true"
                         v-model="form.customerContractNo" required
                         placeholder="请输入客户合同号" :rules="[{ required: true, message: '客户合同号不能为空' }]">
         </van-field>
         <van-field
            v-model="form.customerName"
            is-link
            readonly
            required
            name="customerName"
            border-bottom
         >
            <u-input
               v-model="form.salesman"
               readonly
               placeholder="点击选择业务员"
               @click="showPicker = true"
            />
         </u-form-item>
         <u-form-item label="客户合同号" prop="customerContractNo" required border-bottom>
            <u-input
               v-model="form.customerContractNo"
               placeholder="请输入客户合同号"
            />
         </u-form-item>
         <u-form-item
            label="客户名称"
            placeholder="点击选择客户"
            :rules="[{ required: true, message: '请选择客户' }]"
            @click="showCustomerPicker = true"
         />
         <van-field label="项目名称" name="projectName" borderBottom="true" v-model="form.projectName" placeholder="请输入项目名称" :rules="[{ required: true, message: '项目名称不能为空' }]" required>
         </van-field>
         <van-field
            v-model="form.executionDate"
            is-link
            readonly
            prop="customerName"
            required
            name="executionDate"
            border-bottom
         >
            <u-input
               v-model="form.customerName"
               readonly
               placeholder="点击选择客户"
               @click="showCustomerPicker = true"
            />
         </u-form-item>
         <u-form-item label="项目名称" prop="projectName" required border-bottom>
            <u-input v-model="form.projectName" placeholder="请输入项目名称" />
         </u-form-item>
         <u-form-item
            label="签订日期"
            placeholder="点击选择时间"
            :rules="[{ required: true, message: '签订日期不能为空' }]"
            @click="showDatePicker = true"
         />
         <van-popup v-model:show="showDatePicker" destroy-on-close position="bottom">
            <van-date-picker
            prop="executionDate"
            required
            border-bottom
         >
            <u-input
               v-model="form.executionDate"
               readonly
               placeholder="点击选择时间"
               @click="showDatePicker = true"
            />
         </u-form-item>
         <u-popup v-model="showDatePicker" mode="bottom">
            <u-datetime-picker
               v-model="pickerDateValue"
               @confirm="onDateConfirm"
               @cancel="showDatePicker = false"
            />
         </van-popup>
         <van-field label="付款方式" name="paymentMethod" borderBottom="true" v-model="form.paymentMethod" placeholder="请输入付款方式">
         </van-field>
         <van-field label="录入人" name="entryPersonName" borderBottom="true" v-model="form.entryPersonName" placeholder="请输入" disabled>
         </van-field>
         <van-field label="录入日期" name="entryDate" borderBottom="true" v-model="form.entryDate" placeholder="请输入" disabled>
         </van-field>
         <van-popup v-model:show="showPicker" destroy-on-close position="bottom">
            <van-picker
         </u-popup>
         <u-form-item label="付款方式" prop="paymentMethod" border-bottom>
            <u-input v-model="form.paymentMethod" placeholder="请输入付款方式" />
         </u-form-item>
         <u-form-item label="录入人" prop="entryPersonName" border-bottom>
            <u-input v-model="form.entryPersonName" placeholder="请输入" disabled />
         </u-form-item>
         <u-form-item label="录入日期" prop="entryDate" border-bottom>
            <u-input v-model="form.entryDate" placeholder="请输入" disabled />
         </u-form-item>
         <!-- 业务员选择弹窗 -->
         <u-popup v-model="showPicker" mode="bottom">
            <view class="picker-header">
               <view class="picker-cancel" @click="showPicker = false">取消</view>
               <view class="picker-title">选择业务员</view>
               <view class="picker-confirm" @click="confirmSalesman">确定</view>
            </view>
            <u-picker
               :columns="userList"
               v-model="pickerValue"
               @confirm="onConfirm"
               @cancel="showPicker = false"
               @change="onPickerChange"
            />
         </van-popup>
         <van-popup v-model:show="showCustomerPicker" destroy-on-close position="bottom">
            <van-picker
         </u-popup>
         <!-- 客户选择弹窗 -->
         <u-popup v-model="showCustomerPicker" mode="bottom">
            <view class="picker-header">
               <view class="picker-cancel" @click="showCustomerPicker = false">取消</view>
               <view class="picker-title">选择客户</view>
               <view class="picker-confirm" @click="confirmCustomer">确定</view>
            </view>
            <u-picker
               :columns="customerOption"
               v-model="pickerCustomerValue"
               @confirm="onCustomerConfirm"
               @cancel="showCustomerPicker = false"
               @change="onCustomerPickerChange"
            />
         </van-popup>
         </u-popup>
         
         <!-- 产品大类选择器 -->
         <van-popup v-model:show="showCategoryPicker" destroy-on-close position="bottom">
         <u-popup v-model="showCategoryPicker" mode="bottom">
            <!-- 头部按钮区域 -->
            <view class="popup-header">
               <view @click="showCategoryPicker = false" class="cancelButton">取消</view>
@@ -91,175 +115,209 @@
               check-strictly
               @check-change="onCategoryConfirm"
            />
         </van-popup>
         </u-popup>
         
         <!-- 规格型号选择器 -->
         <van-popup v-model:show="showSpecificationPicker" destroy-on-close position="bottom">
            <van-picker
         <u-popup v-model="showSpecificationPicker" mode="bottom">
            <u-picker
               :columns="modelOptions"
               v-model="pickerSpecificationValue"
               @confirm="onSpecificationConfirm"
               @cancel="showSpecificationPicker = false"
            />
         </van-popup>
         </u-popup>
         
         <!-- 税率选择器 -->
         <van-popup v-model:show="showTaxRatePicker" destroy-on-close position="bottom">
            <van-picker
         <u-popup v-model="showTaxRatePicker" mode="bottom">
            <u-picker
               :columns="taxRateOptions"
               v-model="pickerTaxRateValue"
               @confirm="onTaxRateConfirm"
               @cancel="showTaxRatePicker = false"
            />
         </van-popup>
         </u-popup>
         
         <!-- 发票类型选择器 -->
         <van-popup v-model:show="showInvoiceTypePicker" destroy-on-close position="bottom">
            <van-picker
         <u-popup v-model="showInvoiceTypePicker" mode="bottom">
            <u-picker
               :columns="invoiceTypeOptions"
               v-model="pickerInvoiceTypeValue"
               @confirm="onInvoiceTypeConfirm"
               @cancel="showInvoiceTypePicker = false"
            />
         </van-popup>
         </u-popup>
         <!-- 产品信息 -->
         <view class="product-section">
            <view class="section-header">
               <text class="section-title">产品信息</text>
               <van-button type="primary" size="small" @click="addProduct" class="add-btn" icon="plus"  v-if="operationType !== 'view'">新增</van-button>
               <u-button type="primary" size="small" @click="addProduct" class="add-btn" v-if="operationType !== 'view'">
                  <u-icon name="plus" size="14" />
                  新增
               </u-button>
            </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" />
                     <u-icon name="file-text" color="#2979ff" size="15" />
                     <text class="product-productCategory">产品 {{ idx + 1 }}</text>
                  </view>
                  <!-- 操作按钮 -->
                  <view class="product-actions"  v-if="operationType !== 'view'">
                     <van-button type="danger" size="mini" @click="removeProduct(idx)" class="del-btn" icon="delete">删除</van-button>
                  <view class="product-actions" v-if="operationType !== 'view'">
                     <u-button type="error" size="mini" @click="removeProduct(idx)" class="del-btn">
                        <u-icon name="trash" size="12" />
                        删除
                     </u-button>
                  </view>
               </view>
               
               <!-- 产品信息表单 -->
               <view class="product-form">
                  <!-- 产品大类 -->
                  <van-field
                     v-model="product.productCategory"
                     is-link
                     readonly
                     name="productCategory"
                  <u-form-item
                     label="产品大类"
                     prop="productCategory"
                     required
                     placeholder="请选择"
                     :rules="[{ required: true, message: '请选择' }]"
                     @click="openCategoryPicker(idx)"
                  />
                     border-bottom
                  >
                     <u-input
                        v-model="product.productCategory"
                        readonly
                        placeholder="请选择"
                        @click="openCategoryPicker(idx)"
                     />
                  </u-form-item>
                  
                  <!-- 规格型号 -->
                  <van-field
                     v-model="product.specificationModel"
                     is-link
                     readonly
                     name="specificationModel"
                  <u-form-item
                     label="规格型号"
                     prop="specificationModel"
                     required
                     :rules="[{ required: true, message: '请选择' }]"
                     placeholder="请选择"
                     @click="openSpecificationPicker(idx)"
                  />
                     border-bottom
                  >
                     <u-input
                        v-model="product.specificationModel"
                        readonly
                        placeholder="请选择"
                        @click="openSpecificationPicker(idx)"
                     />
                  </u-form-item>
                  
                  <!-- 单位 -->
                  <van-field
                     v-model="product.unit"
                     name="unit"
                  <u-form-item
                     label="单位"
                     prop="unit"
                     required
                     :rules="[{ required: true, message: '请输入' }]"
                     placeholder="请输入"
                  />
                     border-bottom
                  >
                     <u-input
                        v-model="product.unit"
                        placeholder="请输入"
                     />
                  </u-form-item>
                  
                  <!-- 税率 -->
                  <van-field
                     v-model="product.taxRate"
                     is-link
                     readonly
                     name="taxRate"
                  <u-form-item
                     label="税率(%)"
                     prop="taxRate"
                     required
                     :rules="[{ required: true, message: '请选择' }]"
                     placeholder="请选择"
                     @click="openTaxRatePicker(idx)"
                  />
                     border-bottom
                  >
                     <u-input
                        v-model="product.taxRate"
                        readonly
                        placeholder="请选择"
                        @click="openTaxRatePicker(idx)"
                     />
                  </u-form-item>
                  
                  <!-- 含税单价 -->
                  <van-field
                     v-model="product.taxInclusiveUnitPrice"
                     name="taxInclusiveUnitPrice"
                  <u-form-item
                     label="含税单价(元)"
                     type="number"
                     prop="taxInclusiveUnitPrice"
                     required
                     :rules="[{ required: true, message: '请输入' }]"
                     placeholder="请输入"
                     @blur="formatTaxPrice(idx)"
                  />
                     border-bottom
                  >
                     <u-input
                        v-model="product.taxInclusiveUnitPrice"
                        type="number"
                        placeholder="请输入"
                        @blur="formatTaxPrice(idx)"
                     />
                  </u-form-item>
                  
                  <!-- 数量 -->
                  <van-field
                     v-model="product.quantity"
                     name="quantity"
                  <u-form-item
                     label="数量"
                     type="number"
                     :rules="[{ required: true, message: '请输入' }]"
                     prop="quantity"
                     required
                     placeholder="请输入"
                     @blur="formatAmount(idx)"
                  />
                     border-bottom
                  >
                     <u-input
                        v-model="product.quantity"
                        type="number"
                        placeholder="请输入"
                        @blur="formatAmount(idx)"
                     />
                  </u-form-item>
                  
                  <!-- 含税总价 -->
                  <van-field
                     v-model="product.taxInclusiveTotalPrice"
                     name="taxInclusiveTotalPrice"
                  <u-form-item
                     label="含税总价(元)"
                     type="number"
                     :rules="[{ required: true, message: '请输入' }]"
                     prop="taxInclusiveTotalPrice"
                     required
                     placeholder="请输入"
                     @blur="formatTaxTotal(idx)"
                  />
                     border-bottom
                  >
                     <u-input
                        v-model="product.taxInclusiveTotalPrice"
                        type="number"
                        placeholder="请输入"
                        @blur="formatTaxTotal(idx)"
                     />
                  </u-form-item>
                  
                  <!-- 不含税总价 -->
                  <van-field
                     v-model="product.taxExclusiveTotalPrice"
                     name="taxExclusiveTotalPrice"
                  <u-form-item
                     label="不含税总价(元)"
                     type="number"
                     prop="taxExclusiveTotalPrice"
                     required
                     :rules="[{ required: true, message: '请输入' }]"
                     placeholder="请输入"
                     @blur="formatNoTaxTotal(idx)"
                  />
                     border-bottom
                  >
                     <u-input
                        v-model="product.taxExclusiveTotalPrice"
                        type="number"
                        placeholder="请输入"
                        @blur="formatNoTaxTotal(idx)"
                     />
                  </u-form-item>
                  
                  <!-- 发票类型 -->
                  <van-field
                     v-model="product.invoiceType"
                     is-link
                     readonly
                     name="invoiceType"
                  <u-form-item
                     label="发票类型"
                     :rules="[{ required: true, message: '请选择' }]"
                     prop="invoiceType"
                     required
                     placeholder="请选择"
                     @click="openInvoiceTypePicker(idx)"
                  />
                     border-bottom
                  >
                     <u-input
                        v-model="product.invoiceType"
                        readonly
                        placeholder="请选择"
                        @click="openInvoiceTypePicker(idx)"
                     />
                  </u-form-item>
               </view>
            </view>
         </view>
         <view class="footer-btns" v-if="operationType !== 'view'">
            <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>
      </u-form>
      <!-- 使用公共底部按钮组件 -->
      <FooterButtons
         :show="operationType !== 'view'"
         cancelText="取消"
         confirmText="保存"
         @cancel="goBack"
         @confirm="onSubmit"
      />
  </view>
</template>
@@ -276,6 +334,8 @@
} from "@/api/salesManagement/salesLedger";
import useUserStore from "@/store/modules/user";
import {calculateTaxExclusiveTotalPrice} from "@/utils/summarizeTable";
import PageHeader from '@/components/PageHeader.vue';
import FooterButtons from '@/components/FooterButtons.vue';
// 获取页面参数
const operationType = ref('');
@@ -314,6 +374,12 @@
const pickerSpecificationValue = ref(['']);
const pickerTaxRateValue = ref(['']);
const pickerInvoiceTypeValue = ref(['']);
// 临时存储选择器选中的值
const tempSalesmanValue = ref('');
const tempCustomerValue = ref('');
const selectedSalesman = ref(null);
const selectedCustomer = ref(null);
const currentProductIndex = ref(0);
// 选项数据
@@ -356,15 +422,58 @@
    invoiceType: ''
  });
};
const onConfirm = ({ selectedValues, selectedOptions }) => {
   form.value.salesman = selectedOptions[0]?.text;
   pickerValue.value = [selectedValues[0]];
// 业务员选择器变化事件
const onPickerChange = ({ selectedValues, selectedOptions }) => {
   selectedSalesman.value = selectedOptions[0];
   tempSalesmanValue.value = {
      text: selectedOptions[0]?.text,
      value: selectedOptions[0]?.value
   };
};
// 确认选择业务员
const confirmSalesman = () => {
   if (selectedSalesman.value) {
      form.value.salesman = selectedSalesman.value.text;
      pickerValue.value = [selectedSalesman.value.value];
   }
   showPicker.value = false;
};
// 客户选择器变化事件
const onCustomerPickerChange = ({ selectedValues, selectedOptions }) => {
   selectedCustomer.value = selectedOptions[0];
   tempCustomerValue.value = {
      text: selectedOptions[0]?.text,
      value: selectedOptions[0]?.value
   };
};
// 确认选择客户
const confirmCustomer = () => {
   if (selectedCustomer.value) {
      form.value.customerName = selectedCustomer.value.text;
      form.value.customerId = selectedCustomer.value.value;
      pickerCustomerValue.value = [selectedCustomer.value.value];
   }
   showCustomerPicker.value = false;
};
// 修改原有的确认方法(保持兼容性)
const onConfirm = ({ selectedValues, selectedOptions }) => {
   if (selectedOptions && selectedOptions[0]) {
      form.value.salesman = selectedOptions[0].text;
      pickerValue.value = [selectedValues[0]];
   }
   showPicker.value = false;
};
const onCustomerConfirm = ({ selectedValues, selectedOptions }) => {
   form.value.customerName = selectedOptions[0]?.text;
   form.value.customerId = selectedOptions[0]?.value;
   pickerCustomerValue.value = [selectedValues[0]];
   if (selectedOptions && selectedOptions[0]) {
      form.value.customerName = selectedOptions[0].text;
      form.value.customerId = selectedOptions[0].value;
      pickerCustomerValue.value = [selectedValues[0]];
   }
   showCustomerPicker.value = false;
};
const onDateConfirm = ({ selectedValues }) => {
@@ -664,20 +773,20 @@
};
const getUserList = () => {
   userListNoPage().then((res) => {
      // 将用户数据组装成 picker 需要的格式
      userList.value = res.data.map(user => ({
      // 确保数据格式正确
      userList.value = [res.data.map(user => ({
         text: user.nickName,
         value: user.nickName
      }));
      }))];
   })
}
const getCustomerList = () => {
   customerList().then((res) => {
      // 将用户数据组装成 picker 需要的格式
      customerOption.value = res.map(item => ({
      // 确保数据格式正确
      customerOption.value = [res.map(item => ({
         text: item.customerName,
         value: item.id
      }));
      }))];
   })
}
const convertIdToValue = (data) => {
@@ -745,6 +854,7 @@
  background: #f8f9fa;
  padding-bottom: 5rem;
}
.header {
  display: flex;
  align-items: center;
@@ -757,6 +867,7 @@
   /* 兼容 iOS 刘海/灵动岛安全区 */
   padding-top: env(safe-area-inset-top);
}
.title {
  flex: 1;
  text-align: center;
@@ -764,6 +875,7 @@
  font-weight: 600;
  color: #333;
}
.form-section {
   margin-top: 1rem;
}
@@ -779,17 +891,20 @@
  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-card {
   background: #FFFFFF;
   box-shadow: 0 0 1.25rem 0 rgba(0,57,117,0.08);
@@ -797,6 +912,7 @@
  padding: 1rem 0.5rem 0 0.5rem;
  position: relative;
}
.product-header {
  display: flex;
  align-items: center;
@@ -804,70 +920,46 @@
  padding: 0 0.5rem 0.75rem 0.5rem;
  border-bottom: 0.0625rem solid #e8e8e8;
}
.product-productCategory {
  margin-left: 0.5rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: #333;
}
.info-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
  margin-bottom: 1rem;
}
.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;
}
.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;
}
.popup-header {
@@ -880,13 +972,102 @@
   top: 0;
   z-index: 10;
}
.cancelButton {
   color: #969799
}
.confirmButton {
   color: #1989FA
}
.u-tree {
   height: 13rem;
}
/* 移除 input 边框的样式 */
:deep(.u-input) {
  border: none !important;
  box-shadow: none !important;
  background: transparent !important;
}
:deep(.u-input__content) {
  border: none !important;
  box-shadow: none !important;
  background: transparent !important;
}
:deep(.u-input__content__field-wrapper) {
  border: none !important;
  box-shadow: none !important;
  background: transparent !important;
}
:deep(.u-input__content__field-wrapper__field) {
  border: none !important;
  box-shadow: none !important;
  background: transparent !important;
  outline: none !important;
}
/* 移除 textarea 边框的样式 */
:deep(.u-textarea) {
  border: none !important;
  box-shadow: none !important;
  background: transparent !important;
}
:deep(.u-textarea__content) {
  border: none !important;
  box-shadow: none !important;
  background: transparent !important;
}
:deep(.u-textarea__content__field) {
  border: none !important;
  box-shadow: none !important;
  background: transparent !important;
  outline: none !important;
}
/* 移除 form-item 的边框 */
:deep(.u-form-item) {
  border: none !important;
}
:deep(.u-form-item__body) {
  border: none !important;
}
/* 保持分割线样式 */
:deep(.u-form-item--border-bottom) {
  border-bottom: 1px solid #ebeef5 !important;
}
/* 选择器头部样式 */
.picker-header {
   display: flex;
   justify-content: space-between;
   align-items: center;
   padding: 15px 20px;
   background: #fff;
   border-bottom: 1px solid #ebeef5;
}
.picker-cancel {
   color: #909399;
   font-size: 16px;
}
.picker-title {
   color: #303133;
   font-size: 16px;
   font-weight: 500;
}
.picker-confirm {
   color: #2979ff;
   font-size: 16px;
}
</style>