销售管理适配手机端

This commit is contained in:
2026-03-06 14:46:40 +08:00
parent 8ca2e6d52f
commit 1b3863bd7e
21 changed files with 4164 additions and 3889 deletions

View File

@@ -1,71 +1,50 @@
<template> <template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="800px" class="customer-form-dialog"> <el-drawer
<el-form v-model="dialogVisible"
ref="formRef" :title="dialogTitle"
:model="formData" direction="rtl"
:rules="formRules" size="100%"
label-width="120px" :close-on-press-escape="true"
v-loading="formLoading" :destroy-on-close="true"
class="customer-form" :append-to-body="true"
> class="mobile-form-drawer"
<el-row :gutter="20"> >
<el-col :span="24"> <div class="mobile-form" v-loading="formLoading">
<el-divider class="customer-section-divider">基础信息</el-divider> <el-form
</el-col> ref="formRef"
<el-col :span="12" :xs="24" :sm="12"> :model="formData"
:rules="formRules"
label-position="top"
>
<!-- 基础信息 -->
<div class="mobile-form__section">
<div class="mobile-form__section-title">基础信息</div>
<el-form-item label="名称" prop="name"> <el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入名称" /> <el-input v-model="formData.name" placeholder="请输入名称" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="联系人" prop="contact"> <el-form-item label="联系人" prop="contact">
<el-input v-model="formData.contact" placeholder="请输入联系人" /> <el-input v-model="formData.contact" placeholder="请输入联系人" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="手机号码" prop="mobile"> <el-form-item label="手机号码" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号码" /> <el-input v-model="formData.mobile" placeholder="请输入手机号码" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="联系电话" prop="telephone"> <el-form-item label="联系电话" prop="telephone">
<el-input v-model="formData.telephone" placeholder="请输入联系电话" /> <el-input v-model="formData.telephone" placeholder="请输入联系电话" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="电子邮箱" prop="email"> <el-form-item label="电子邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入电子邮箱" /> <el-input v-model="formData.email" placeholder="请输入电子邮箱" />
</el-form-item> </el-form-item>
</el-col> <!-- <el-form-item label="传真" prop="fax">
<!-- <el-col :span="12" :xs="24" :sm="12">
<el-form-item label="传真" prop="fax">
<el-input v-model="formData.fax" placeholder="请输入传真" /> <el-input v-model="formData.fax" placeholder="请输入传真" />
</el-form-item> </el-form-item> -->
</el-col> --> <!-- <el-form-item label="标签集合" prop="tags">
<!-- <el-col :span="12" :xs="24" :sm="12">
<el-form-item label="标签集合" prop="tags">
<el-input v-model="formData.tags" placeholder="请输入标签,逗号分隔" /> <el-input v-model="formData.tags" placeholder="请输入标签,逗号分隔" />
</el-form-item> </el-form-item> -->
</el-col> --> <!-- <el-form-item label="税率(%)" prop="taxPercent">
<el-input-number v-model="formData.taxPercent" :min="0" :precision="4" placeholder="请输入税率" style="width:100%" />
<!-- <el-col :span="12" :xs="24" :sm="12"> </el-form-item> -->
<el-form-item label="税率(%)" prop="taxPercent">
<el-input-number
v-model="formData.taxPercent"
:min="0"
:precision="4"
placeholder="请输入税率"
class="!w-1/1"
/>
</el-form-item>
</el-col> -->
<!-- <el-col :span="24">
<el-divider class="customer-section-divider">企业信息</el-divider>
</el-col> -->
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="企业类型" prop="companyType"> <el-form-item label="企业类型" prop="companyType">
<el-select v-model="formData.companyType" placeholder="请选择企业类型" class="!w-1/1"> <el-select v-model="formData.companyType" placeholder="请选择企业类型" style="width:100%">
<el-option label="餐饮" :value="1" /> <el-option label="餐饮" :value="1" />
<el-option label="食品批发" :value="2" /> <el-option label="食品批发" :value="2" />
<el-option label="制造" :value="3" /> <el-option label="制造" :value="3" />
@@ -73,19 +52,11 @@
<el-option label="其他" :value="5" /> <el-option label="其他" :value="5" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="企业规模" prop="businessScale"> <el-form-item label="企业规模" prop="businessScale">
<el-input v-model="formData.businessScale" placeholder="请输入企业规模" /> <el-input v-model="formData.businessScale" placeholder="请输入企业规模" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="客户来源" prop="leadSourceType"> <el-form-item label="客户来源" prop="leadSourceType">
<el-select <el-select v-model="formData.leadSourceType" placeholder="请选择来源类型" style="width:100%">
v-model="formData.leadSourceType"
placeholder="请选择来源类型"
class="!w-1/1"
>
<el-option label="展会" :value="1" /> <el-option label="展会" :value="1" />
<el-option label="地推" :value="2" /> <el-option label="地推" :value="2" />
<el-option label="转介绍" :value="3" /> <el-option label="转介绍" :value="3" />
@@ -96,275 +67,137 @@
<el-option label="其他" :value="99" /> <el-option label="其他" :value="99" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> <!-- <el-form-item label="年采购量" prop="annualPurchaseVolume">
<!-- <el-col :span="12" :xs="24" :sm="12"> <el-input-number v-model="formData.annualPurchaseVolume" :min="0" :precision="2" placeholder="请输入年采购量" style="width:100%" />
<el-form-item label="年采购量" prop="annualPurchaseVolume">
<el-input-number
v-model="formData.annualPurchaseVolume"
:min="0"
:precision="2"
placeholder="请输入年采购量"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="年采购金额" prop="annualPurchaseAmount"> <el-form-item label="年采购金额" prop="annualPurchaseAmount">
<el-input-number <el-input-number v-model="formData.annualPurchaseAmount" :min="0" :precision="2" placeholder="请输入年采购金额" style="width:100%" />
v-model="formData.annualPurchaseAmount" </el-form-item> -->
:min="0" </div>
:precision="2"
placeholder="请输入年采购金额" <!-- 财务信息 -->
class="!w-1/1" <div class="mobile-form__section">
/> <div class="mobile-form__section-title">财务信息</div>
</el-form-item>
</el-col> -->
<el-col :span="24">
<el-divider />
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="纳税人识别号" prop="taxNo"> <el-form-item label="纳税人识别号" prop="taxNo">
<el-input v-model="formData.taxNo" placeholder="请输入纳税人识别号" /> <el-input v-model="formData.taxNo" placeholder="请输入纳税人识别号" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="开户行" prop="bankName"> <el-form-item label="开户行" prop="bankName">
<el-input v-model="formData.bankName" placeholder="请输入开户行" /> <el-input v-model="formData.bankName" placeholder="请输入开户行" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="开户账号" prop="bankAccount"> <el-form-item label="开户账号" prop="bankAccount">
<el-input v-model="formData.bankAccount" placeholder="请输入开户账号" /> <el-input v-model="formData.bankAccount" placeholder="请输入开户账号" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="开户地址" prop="bankAddress"> <el-form-item label="开户地址" prop="bankAddress">
<el-input v-model="formData.bankAddress" placeholder="请输入开户地址" /> <el-input v-model="formData.bankAddress" placeholder="请输入开户地址" />
</el-form-item> </el-form-item>
</el-col> </div>
<!-- <el-col :span="24">
<el-divider class="customer-section-divider">偏好</el-divider> <!-- 偏好信息 -->
</el-col> --> <div class="mobile-form__section">
<el-col :span="12" :xs="24" :sm="12"> <div class="mobile-form__section-title">偏好信息</div>
<el-form-item label="偏好产品" prop="preferredProducts"> <el-form-item label="偏好产品" prop="preferredProducts">
<el-input v-model="formData.preferredProducts" placeholder="请输入偏好产品或品类" /> <el-input v-model="formData.preferredProducts" placeholder="请输入偏好产品或品类" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="偏好包装" prop="preferredPackaging"> <el-form-item label="偏好包装" prop="preferredPackaging">
<el-input v-model="formData.preferredPackaging" placeholder="请输入偏好包装形式" /> <el-input v-model="formData.preferredPackaging" placeholder="请输入偏好包装形式" />
</el-form-item> </el-form-item>
</el-col> <!-- <el-form-item label="质量/认证要求" prop="qualityCertRequirements">
<!-- <el-col :span="12" :xs="24" :sm="12">
<el-form-item label="质量/认证要求" prop="qualityCertRequirements">
<el-input v-model="formData.qualityCertRequirements" placeholder="请输入质量/认证要求" /> <el-input v-model="formData.qualityCertRequirements" placeholder="请输入质量/认证要求" />
</el-form-item> </el-form-item> -->
</el-col> -->
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="偏好交期" prop="deliveryCyclePrefer"> <el-form-item label="偏好交期" prop="deliveryCyclePrefer">
<el-input v-model="formData.deliveryCyclePrefer" placeholder="请输入偏好交期/周期" /> <el-input v-model="formData.deliveryCyclePrefer" placeholder="请输入偏好交期/周期" />
</el-form-item> </el-form-item>
</el-col> <!-- <el-form-item label="付款条件" prop="paymentTerms">
<!-- <el-col :span="12" :xs="24" :sm="12">
<el-form-item label="付款条件" prop="paymentTerms">
<el-input v-model="formData.paymentTerms" placeholder="请输入付款条件" /> <el-input v-model="formData.paymentTerms" placeholder="请输入付款条件" />
</el-form-item> </el-form-item> -->
</el-col> --> </div>
<el-col :span="24">
<el-divider />
</el-col>
<!-- <el-col :span="12" :xs="24" :sm="12">
<el-form-item label="上次交付时间" prop="lastDeliveryTime">
<el-date-picker
v-model="formData.lastDeliveryTime"
type="datetime"
value-format="x"
placeholder="选择上次交付时间"
class="!w-1/1"
/>
</el-form-item>
</el-col> -->
<!-- <el-col :span="24">
<el-form-item label="产品送达地址" prop="deliveryAddress">
<el-input
type="textarea"
v-model="formData.deliveryAddress"
placeholder="请输入产品送达地址"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-divider>资质与风险</el-divider>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="营业执照编号" prop="businessLicenseNo">
<el-input v-model="formData.businessLicenseNo" placeholder="请输入营业执照编号" />
</el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="许可证有效期" prop="licenseValidity">
<el-date-picker
v-model="formData.licenseValidity"
type="date"
value-format="x"
placeholder="选择许可证有效期"
class="!w-1/1"
/>
</el-form-item>
</el-col> -->
<!-- <el-col :span="12" :xs="24" :sm="12">
<el-form-item label="客户风险级别" prop="riskLevel">
<el-select v-model="formData.riskLevel" placeholder="请选择风险级别" class="!w-1/1">
<el-option label="低" :value="1" />
<el-option label="中" :value="2" />
<el-option label="高" :value="3" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="指定物流合作伙伴" prop="logisticsPartner">
<el-input v-model="formData.logisticsPartner" placeholder="请输入指定物流合作伙伴" />
</el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="需冷链配送" prop="requiresColdChain">
<el-radio-group v-model="formData.requiresColdChain">
<el-radio :value="true"></el-radio>
<el-radio :value="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="服务区域" prop="serviceRegion">
<el-input v-model="formData.serviceRegion" placeholder="请输入服务区域" />
</el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="客情等级" prop="relationshipLevel">
<el-select
v-model="formData.relationshipLevel"
placeholder="请选择客情等级"
class="!w-1/1"
>
<el-option label="一般" :value="1" />
<el-option label="良好" :value="2" />
<el-option label="紧密" :value="3" />
<el-option label="关键" :value="4" />
</el-select>
</el-form-item>
</el-col> -->
<!-- <el-col :span="24"> <!-- <el-form-item label="上次交付时间" prop="lastDeliveryTime">
<el-form-item label="来源详情" prop="leadSourceDetail"> <el-date-picker v-model="formData.lastDeliveryTime" type="datetime" value-format="x" placeholder="选择上次交付时间" style="width:100%" />
<el-input </el-form-item> -->
type="textarea" <!-- <el-form-item label="产品送达地址" prop="deliveryAddress">
v-model="formData.leadSourceDetail" <el-input type="textarea" v-model="formData.deliveryAddress" placeholder="请输入产品送达地址" />
placeholder="请输入来源详情" </el-form-item> -->
/> <!-- 资质与风险 -->
</el-form-item> <!-- <el-form-item label="营业执照编号" prop="businessLicenseNo">
</el-col> <el-input v-model="formData.businessLicenseNo" placeholder="请输入营业执照编号" />
<el-col :span="12" :xs="24" :sm="12"> </el-form-item>
<el-form-item label="线索评分" prop="leadScore"> <el-form-item label="许可证有效期" prop="licenseValidity">
<el-input-number <el-date-picker v-model="formData.licenseValidity" type="date" value-format="x" placeholder="选择许可证有效期" style="width:100%" />
v-model="formData.leadScore" </el-form-item> -->
:min="0" <!-- <el-form-item label="客户风险级别" prop="riskLevel">
:max="100" <el-select v-model="formData.riskLevel" placeholder="请选择风险级别" style="width:100%">
:precision="0" <el-option label="" :value="1" />
placeholder="请输入线索评分" <el-option label="中" :value="2" />
class="!w-1/1" <el-option label="高" :value="3" />
/> </el-select>
</el-form-item> </el-form-item>
</el-col> <el-form-item label="指定物流合作伙伴" prop="logisticsPartner">
<el-col :span="12" :xs="24" :sm="12"> <el-input v-model="formData.logisticsPartner" placeholder="请输入指定物流合作伙伴" />
<el-form-item label="潜力等级" prop="potentialLevel"> </el-form-item>
<el-select <el-form-item label="需冷链配送" prop="requiresColdChain">
v-model="formData.potentialLevel" <el-radio-group v-model="formData.requiresColdChain">
placeholder="请选择潜力等级" <el-radio :value="true"></el-radio>
class="!w-1/1" <el-radio :value="false"></el-radio>
> </el-radio-group>
<el-option label="低" :value="1" /> </el-form-item>
<el-option label="中" :value="2" /> <el-form-item label="服务区域" prop="serviceRegion">
<el-option label="高" :value="3" /> <el-input v-model="formData.serviceRegion" placeholder="请输入服务区域" />
</el-select> </el-form-item>
</el-form-item> <el-form-item label="客情等级" prop="relationshipLevel">
</el-col> <el-select v-model="formData.relationshipLevel" placeholder="请选择客情等级" style="width:100%">
<el-col :span="12" :xs="24" :sm="12"> <el-option label="一般" :value="1" />
<el-form-item label="预估年采购量(吨/件)" prop="expectedAnnualVolume"> <el-option label="良好" :value="2" />
<el-input-number <el-option label="紧密" :value="3" />
v-model="formData.expectedAnnualVolume" <el-option label="关键" :value="4" />
:min="0" </el-select>
:precision="2" </el-form-item> -->
placeholder="请输入预估年采购量" <!-- <el-form-item label="来源详情" prop="leadSourceDetail">
class="!w-1/1" <el-input type="textarea" v-model="formData.leadSourceDetail" placeholder="请输入来源详情" />
/> </el-form-item>
</el-form-item> <el-form-item label="线索评分" prop="leadScore">
</el-col> <el-input-number v-model="formData.leadScore" :min="0" :max="100" :precision="0" placeholder="请输入线索评分" style="width:100%" />
<el-col :span="12" :xs="24" :sm="12"> </el-form-item>
<el-form-item label="预估年采购金额" prop="expectedAnnualAmount"> <el-form-item label="潜力等级" prop="potentialLevel">
<el-input-number <el-select v-model="formData.potentialLevel" placeholder="请选择潜力等级" style="width:100%">
v-model="formData.expectedAnnualAmount" <el-option label="低" :value="1" />
:min="0" <el-option label="中" :value="2" />
:precision="2" <el-option label="" :value="3" />
placeholder="请输入预估年采购金额" </el-select>
class="!w-1/1" </el-form-item>
/> <el-form-item label="预估年采购量(吨/件)" prop="expectedAnnualVolume">
</el-form-item> <el-input-number v-model="formData.expectedAnnualVolume" :min="0" :precision="2" placeholder="请输入预估年采购量" style="width:100%" />
</el-col> </el-form-item>
<el-col :span="12" :xs="24" :sm="12"> <el-form-item label="预估年采购金额" prop="expectedAnnualAmount">
<el-form-item label="采购周期" prop="purchaseCycle"> <el-input-number v-model="formData.expectedAnnualAmount" :min="0" :precision="2" placeholder="请输入预估年采购金额" style="width:100%" />
<el-input v-model="formData.purchaseCycle" placeholder="如周采/月采/季度/项目制" /> </el-form-item>
</el-form-item> <el-form-item label="采购周期" prop="purchaseCycle">
</el-col> --> <el-input v-model="formData.purchaseCycle" placeholder="如周采/月采/季度/项目制" />
<!-- <el-col :span="24"> </el-form-item> -->
<el-divider class="customer-section-divider">备注</el-divider>
</el-col> --> <!-- 统计信息 -->
<el-col :span="12" :xs="24" :sm="12"> <div class="mobile-form__section">
<div class="mobile-form__section-title">统计信息</div>
<el-form-item label="年度订单数" prop="annualOrderNums"> <el-form-item label="年度订单数" prop="annualOrderNums">
<el-input <el-input :model-value="formatInteger(formData.annualOrderNums)" placeholder="系统自动生成" disabled />
:model-value="formatInteger(formData.annualOrderNums)"
placeholder="系统自动生成"
disabled
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="年度订单额" prop="annualOrderAmounts"> <el-form-item label="年度订单额" prop="annualOrderAmounts">
<el-input <el-input :model-value="formatAmount(formData.annualOrderAmounts)" placeholder="系统自动生成" disabled />
:model-value="formatAmount(formData.annualOrderAmounts)"
placeholder="系统自动生成"
disabled
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="年度已收款" prop="annualReceivedAmounts"> <el-form-item label="年度已收款" prop="annualReceivedAmounts">
<el-input <el-input :model-value="formatAmount(formData.annualReceivedAmounts)" placeholder="系统自动生成" disabled />
:model-value="formatAmount(formData.annualReceivedAmounts)"
placeholder="系统自动生成"
disabled
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="累计未收款" prop="totalUnreceivedAmounts"> <el-form-item label="累计未收款" prop="totalUnreceivedAmounts">
<el-input <el-input :model-value="formatAmount(formData.totalUnreceivedAmounts)" placeholder="系统自动生成" disabled />
:model-value="formatAmount(formData.totalUnreceivedAmounts)"
placeholder="系统自动生成"
disabled
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" /> <el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" />
</el-form-item> </el-form-item>
</el-col> </div>
<el-col :span="24"> <!-- 状态信息 -->
<el-divider class="customer-section-divider">状态信息</el-divider> <div class="mobile-form__section">
</el-col> <div class="mobile-form__section-title">状态信息</div>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="开启状态" prop="status"> <el-form-item label="开启状态" prop="status">
<el-radio-group v-model="formData.status"> <el-radio-group v-model="formData.status">
<el-radio <el-radio
@@ -376,24 +209,21 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12" :xs="24" :sm="12">
<el-form-item label="排序" prop="sort"> <el-form-item label="排序" prop="sort">
<el-input-number <el-input-number v-model="formData.sort" placeholder="请输入排序" style="width:100%" :precision="0" />
v-model="formData.sort"
placeholder="请输入排序"
class="!w-1/1"
:precision="0"
/>
</el-form-item> </el-form-item>
</el-col> </div>
</el-row> </el-form>
</el-form> </div>
<!-- 底部按钮 -->
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button> <div class="mobile-form__footer">
<el-button @click="dialogVisible = false"> </el-button> <el-button @click="dialogVisible = false" style="flex:1"> </el-button>
<el-button type="primary" @click="submitForm" :disabled="formLoading" style="flex:2"> </el-button>
</div>
</template> </template>
</Dialog> </el-drawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
@@ -578,19 +408,30 @@ const resetForm = () => {
formRef.value?.resetFields() formRef.value?.resetFields()
} }
</script> </script>
<style scoped> <style lang="scss" scoped>
:deep(.customer-form .el-form-item__label) { .mobile-form {
white-space: nowrap !important; padding: 12px;
overflow: hidden;
text-overflow: ellipsis;
} }
:deep(.customer-form .customer-section-divider) { .mobile-form__section {
margin: 16px 0 12px; background: #fff;
border-radius: 8px;
padding: 14px;
margin-bottom: 12px;
} }
:deep(.customer-form-dialog .el-dialog__body) { .mobile-form__section-title {
padding-left: 12px; font-size: 15px;
padding-right: 12px; font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
}
.mobile-form__footer {
display: flex;
gap: 12px;
padding: 0 12px;
} }
</style> </style>

View File

@@ -1,118 +1,101 @@
<template> <template>
<doc-alert title="【销售】销售订单、出库、退货" url="https://doc.iocoder.cn/erp/sale/" /> <div class="mobile-customer">
<!-- 顶部操作栏 -->
<ContentWrap> <div class="mobile-header">
<!-- 搜索工作栏 --> <div class="mobile-header__search">
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="名称" prop="name">
<el-input <el-input
v-model="queryParams.name" v-model="queryParams.name"
placeholder="请输入名称" placeholder="搜索客户名称"
clearable clearable
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
class="!w-240px" :prefix-icon="Search"
/> />
</el-form-item> </div>
<el-form-item label="手机号码" prop="mobile"> <div class="mobile-header__actions">
<el-input <el-button :icon="Filter" circle @click="filterVisible = true" />
v-model="queryParams.mobile"
placeholder="请输入手机号码"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="联系电话" prop="telephone">
<el-input
v-model="queryParams.telephone"
placeholder="请输入联系电话"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button <el-button
type="primary" type="primary"
plain :icon="Plus"
circle
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['erp:customer:create']" v-hasPermi="['erp:customer:create']"
> />
<Icon icon="ep:plus" class="mr-5px" /> 新增 </div>
</el-button> </div>
<el-button
type="success" <!-- 卡片列表 -->
plain <div class="mobile-list" v-loading="loading">
@click="handleExport" <div v-if="list.length === 0 && !loading" class="mobile-empty">
:loading="exportLoading" <el-empty description="暂无客户" />
v-hasPermi="['erp:customer:export']" </div>
> <div
<Icon icon="ep:download" class="mr-5px" /> 导出 v-for="item in list"
</el-button> :key="item.id"
</el-form-item> class="mobile-card"
</el-form> @click="openForm('update', item.id)"
</ContentWrap> >
<div class="mobile-card__header">
<span class="mobile-card__name">{{ item.name }}</span>
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="item.status" />
</div>
<div class="mobile-card__body">
<div class="mobile-card__row" v-if="item.contact">
<span class="mobile-card__label">联系人</span>
<span class="mobile-card__value">{{ item.contact }}</span>
</div>
<div class="mobile-card__row" v-if="item.mobile">
<span class="mobile-card__label">手机号码</span>
<span class="mobile-card__value">{{ item.mobile }}</span>
</div>
<div class="mobile-card__row" v-if="item.remark">
<span class="mobile-card__label">备注</span>
<span class="mobile-card__value mobile-card__value--ellipsis">{{ item.remark }}</span>
</div>
</div>
<div class="mobile-card__footer">
<el-button size="small" type="primary" @click.stop="openForm('update', item.id)" v-hasPermi="['erp:customer:update']">编辑</el-button>
<el-button size="small" type="danger" @click.stop="handleDelete(item.id)" v-hasPermi="['erp:customer:delete']">删除</el-button>
</div>
</div>
</div>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" @row-click="handleRowClick">
<el-table-column label="名称" align="center" prop="name" />
<el-table-column label="联系人" align="center" prop="contact" />
<el-table-column label="手机号码" align="center" prop="mobile" />
<!-- <el-table-column label="联系电话" align="center" prop="telephone" />-->
<!-- <el-table-column label="电子邮箱" align="center" prop="email" />-->
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="排序" align="center" prop="sort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['erp:customer:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['erp:customer:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 --> <!-- 分页 -->
<Pagination <div class="mobile-pagination" v-if="total > 0">
:total="total" <Pagination
v-model:page="queryParams.pageNo" :total="total"
v-model:limit="queryParams.pageSize" v-model:page="queryParams.pageNo"
@pagination="getList" v-model:limit="queryParams.pageSize"
/> :page-sizes="[10, 20]"
</ContentWrap> layout="total, prev, pager, next"
:pager-count="5"
@pagination="getList"
/>
</div>
<!-- 表单弹窗添加/修改 --> <!-- 筛选抽屉 -->
<CustomerForm ref="formRef" @success="getList" /> <el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="50%">
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
<el-form-item label="手机号码" prop="mobile">
<el-input v-model="queryParams.mobile" placeholder="请输入手机号码" clearable />
</el-form-item>
<el-form-item label="联系电话" prop="telephone">
<el-input v-model="queryParams.telephone" placeholder="请输入联系电话" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="resetQuery">重置</el-button>
<el-button type="primary" @click="handleFilterConfirm">确认筛选</el-button>
</template>
</el-drawer>
<!-- 表单弹窗添加/修改 -->
<CustomerForm ref="formRef" @success="getList" />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Search, Filter, Plus } from '@element-plus/icons-vue'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download' import download from '@/utils/download'
import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer'
import CustomerForm from './CustomerForm.vue' import CustomerForm from './CustomerForm.vue'
@@ -126,6 +109,7 @@ const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中 const loading = ref(true) // 列表的加载中
const list = ref<CustomerVO[]>([]) // 列表的数据 const list = ref<CustomerVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数 const total = ref(0) // 列表的总页数
const filterVisible = ref(false) // 筛选抽屉
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@@ -148,25 +132,6 @@ const getList = async () => {
} }
} }
/** 行点击操作 */
const handleRowClick = (row: CustomerVO, column: any, event: MouseEvent) => {
// 检查是否点击了按钮、链接或其他交互元素
const target = event.target as HTMLElement
if (
target.tagName === 'BUTTON' ||
target.tagName === 'A' ||
target.tagName === 'I' ||
target.tagName === 'svg' ||
target.closest('button') ||
target.closest('a') ||
target.closest('.el-button') ||
target.closest('.el-checkbox')
) {
return
}
openForm('update', row.id)
}
/** 搜索按钮操作 */ /** 搜索按钮操作 */
const handleQuery = () => { const handleQuery = () => {
queryParams.pageNo = 1 queryParams.pageNo = 1
@@ -175,7 +140,13 @@ const handleQuery = () => {
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value?.resetFields()
handleQuery()
}
/** 筛选确认 */
const handleFilterConfirm = () => {
filterVisible.value = false
handleQuery() handleQuery()
} }
@@ -218,3 +189,106 @@ onMounted(() => {
getList() getList()
}) })
</script> </script>
<style lang="scss" scoped>
.mobile-customer {
padding: 12px;
background: #f5f5f5;
min-height: 100vh;
}
.mobile-header {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
&__search {
flex: 1;
}
&__actions {
display: flex;
gap: 4px;
flex-shrink: 0;
}
}
.mobile-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-empty {
padding: 40px 0;
}
.mobile-card {
background: #fff;
border-radius: 10px;
padding: 14px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
&__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
&__name {
font-weight: 600;
font-size: 15px;
color: #303133;
}
&__body {
font-size: 13px;
}
&__row {
display: flex;
justify-content: space-between;
padding: 3px 0;
}
&__label {
color: #909399;
flex-shrink: 0;
margin-right: 12px;
}
&__value {
color: #606266;
text-align: right;
&--ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200px;
}
}
&__footer {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid #f0f0f0;
}
}
.mobile-pagination {
margin-top: 12px;
display: flex;
justify-content: center;
:deep(.el-pagination) {
flex-wrap: wrap;
justify-content: center;
}
}
</style>

View File

@@ -1,92 +1,64 @@
<template> <template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1080"> <el-drawer
<el-form v-model="dialogVisible"
ref="formRef" :title="dialogTitle"
:model="formData" direction="rtl"
:rules="formRules" size="100%"
label-width="100px" :close-on-press-escape="true"
v-loading="formLoading" :destroy-on-close="true"
:disabled="disabled" :append-to-body="true"
> class="mobile-form-drawer"
<el-row :gutter="20"> >
<el-col :span="8"> <div class="mobile-form" v-loading="formLoading">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-position="top"
:disabled="disabled"
>
<!-- 基本信息 -->
<div class="mobile-form__section">
<div class="mobile-form__section-title">基本信息</div>
<el-form-item label="订单单号" prop="no"> <el-form-item label="订单单号" prop="no">
<el-input disabled v-model="formData.no" placeholder="保存时自动生成" /> <el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="订单时间" prop="orderTime"> <el-form-item label="订单时间" prop="orderTime">
<el-date-picker <el-date-picker
v-model="formData.orderTime" v-model="formData.orderTime"
type="date" type="date"
value-format="x" value-format="x"
placeholder="选择订单时间" placeholder="选择订单时间"
class="!w-1/1" style="width: 100%"
/> />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="客户" prop="customerId"> <el-form-item label="客户" prop="customerId">
<el-select <el-select v-model="formData.customerId" clearable filterable placeholder="请选择客户" style="width: 100%">
v-model="formData.customerId" <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择客户"
class="!w-1/1"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="销售人员" prop="saleUserId"> <el-form-item label="销售人员" prop="saleUserId">
<el-select <el-select v-model="formData.saleUserId" clearable filterable placeholder="请选择销售人员" style="width: 100%">
v-model="formData.saleUserId" <el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
clearable
filterable
placeholder="请选择销售人员"
class="!w-1/1"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input <el-input type="textarea" v-model="formData.remark" :rows="2" placeholder="请输入备注" />
type="textarea"
v-model="formData.remark"
:rows="1"
placeholder="请输入备注"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="附件" prop="fileUrl"> <el-form-item label="附件" prop="fileUrl">
<UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" />
</el-form-item> </el-form-item>
</el-col> </div>
</el-row>
<!-- 子表的表 --> <!-- 订单产品清 -->
<ContentWrap> <div class="mobile-form__section">
<el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> <div class="mobile-form__section-title">订单产品清单</div>
<el-tab-pane label="订单产品清单" name="item"> <SaleOrderItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" />
<SaleOrderItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> </div>
</el-tab-pane>
</el-tabs> <!-- 价格信息 -->
</ContentWrap> <div class="mobile-form__section">
<el-row :gutter="20"> <div class="mobile-form__section-title">价格信息</div>
<el-col :span="8">
<el-form-item label="优惠率(%" prop="discountPercent"> <el-form-item label="优惠率(%" prop="discountPercent">
<el-input-number <el-input-number
v-model="formData.discountPercent" v-model="formData.discountPercent"
@@ -94,43 +66,20 @@
:min="0" :min="0"
:precision="4" :precision="4"
placeholder="请输入优惠率" placeholder="请输入优惠率"
class="!w-1/1" style="width: 100%"
/> />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="收款优惠" prop="discountPrice"> <el-form-item label="收款优惠" prop="discountPrice">
<el-input <el-input disabled v-model="formData.discountPrice" :formatter="erpPriceInputFormatter" />
disabled
v-model="formData.discountPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="优惠后金额"> <el-form-item label="优惠后金额">
<el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结算账户" prop="accountId"> <el-form-item label="结算账户" prop="accountId">
<el-select <el-select v-model="formData.accountId" clearable filterable placeholder="请选择结算账户" style="width: 100%">
v-model="formData.accountId" <el-option v-for="item in accountList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择结算账户"
class="!w-1/1"
>
<el-option
v-for="item in accountList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="收取订金" prop="depositPrice"> <el-form-item label="收取订金" prop="depositPrice">
<el-input-number <el-input-number
v-model="formData.depositPrice" v-model="formData.depositPrice"
@@ -138,19 +87,23 @@
:min="0" :min="0"
:precision="4" :precision="4"
placeholder="请输入收取订金" placeholder="请输入收取订金"
class="!w-1/1" style="width: 100%"
/> />
</el-form-item> </el-form-item>
</el-col> </div>
</el-row> </el-form>
</el-form> </div>
<!-- 底部按钮 -->
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> <div class="mobile-form__footer">
<el-button @click="dialogVisible = false" style="flex:1"> </el-button>
</el-button> <el-button type="primary" @click="submitForm" :disabled="formLoading" v-if="!disabled" style="flex:2">
<el-button @click="dialogVisible = false"> </el-button>
</el-button>
</div>
</template> </template>
</Dialog> </el-drawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order' import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order'
@@ -315,3 +268,31 @@ const resetForm = () => {
formRef.value?.resetFields() formRef.value?.resetFields()
} }
</script> </script>
<style lang="scss" scoped>
.mobile-form {
padding: 12px;
}
.mobile-form__section {
background: #fff;
border-radius: 8px;
padding: 14px;
margin-bottom: 12px;
}
.mobile-form__section-title {
font-size: 15px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
}
.mobile-form__footer {
display: flex;
gap: 12px;
padding: 0 12px;
}
</style>

View File

@@ -4,21 +4,42 @@
:model="formData" :model="formData"
:rules="formRules" :rules="formRules"
v-loading="formLoading" v-loading="formLoading"
label-width="0px" label-position="top"
:inline-message="true" :inline-message="true"
:disabled="disabled" :disabled="disabled"
> >
<el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> <div class="mobile-item-list">
<el-table-column label="序号" type="index" align="center" width="60" /> <div
<el-table-column label="产品名称" min-width="180"> v-for="(row, $index) in formData"
<template #default="{ row, $index }"> :key="$index"
<el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!"> class="mobile-item-card"
>
<div class="mobile-item-card__header">
<span class="mobile-item-card__index">#{{ $index + 1 }}</span>
<span class="mobile-item-card__name">{{ row.productName || '未选择产品' }}</span>
<el-button
:disabled="disabled || formData.length === 1"
@click="handleDelete($index)"
link
type="danger"
size="small"
>
删除
</el-button>
</div>
<div class="mobile-item-card__body">
<el-form-item
label="产品"
:prop="`${$index}.productId`"
:rules="formRules.productId"
>
<el-select <el-select
v-model="row.productId" v-model="row.productId"
clearable clearable
filterable filterable
@change="onChangeProduct($event, row)" @change="onChangeProduct($event, row)"
placeholder="请选择产品" placeholder="请选择产品"
style="width: 100%"
> >
<el-option <el-option
v-for="item in productList" v-for="item in productList"
@@ -28,120 +49,97 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> <div class="mobile-item-card__info-row">
</el-table-column> <span class="mobile-item-card__info-label">库存</span>
<el-table-column label="库存" min-width="100"> <span class="mobile-item-card__info-value">{{ erpCountInputFormatter(row.stockCount) }}</span>
<template #default="{ row }"> </div>
<el-form-item class="mb-0px!"> <div class="mobile-item-card__info-row">
<el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> <span class="mobile-item-card__info-label">条码</span>
</el-form-item> <span class="mobile-item-card__info-value">{{ row.productBarCode || '-' }}</span>
</template> </div>
</el-table-column> <div class="mobile-item-card__info-row">
<el-table-column label="条码" min-width="150"> <span class="mobile-item-card__info-label">单位</span>
<template #default="{ row }"> <span class="mobile-item-card__info-value">{{ row.productUnitName || '-' }}</span>
<el-form-item class="mb-0px!"> </div>
<el-input disabled v-model="row.productBarCode" /> <div class="mobile-item-card__input-group">
</el-form-item> <el-form-item label="数量" :prop="`${$index}.count`" :rules="formRules.count">
</template> <el-input-number
</el-table-column> v-model="row.count"
<el-table-column label="单位" min-width="80"> controls-position="right"
<template #default="{ row }"> :min="0.0001"
<el-form-item class="mb-0px!"> :precision="4"
<el-input disabled v-model="row.productUnitName" /> style="width: 100%"
</el-form-item> />
</template> </el-form-item>
</el-table-column> <el-form-item label="产品单价" :prop="`${$index}.productPrice`">
<el-table-column label="数量" prop="count" fixed="right" min-width="140"> <el-input-number
<template #default="{ row, $index }"> v-model="row.productPrice"
<el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> controls-position="right"
<el-input-number :min="0.0001"
v-model="row.count" :precision="4"
controls-position="right" style="width: 100%"
:min="0.0001" />
:precision="4" </el-form-item>
class="!w-100%" </div>
/> <div class="mobile-item-card__info-row">
</el-form-item> <span class="mobile-item-card__info-label">金额</span>
</template> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.totalProductPrice) }}</span>
</el-table-column> </div>
<el-table-column label="产品单价" fixed="right" min-width="120"> <el-form-item label="税率(%" :prop="`${$index}.taxPercent`">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.productPrice`" class="mb-0px!">
<el-input-number
v-model="row.productPrice"
controls-position="right"
:min="0.0001"
:precision="4"
class="!w-100%"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="金额" prop="totalProductPrice" fixed="right" min-width="100">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.totalProductPrice`" class="mb-0px!">
<el-input
disabled
v-model="row.totalProductPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="税率(%" fixed="right" min-width="115">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.taxPercent`" class="mb-0px!">
<el-input-number <el-input-number
v-model="row.taxPercent" v-model="row.taxPercent"
controls-position="right" controls-position="right"
:min="0" :min="0"
:precision="4" :precision="4"
class="!w-100%" style="width: 100%"
/> />
</el-form-item> </el-form-item>
</template> <div class="mobile-item-card__info-row">
</el-table-column> <span class="mobile-item-card__info-label">税额</span>
<el-table-column label="税额" prop="taxPrice" fixed="right" min-width="120"> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.taxPrice) }}</span>
<template #default="{ row, $index }"> </div>
<el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> <el-form-item label="税额合计" :prop="`${$index}.totalPrice`">
<el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!">
<el-input disabled v-model="row.taxPrice" :formatter="erpPriceInputFormatter" />
</el-form-item>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="税额合计" prop="totalPrice" fixed="right" min-width="120">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!">
<el-input-number <el-input-number
v-model="row.totalPrice" v-model="row.totalPrice"
controls-position="right" controls-position="right"
:min="0" :min="0"
:precision="4" :precision="4"
class="!w-100%" style="width: 100%"
@change="onChangeTotalPrice(row)" @change="onChangeTotalPrice(row)"
/> />
<!-- <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" />-->
</el-form-item> </el-form-item>
</template> <el-form-item label="备注" :prop="`${$index}.remark`">
</el-table-column>
<el-table-column label="备注" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.remark`" class="mb-0px!">
<el-input v-model="row.remark" placeholder="请输入备注" /> <el-input v-model="row.remark" placeholder="请输入备注" />
</el-form-item> </el-form-item>
</template> </div>
</el-table-column> </div>
<el-table-column align="center" fixed="right" label="操作" width="60">
<template #default="{ $index }"> <!-- 合计 -->
<el-button @click="handleDelete($index)" link></el-button> <div class="mobile-item-summary" v-if="formData.length > 0">
</template> <div class="mobile-item-summary__row">
</el-table-column> <span>合计数量</span>
</el-table> <span>{{ erpCountInputFormatter(summaryData.count) }}</span>
</div>
<div class="mobile-item-summary__row">
<span>合计金额</span>
<span>{{ erpPriceInputFormatter(summaryData.totalProductPrice) }}</span>
</div>
<div class="mobile-item-summary__row">
<span>合计税额</span>
<span>{{ erpPriceInputFormatter(summaryData.taxPrice) }}</span>
</div>
<div class="mobile-item-summary__row mobile-item-summary__row--total">
<span>税额合计</span>
<span>{{ erpPriceInputFormatter(summaryData.totalPrice) }}</span>
</div>
</div>
<!-- 添加按钮 -->
<div class="mobile-item-add" v-if="!disabled">
<el-button @click="handleAdd" round>+ 添加销售产品</el-button>
</div>
</div>
</el-form> </el-form>
<el-row justify="center" class="mt-3" v-if="!disabled">
<el-button @click="handleAdd" round>+ 添加销售产品</el-button>
</el-row>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ProductApi, ProductVO } from '@/api/erp/product/product' import { ProductApi, ProductVO } from '@/api/erp/product/product'
@@ -197,25 +195,14 @@ watch(
) )
/** 合计 */ /** 合计 */
const getSummaries = (param: SummaryMethodProps) => { const summaryData = computed(() => {
const { columns, data } = param return {
const sums: string[] = [] count: getSumValue(formData.value.map((item) => Number(item.count))),
columns.forEach((column, index: number) => { totalProductPrice: getSumValue(formData.value.map((item) => Number(item.totalProductPrice))),
if (index === 0) { taxPrice: getSumValue(formData.value.map((item) => Number(item.taxPrice))),
sums[index] = '合计' totalPrice: getSumValue(formData.value.map((item) => Number(item.totalPrice)))
return }
} })
if (['count', 'totalProductPrice', 'taxPrice', 'totalPrice'].includes(column.property)) {
const sum = getSumValue(data.map((item) => Number(item[column.property])))
sums[index] =
column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum)
} else {
sums[index] = ''
}
})
return sums
}
/** 新增按钮操作 */ /** 新增按钮操作 */
const handleAdd = () => { const handleAdd = () => {
@@ -245,6 +232,7 @@ const handleDelete = (index: number) => {
const onChangeProduct = (productId, row) => { const onChangeProduct = (productId, row) => {
const product = productList.value.find((item) => item.id === productId) const product = productList.value.find((item) => item.id === productId)
if (product) { if (product) {
row.productName = product.name
row.productUnitName = product.unitName row.productUnitName = product.unitName
row.productBarCode = product.barCode row.productBarCode = product.barCode
row.productPrice = product.salePrice row.productPrice = product.salePrice
@@ -294,3 +282,86 @@ onMounted(async () => {
} }
}) })
</script> </script>
<style lang="scss" scoped>
.mobile-item-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-item-card {
background: #f9fafb;
border-radius: 8px;
border: 1px solid #ebeef5;
overflow: hidden;
&__header {
display: flex;
align-items: center;
padding: 10px 12px;
background: #f0f2f5;
gap: 8px;
}
&__index {
font-size: 13px;
font-weight: 600;
color: #409eff;
flex-shrink: 0;
}
&__name {
flex: 1;
font-size: 14px;
font-weight: 500;
color: #303133;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__body {
padding: 10px 12px;
}
&__info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 4px 0;
font-size: 13px;
}
&__info-label {
color: #909399;
flex-shrink: 0;
}
&__info-value {
color: #606266;
text-align: right;
}
&__input-group {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
}
.mobile-item-summary {
background: #fff;
border-radius: 8px;
border: 1px solid #ebeef5;
padding: 10px 12px;
&__row {
display: flex;
justify-content: space-between;
padding: 4px 0;
font-size: 13px;
color: #606266;
&--total {
font-weight: 600;
color: #303133;
border-top: 1px solid #ebeef5;
padding-top: 8px;
margin-top: 4px;
}
}
}
.mobile-item-add {
text-align: center;
padding: 8px 0;
}
</style>

View File

@@ -1,44 +1,93 @@
<!-- 可出库的订单列表 --> <!-- 可出库的订单列表 -->
<template> <template>
<Dialog <el-drawer
title="选择销售订单(仅展示可出库)"
v-model="dialogVisible" v-model="dialogVisible"
:appendToBody="true" title="选择销售订单(仅展示可出库)"
:scroll="true" direction="rtl"
width="1080" size="100%"
:close-on-press-escape="true"
:destroy-on-close="true"
> >
<ContentWrap> <div class="mobile-enable-list">
<!-- 搜索工作 --> <!-- 搜索栏 -->
<el-form <div class="mobile-enable-list__search">
class="-mb-15px" <el-input
:model="queryParams" v-model="queryParams.no"
ref="queryFormRef" placeholder="搜索订单单号"
:inline="true" clearable
label-width="68px" @keyup.enter="handleQuery"
> :prefix-icon="Search"
<el-form-item label="订单单号" prop="no"> />
<el-input <el-button :icon="Filter" circle @click="filterVisible = true" />
v-model="queryParams.no" </div>
placeholder="请输入订单单号"
clearable <!-- 卡片列表 -->
@keyup.enter="handleQuery" <div class="mobile-enable-list__body" v-loading="loading">
class="!w-160px" <el-empty v-if="list.length === 0 && !loading" description="暂无可出库订单" />
/> <div
</el-form-item> v-for="item in list"
:key="item.id"
class="mobile-enable-list__card"
:class="{ 'mobile-enable-list__card--selected': currentRowValue === item.id }"
@click="handleCurrentChange(item)"
>
<div class="mobile-enable-list__card-check">
<el-radio :value="item.id" v-model="currentRowValue">&nbsp;</el-radio>
</div>
<div class="mobile-enable-list__card-content">
<div class="mobile-enable-list__card-no">{{ item.no }}</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">客户</span>
<span>{{ item.customerName || '-' }}</span>
</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">产品</span>
<span class="mobile-enable-list__card-ellipsis">{{ item.productNames || '-' }}</span>
</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">订单时间</span>
<span>{{ formatDate2(item.orderTime) }}</span>
</div>
<div class="mobile-enable-list__card-nums">
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val">{{ erpCountInputFormatter(item.totalCount) }}</div>
<div class="mobile-enable-list__card-num-label">总数量</div>
</div>
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val">{{ erpCountInputFormatter(item.outCount) }}</div>
<div class="mobile-enable-list__card-num-label">已出库</div>
</div>
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val mobile-enable-list__card-num-val--price">
¥{{ erpPriceInputFormatter(item.totalPrice) }}
</div>
<div class="mobile-enable-list__card-num-label">含税金额</div>
</div>
</div>
</div>
</div>
</div>
<!-- 分页 -->
<div class="mobile-enable-list__pagination" v-if="total > 0">
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
:page-sizes="[10, 20]"
layout="total, prev, pager, next"
:pager-count="5"
@pagination="getList"
/>
</div>
</div>
<!-- 筛选抽屉 -->
<el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="60%" :append-to-body="true">
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
<el-form-item label="产品" prop="productId"> <el-form-item label="产品" prop="productId">
<el-select <el-select v-model="queryParams.productId" clearable filterable placeholder="请选择产品" style="width:100%">
v-model="queryParams.productId" <el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择产品"
class="!w-160px"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="订单时间" prop="orderTime"> <el-form-item label="订单时间" prop="orderTime">
@@ -48,94 +97,38 @@
type="daterange" type="daterange"
start-placeholder="开始日期" start-placeholder="开始日期"
end-placeholder="结束日期" end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" :default-time="['00:00:00', '23:59:59']"
class="!w-160px" style="width:100%"
/> />
</el-form-item> </el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
</el-form> </el-form>
</ContentWrap> <template #footer>
<el-button @click="resetQuery">重置</el-button>
<el-button type="primary" @click="filterVisible = false; handleQuery()">确认筛选</el-button>
</template>
</el-drawer>
<ContentWrap>
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
<el-table-column align="center" width="65">
<template #default="scope">
<el-radio
:value="scope.row.id"
v-model="currentRowValue"
@change="handleCurrentChange(scope.row)"
>
&nbsp;
</el-radio>
</template>
</el-table-column>
<el-table-column min-width="180" label="订单单号" align="center" prop="no" />
<el-table-column label="客户" align="center" prop="customerName" />
<el-table-column label="产品信息" align="center" prop="productNames" min-width="200" />
<el-table-column
label="订单时间"
align="center"
prop="orderTime"
:formatter="dateFormatter2"
width="120px"
/>
<el-table-column label="创建人" align="center" prop="creatorName" />
<el-table-column
label="总数量"
align="center"
prop="totalCount"
:formatter="erpCountTableColumnFormatter"
/>
<el-table-column
label="出库数量"
align="center"
prop="outCount"
:formatter="erpCountTableColumnFormatter"
/>
<el-table-column
label="金额合计"
align="center"
prop="totalProductPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column
label="含税金额"
align="center"
prop="totalPrice"
:formatter="erpPriceTableColumnFormatter"
/>
</el-table>
<!-- 分页 -->
<Pagination
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNo"
:total="total"
@pagination="getList"
/>
</ContentWrap>
<template #footer> <template #footer>
<el-button :disabled="!currentRow" type="primary" @click="submitForm"> </el-button> <el-button :disabled="!currentRow" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button> <el-button @click="dialogVisible = false"> </el-button>
</template> </template>
</Dialog> </el-drawer>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ElTable } from 'element-plus' import { Search, Filter } from '@element-plus/icons-vue'
import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order' import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order'
import { dateFormatter2 } from '@/utils/formatTime'
import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils'
import { ProductApi, ProductVO } from '@/api/erp/product/product' import { ProductApi, ProductVO } from '@/api/erp/product/product'
import { formatDate } from '@/utils/formatTime'
import { erpCountInputFormatter, erpPriceInputFormatter } from '@/utils'
defineOptions({ name: 'ErpSaleOrderOutEnableList' }) defineOptions({ name: 'ErpSaleOrderOutEnableList' })
const list = ref<SaleOrderVO[]>([]) // 列表的数据 const list = ref<SaleOrderVO[]>([])
const total = ref(0) // 列表的总页数 const total = ref(0)
const loading = ref(false) // 列表的加载中 const loading = ref(false)
const dialogVisible = ref(false) // 弹窗的是否展示 const dialogVisible = ref(false)
const filterVisible = ref(false)
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@@ -144,26 +137,30 @@ const queryParams = reactive({
orderTime: [], orderTime: [],
outEnable: true outEnable: true
}) })
const queryFormRef = ref() // 搜索的表单 const queryFormRef = ref()
const productList = ref<ProductVO[]>([]) // 产品列表 const productList = ref<ProductVO[]>([])
const formatDate2 = (date: any) => {
if (!date) return '-'
return formatDate(new Date(date), 'YYYY-MM-DD')
}
/** 选中行 */ /** 选中行 */
const currentRowValue = ref(undefined) // 选中行的 value const currentRowValue = ref(undefined)
const currentRow = ref(undefined) // 选中行 const currentRow = ref(undefined)
const handleCurrentChange = (row) => { const handleCurrentChange = (row) => {
currentRow.value = row currentRow.value = row
currentRowValue.value = row.id
} }
/** 打开弹窗 */ /** 打开弹窗 */
const open = async () => { const open = async () => {
dialogVisible.value = true dialogVisible.value = true
await nextTick() // 等待,避免 queryFormRef 为空 await nextTick()
// 加载可出库的订单列表
await resetQuery() await resetQuery()
// 加载产品列表
productList.value = await ProductApi.getProductSimpleList() productList.value = await ProductApi.getProductSimpleList()
} }
defineExpose({ open }) // 提供 open 方法,用于打开弹窗 defineExpose({ open })
/** 提交选择 */ /** 提交选择 */
const emits = defineEmits<{ const emits = defineEmits<{
@@ -173,12 +170,11 @@ const submitForm = () => {
try { try {
emits('success', currentRow.value) emits('success', currentRow.value)
} finally { } finally {
// 关闭弹窗
dialogVisible.value = false dialogVisible.value = false
} }
} }
/** 加载列表 */ /** 加载列表 */
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
@@ -192,7 +188,7 @@ const getList = async () => {
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value?.resetFields()
handleQuery() handleQuery()
} }
@@ -204,3 +200,100 @@ const handleQuery = () => {
getList() getList()
} }
</script> </script>
<style lang="scss" scoped>
.mobile-enable-list {
padding: 12px;
&__search {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
}
&__body {
display: flex;
flex-direction: column;
gap: 10px;
}
&__card {
display: flex;
background: #fff;
border-radius: 10px;
padding: 12px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
border: 2px solid transparent;
transition: border-color 0.2s;
&--selected {
border-color: var(--el-color-primary);
}
}
&__card-check {
flex-shrink: 0;
padding-right: 8px;
display: flex;
align-items: flex-start;
padding-top: 2px;
}
&__card-content {
flex: 1;
min-width: 0;
}
&__card-no {
font-weight: 600;
font-size: 14px;
color: #303133;
margin-bottom: 6px;
}
&__card-row {
display: flex;
justify-content: space-between;
font-size: 13px;
color: #606266;
padding: 2px 0;
}
&__card-label {
color: #909399;
flex-shrink: 0;
margin-right: 10px;
}
&__card-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 180px;
text-align: right;
}
&__card-nums {
display: flex;
justify-content: space-around;
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid #f0f0f0;
}
&__card-num {
text-align: center;
}
&__card-num-val {
font-size: 14px;
font-weight: 600;
color: #303133;
&--price {
color: #e6a23c;
}
}
&__card-num-label {
font-size: 11px;
color: #909399;
margin-top: 2px;
}
&__pagination {
margin-top: 12px;
display: flex;
justify-content: center;
:deep(.el-pagination) {
flex-wrap: wrap;
justify-content: center;
}
}
}
</style>

View File

@@ -1,44 +1,97 @@
<!-- 可退货的订单列表 --> <!-- 可退货的订单列表 -->
<template> <template>
<Dialog <el-drawer
title="选择销售订单(仅展示可退货)"
v-model="dialogVisible" v-model="dialogVisible"
:appendToBody="true" title="选择销售订单(仅展示可退货)"
:scroll="true" direction="rtl"
width="1080" size="100%"
:close-on-press-escape="true"
:destroy-on-close="true"
> >
<ContentWrap> <div class="mobile-enable-list">
<!-- 搜索工作 --> <!-- 搜索栏 -->
<el-form <div class="mobile-enable-list__search">
class="-mb-15px" <el-input
:model="queryParams" v-model="queryParams.no"
ref="queryFormRef" placeholder="搜索订单单号"
:inline="true" clearable
label-width="68px" @keyup.enter="handleQuery"
> :prefix-icon="Search"
<el-form-item label="订单单号" prop="no"> />
<el-input <el-button :icon="Filter" circle @click="filterVisible = true" />
v-model="queryParams.no" </div>
placeholder="请输入订单单号"
clearable <!-- 卡片列表 -->
@keyup.enter="handleQuery" <div class="mobile-enable-list__body" v-loading="loading">
class="!w-160px" <el-empty v-if="list.length === 0 && !loading" description="暂无可退货订单" />
/> <div
</el-form-item> v-for="item in list"
:key="item.id"
class="mobile-enable-list__card"
:class="{ 'mobile-enable-list__card--selected': currentRowValue === item.id }"
@click="handleCurrentChange(item)"
>
<div class="mobile-enable-list__card-check">
<el-radio :value="item.id" v-model="currentRowValue">&nbsp;</el-radio>
</div>
<div class="mobile-enable-list__card-content">
<div class="mobile-enable-list__card-no">{{ item.no }}</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">客户</span>
<span>{{ item.customerName || '-' }}</span>
</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">产品</span>
<span class="mobile-enable-list__card-ellipsis">{{ item.productNames || '-' }}</span>
</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">订单时间</span>
<span>{{ formatDate2(item.orderTime) }}</span>
</div>
<div class="mobile-enable-list__card-nums">
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val">{{ erpCountInputFormatter(item.totalCount) }}</div>
<div class="mobile-enable-list__card-num-label">总数量</div>
</div>
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val">{{ erpCountInputFormatter(item.outCount) }}</div>
<div class="mobile-enable-list__card-num-label">出库数量</div>
</div>
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val">{{ erpCountInputFormatter(item.returnCount) }}</div>
<div class="mobile-enable-list__card-num-label">退货数量</div>
</div>
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val mobile-enable-list__card-num-val--price">
¥{{ erpPriceInputFormatter(item.totalPrice) }}
</div>
<div class="mobile-enable-list__card-num-label">含税金额</div>
</div>
</div>
</div>
</div>
</div>
<!-- 分页 -->
<div class="mobile-enable-list__pagination" v-if="total > 0">
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
:page-sizes="[10, 20]"
layout="total, prev, pager, next"
:pager-count="5"
@pagination="getList"
/>
</div>
</div>
<!-- 筛选抽屉 -->
<el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="60%" :append-to-body="true">
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
<el-form-item label="产品" prop="productId"> <el-form-item label="产品" prop="productId">
<el-select <el-select v-model="queryParams.productId" clearable filterable placeholder="请选择产品" style="width:100%">
v-model="queryParams.productId" <el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择产品"
class="!w-160px"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="订单时间" prop="orderTime"> <el-form-item label="订单时间" prop="orderTime">
@@ -48,100 +101,38 @@
type="daterange" type="daterange"
start-placeholder="开始日期" start-placeholder="开始日期"
end-placeholder="结束日期" end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" :default-time="['00:00:00', '23:59:59']"
class="!w-160px" style="width:100%"
/> />
</el-form-item> </el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
</el-form> </el-form>
</ContentWrap> <template #footer>
<el-button @click="resetQuery">重置</el-button>
<el-button type="primary" @click="filterVisible = false; handleQuery()">确认筛选</el-button>
</template>
</el-drawer>
<ContentWrap>
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
<el-table-column align="center" width="65">
<template #default="scope">
<el-radio
:value="scope.row.id"
v-model="currentRowValue"
@change="handleCurrentChange(scope.row)"
>
&nbsp;
</el-radio>
</template>
</el-table-column>
<el-table-column min-width="180" label="订单单号" align="center" prop="no" />
<el-table-column label="客户" align="center" prop="customerName" />
<el-table-column label="产品信息" align="center" prop="productNames" min-width="200" />
<el-table-column
label="订单时间"
align="center"
prop="orderTime"
:formatter="dateFormatter2"
width="120px"
/>
<el-table-column label="创建人" align="center" prop="creatorName" />
<el-table-column
label="总数量"
align="center"
prop="totalCount"
:formatter="erpCountTableColumnFormatter"
/>
<el-table-column
label="出库数量"
align="center"
prop="outCount"
:formatter="erpCountTableColumnFormatter"
/>
<el-table-column
label="退货数量"
align="center"
prop="returnCount"
:formatter="erpCountTableColumnFormatter"
/>
<el-table-column
label="金额合计"
align="center"
prop="totalProductPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column
label="含税金额"
align="center"
prop="totalPrice"
:formatter="erpPriceTableColumnFormatter"
/>
</el-table>
<!-- 分页 -->
<Pagination
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNo"
:total="total"
@pagination="getList"
/>
</ContentWrap>
<template #footer> <template #footer>
<el-button :disabled="!currentRow" type="primary" @click="submitForm"> </el-button> <el-button :disabled="!currentRow" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button> <el-button @click="dialogVisible = false"> </el-button>
</template> </template>
</Dialog> </el-drawer>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ElTable } from 'element-plus' import { Search, Filter } from '@element-plus/icons-vue'
import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order' import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order'
import { dateFormatter2 } from '@/utils/formatTime'
import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils'
import { ProductApi, ProductVO } from '@/api/erp/product/product' import { ProductApi, ProductVO } from '@/api/erp/product/product'
import { formatDate } from '@/utils/formatTime'
import { erpCountInputFormatter, erpPriceInputFormatter } from '@/utils'
defineOptions({ name: 'SaleOrderReturnEnableList' }) defineOptions({ name: 'SaleOrderReturnEnableList' })
const list = ref<SaleOrderVO[]>([]) // 列表的数据 const list = ref<SaleOrderVO[]>([])
const total = ref(0) // 列表的总页数 const total = ref(0)
const loading = ref(false) // 列表的加载中 const loading = ref(false)
const dialogVisible = ref(false) // 弹窗的是否展示 const dialogVisible = ref(false)
const filterVisible = ref(false)
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@@ -150,26 +141,30 @@ const queryParams = reactive({
orderTime: [], orderTime: [],
returnEnable: true returnEnable: true
}) })
const queryFormRef = ref() // 搜索的表单 const queryFormRef = ref()
const productList = ref<ProductVO[]>([]) // 产品列表 const productList = ref<ProductVO[]>([])
const formatDate2 = (date: any) => {
if (!date) return '-'
return formatDate(new Date(date), 'YYYY-MM-DD')
}
/** 选中行 */ /** 选中行 */
const currentRowValue = ref(undefined) // 选中行的 value const currentRowValue = ref(undefined)
const currentRow = ref(undefined) // 选中行 const currentRow = ref(undefined)
const handleCurrentChange = (row) => { const handleCurrentChange = (row) => {
currentRow.value = row currentRow.value = row
currentRowValue.value = row.id
} }
/** 打开弹窗 */ /** 打开弹窗 */
const open = async () => { const open = async () => {
dialogVisible.value = true dialogVisible.value = true
await nextTick() // 等待,避免 queryFormRef 为空 await nextTick()
// 加载可退货的订单列表
await resetQuery() await resetQuery()
// 加载产品列表
productList.value = await ProductApi.getProductSimpleList() productList.value = await ProductApi.getProductSimpleList()
} }
defineExpose({ open }) // 提供 open 方法,用于打开弹窗 defineExpose({ open })
/** 提交选择 */ /** 提交选择 */
const emits = defineEmits<{ const emits = defineEmits<{
@@ -179,12 +174,11 @@ const submitForm = () => {
try { try {
emits('success', currentRow.value) emits('success', currentRow.value)
} finally { } finally {
// 关闭弹窗
dialogVisible.value = false dialogVisible.value = false
} }
} }
/** 加载列表 */ /** 加载列表 */
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
@@ -198,7 +192,7 @@ const getList = async () => {
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value?.resetFields()
handleQuery() handleQuery()
} }
@@ -210,3 +204,101 @@ const handleQuery = () => {
getList() getList()
} }
</script> </script>
<style lang="scss" scoped>
/* 同可入库/可出库列表样式 */
.mobile-enable-list {
padding: 12px;
&__search {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
}
&__body {
display: flex;
flex-direction: column;
gap: 10px;
}
&__card {
display: flex;
background: #fff;
border-radius: 10px;
padding: 12px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
border: 2px solid transparent;
transition: border-color 0.2s;
&--selected {
border-color: var(--el-color-primary);
}
}
&__card-check {
flex-shrink: 0;
padding-right: 8px;
display: flex;
align-items: flex-start;
padding-top: 2px;
}
&__card-content {
flex: 1;
min-width: 0;
}
&__card-no {
font-weight: 600;
font-size: 14px;
color: #303133;
margin-bottom: 6px;
}
&__card-row {
display: flex;
justify-content: space-between;
font-size: 13px;
color: #606266;
padding: 2px 0;
}
&__card-label {
color: #909399;
flex-shrink: 0;
margin-right: 10px;
}
&__card-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 180px;
text-align: right;
}
&__card-nums {
display: flex;
justify-content: space-around;
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid #f0f0f0;
}
&__card-num {
text-align: center;
}
&__card-num-val {
font-size: 14px;
font-weight: 600;
color: #303133;
&--price {
color: #e6a23c;
}
}
&__card-num-label {
font-size: 11px;
color: #909399;
margin-top: 2px;
}
&__pagination {
margin-top: 12px;
display: flex;
justify-content: center;
:deep(.el-pagination) {
flex-wrap: wrap;
justify-content: center;
}
}
}
</style>

View File

@@ -1,333 +1,186 @@
<template> <template>
<doc-alert title="【销售】销售订单、出库、退货" url="https://doc.iocoder.cn/erp/sale/" /> <div class="mobile-sale-order">
<!-- 顶部操作栏 -->
<ContentWrap> <div class="mobile-header">
<!-- 搜索工作栏 --> <div class="mobile-header__search">
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="订单单号" prop="no">
<el-input <el-input
v-model="queryParams.no" v-model="queryParams.no"
placeholder="请输入订单单号" placeholder="搜索订单单号"
clearable clearable
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
class="!w-240px" :prefix-icon="Search"
/> />
</el-form-item> </div>
<el-form-item label="产品" prop="productId"> <div class="mobile-header__actions">
<el-select <el-button :icon="Filter" circle @click="filterVisible = true" />
v-model="queryParams.productId"
clearable
filterable
placeholder="请选择产品"
class="!w-240px"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="订单时间" prop="orderTime">
<el-date-picker
v-model="queryParams.orderTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-select
v-model="queryParams.customerId"
clearable
filterable
placeholder="请选择供客户"
class="!w-240px"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="创建人" prop="creator">
<el-select
v-model="queryParams.creator"
clearable
filterable
placeholder="请选择创建人"
class="!w-240px"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable class="!w-240px">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="queryParams.remark"
placeholder="请输入备注"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="出库数量" prop="outStatus">
<el-select
v-model="queryParams.outStatus"
placeholder="请选择出库数量"
clearable
class="!w-240px"
>
<el-option label="未出库" value="0" />
<el-option label="部分出库" value="1" />
<el-option label="全部出库" value="2" />
</el-select>
</el-form-item>
<el-form-item label="退货数量" prop="returnStatus">
<el-select
v-model="queryParams.returnStatus"
placeholder="请选择退货数量"
clearable
class="!w-240px"
>
<el-option label="未退货" value="0" />
<el-option label="部分退货" value="1" />
<el-option label="全部退货" value="2" />
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button <el-button
type="primary" type="primary"
plain :icon="Plus"
circle
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['erp:sale-order:create']" v-hasPermi="['erp:sale-order:create']"
> />
<Icon icon="ep:plus" class="mr-5px" /> 新增 </div>
</el-button> </div>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['erp:sale-order:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
<el-button
type="danger"
plain
@click="handleDelete(selectionList.map((item) => item.id))"
v-hasPermi="['erp:sale-order:delete']"
:disabled="selectionList.length === 0"
>
<Icon icon="ep:delete" class="mr-5px" /> 删除
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 --> <!-- 卡片列表 -->
<ContentWrap> <div class="mobile-list" v-loading="loading">
<el-table <div v-if="list.length === 0 && !loading" class="mobile-empty">
v-loading="loading" <el-empty description="暂无销售订单" />
:data="list" </div>
:stripe="true" <div
:show-overflow-tooltip="true" v-for="item in list"
@selection-change="handleSelectionChange" :key="item.id"
@row-click="handleRowClick" class="mobile-card"
> @click="handleCardClick(item)"
<el-table-column width="30" label="选择" type="selection" /> >
<el-table-column min-width="180" label="订单单号" align="center" prop="no" /> <div class="mobile-card__header">
<el-table-column label="产品信息" align="center" prop="productNames" min-width="200" /> <span class="mobile-card__no">{{ item.no }}</span>
<el-table-column label="客户" align="center" prop="customerName" /> <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="item.status" />
<el-table-column </div>
label="订单时间" <div class="mobile-card__body">
align="center" <div class="mobile-card__row">
prop="orderTime" <span class="mobile-card__label">客户</span>
:formatter="dateFormatter2" <span class="mobile-card__value">{{ item.customerName || '-' }}</span>
width="120px" </div>
sortable <div class="mobile-card__row">
/> <span class="mobile-card__label">产品</span>
<el-table-column label="创建人" align="center" prop="creatorName" /> <span class="mobile-card__value mobile-card__value--ellipsis">{{ item.productNames || '-' }}</span>
<el-table-column </div>
label="总数量" <div class="mobile-card__row">
align="center" <span class="mobile-card__label">订单时间</span>
prop="totalCount" <span class="mobile-card__value">{{ formatDate2(item.orderTime) }}</span>
:formatter="erpCountTableColumnFormatter" </div>
/> <div class="mobile-card__row">
<el-table-column <span class="mobile-card__label">创建人</span>
label="出库数量" <span class="mobile-card__value">{{ item.creatorName || '-' }}</span>
align="center" </div>
prop="outCount" <div class="mobile-card__nums">
:formatter="erpCountTableColumnFormatter" <div class="mobile-card__num-item">
/> <div class="mobile-card__num-val">{{ erpCountInputFormatter(item.totalCount) }}</div>
<el-table-column <div class="mobile-card__num-label">总数量</div>
label="退货数量" </div>
align="center" <div class="mobile-card__num-item">
prop="returnCount" <div class="mobile-card__num-val">{{ erpCountInputFormatter(item.outCount) }}</div>
:formatter="erpCountTableColumnFormatter" <div class="mobile-card__num-label">出库</div>
/> </div>
<el-table-column <div class="mobile-card__num-item">
label="金额合计" <div class="mobile-card__num-val">{{ erpCountInputFormatter(item.returnCount) }}</div>
align="center" <div class="mobile-card__num-label">退货</div>
prop="totalProductPrice" </div>
:formatter="erpPriceTableColumnFormatter" <div class="mobile-card__num-item">
/> <div class="mobile-card__num-val mobile-card__num-val--price">¥{{ erpPriceInputFormatter(item.totalPrice) }}</div>
<el-table-column <div class="mobile-card__num-label">含税金额</div>
label="含税金额" </div>
align="center" </div>
prop="totalPrice" </div>
:formatter="erpPriceTableColumnFormatter" <div class="mobile-card__footer">
/> <el-button size="small" @click.stop="openForm('detail', item.id)" v-hasPermi="['erp:sale-order:query']">详情</el-button>
<el-table-column <el-button size="small" type="primary" @click.stop="openForm('update', item.id)" v-hasPermi="['erp:sale-order:update']" :disabled="item.status === 20 || item.hasApprovalRecords">编辑</el-button>
label="收取订金" <el-button size="small" type="success" @click.stop="handleSubmitApproval(item.id)" v-hasPermi="['erp:sale-order:submit-approval']" v-if="item.status === 10 && !item.hasApprovalRecords">提交审批</el-button>
align="center" <el-button size="small" type="info" @click.stop="handleViewApproval(item.id)" v-hasPermi="['erp:sale-order:query-approval']" v-if="item.hasApprovalRecords">审批记录</el-button>
prop="depositPrice" <el-button size="small" type="primary" @click.stop="handleProcessApproval(item.id)" v-hasPermi="['erp:approval-record:process']" v-if="item.hasApprovalRecords && item.status !== 20">处理审批</el-button>
:formatter="erpPriceTableColumnFormatter" <el-button size="small" type="primary" @click.stop="handleUpdateStatus(item.id, 20)" v-hasPermi="['erp:sale-order:update-status']" v-if="item.status === 10">审批</el-button>
/> <el-button size="small" type="danger" @click.stop="handleUpdateStatus(item.id, 10)" v-hasPermi="['erp:sale-order:update-status']" v-if="item.status === 20">反审批</el-button>
<el-table-column label="状态" align="center" fixed="right" width="90" prop="status"> <el-button size="small" type="danger" @click.stop="handleDelete([item.id])" v-hasPermi="['erp:sale-order:delete']" :disabled="item.hasApprovalRecords">删除</el-button>
<template #default="scope"> </div>
<dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> </div>
</template> </div>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" width="380">
<template #default="scope">
<el-button
link
@click="openForm('detail', scope.row.id)"
v-hasPermi="['erp:sale-order:query']"
>
详情
</el-button>
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['erp:sale-order:update']"
:disabled="scope.row.status === 20 || scope.row.hasApprovalRecords"
>
编辑
</el-button>
<el-button
link
type="success"
@click="handleSubmitApproval(scope.row.id)"
v-hasPermi="['erp:sale-order:submit-approval']"
v-if="scope.row.status === 10 && !scope.row.hasApprovalRecords"
>
提交审批
</el-button>
<el-button
link
type="info"
@click="handleViewApproval(scope.row.id)"
v-hasPermi="['erp:sale-order:query-approval']"
v-if="scope.row.hasApprovalRecords"
>
审批记录
</el-button>
<el-button
link
type="primary"
@click="handleProcessApproval(scope.row.id)"
v-hasPermi="['erp:approval-record:process']"
v-if="scope.row.hasApprovalRecords && scope.row.status !== 20"
>
处理审批
</el-button>
<el-button
link
type="primary"
@click="handleUpdateStatus(scope.row.id, 20)"
v-hasPermi="['erp:sale-order:update-status']"
v-if="scope.row.status === 10"
>
审批
</el-button>
<el-button
link
type="danger"
@click="handleUpdateStatus(scope.row.id, 10)"
v-hasPermi="['erp:sale-order:update-status']"
v-else
>
反审批
</el-button>
<el-button
link
type="danger"
@click="handleDelete([scope.row.id])"
v-hasPermi="['erp:sale-order:delete']"
:disabled="scope.row.hasApprovalRecords"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 --> <!-- 分页 -->
<Pagination <div class="mobile-pagination" v-if="total > 0">
:total="total" <Pagination
v-model:page="queryParams.pageNo" :total="total"
v-model:limit="queryParams.pageSize" v-model:page="queryParams.pageNo"
@pagination="getList" v-model:limit="queryParams.pageSize"
/> :page-sizes="[10, 20]"
</ContentWrap> layout="total, prev, pager, next"
:pager-count="5"
@pagination="getList"
/>
</div>
<!-- 表单弹窗添加/修改 --> <!-- 筛选抽屉 -->
<SaleOrderForm ref="formRef" @success="getList" /> <el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="70%">
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
<el-form-item label="产品" prop="productId">
<el-select v-model="queryParams.productId" clearable filterable placeholder="请选择产品" style="width:100%">
<el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-select v-model="queryParams.customerId" clearable filterable placeholder="请选择客户" style="width:100%">
<el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="订单时间" prop="orderTime">
<el-date-picker
v-model="queryParams.orderTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
style="width:100%"
/>
</el-form-item>
<el-form-item label="创建人" prop="creator">
<el-select v-model="queryParams.creator" clearable filterable placeholder="请选择创建人" style="width:100%">
<el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width:100%">
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="出库状态" prop="outStatus">
<el-select v-model="queryParams.outStatus" placeholder="请选择" clearable style="width:100%">
<el-option label="未出库" value="0" />
<el-option label="部分出库" value="1" />
<el-option label="全部出库" value="2" />
</el-select>
</el-form-item>
<el-form-item label="退货状态" prop="returnStatus">
<el-select v-model="queryParams.returnStatus" placeholder="请选择" clearable style="width:100%">
<el-option label="未退货" value="0" />
<el-option label="部分退货" value="1" />
<el-option label="全部退货" value="2" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="resetQuery">重置</el-button>
<el-button type="primary" @click="handleFilterConfirm">确认筛选</el-button>
</template>
</el-drawer>
<!-- 提交审批对话框 --> <!-- 表单弹窗添加/修改 -->
<SubmitApprovalDialog ref="submitApprovalDialogRef" @success="getList" /> <SaleOrderForm ref="formRef" @success="getList" />
<!-- 审批记录对话框 --> <!-- 提交审批对话框 -->
<ApprovalRecordsDialog ref="approvalDialogRef" /> <SubmitApprovalDialog ref="submitApprovalDialogRef" @success="getList" />
<!-- 处理审批对话框 --> <!-- 审批记录对话框 -->
<ProcessApprovalDialog ref="processApprovalDialogRef" @success="getList" /> <ApprovalRecordsDialog ref="approvalDialogRef" />
<!-- 处理审批对话框 -->
<ProcessApprovalDialog ref="processApprovalDialogRef" @success="getList" />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Search, Filter, Plus } from '@element-plus/icons-vue'
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter2 } from '@/utils/formatTime' import { formatDate } from '@/utils/formatTime'
import download from '@/utils/download' import download from '@/utils/download'
import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order' import { SaleOrderApi, SaleOrderVO } from '@/api/erp/sale/order'
import SaleOrderForm from './SaleOrderForm.vue' import SaleOrderForm from './SaleOrderForm.vue'
import { ProductApi, ProductVO } from '@/api/erp/product/product' import { ProductApi, ProductVO } from '@/api/erp/product/product'
import { UserVO } from '@/api/system/user' import { UserVO } from '@/api/system/user'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
import { erpCountTableColumnFormatter, erpPriceTableColumnFormatter } from '@/utils' import { erpCountInputFormatter, erpPriceInputFormatter } from '@/utils'
import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer'
import {PurchaseOrderVO} from "@/api/erp/purchase/order";
import { SubmitApprovalDialog, ApprovalRecordsDialog, ProcessApprovalDialog } from '@/components/Approval' import { SubmitApprovalDialog, ApprovalRecordsDialog, ProcessApprovalDialog } from '@/components/Approval'
import { ApprovalRecordApi, ApprovalRecordVO } from '@/api/erp/approval/index' import { ApprovalRecordApi, ApprovalRecordVO } from '@/api/erp/approval/index'
@@ -340,6 +193,7 @@ const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中 const loading = ref(true) // 列表的加载中
const list = ref<SaleOrderVO[]>([]) // 列表的数据 const list = ref<SaleOrderVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数 const total = ref(0) // 列表的总页数
const filterVisible = ref(false) // 筛选抽屉
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@@ -359,6 +213,11 @@ const productList = ref<ProductVO[]>([]) // 产品列表
const customerList = ref<CustomerVO[]>([]) // 客户列表 const customerList = ref<CustomerVO[]>([]) // 客户列表
const userList = ref<UserVO[]>([]) // 用户列表 const userList = ref<UserVO[]>([]) // 用户列表
const formatDate2 = (date: any) => {
if (!date) return '-'
return formatDate(new Date(date), 'YYYY-MM-DD')
}
/** 查询列表 */ /** 查询列表 */
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
@@ -399,7 +258,13 @@ const handleQuery = () => {
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value?.resetFields()
handleQuery()
}
/** 筛选确认 */
const handleFilterConfirm = () => {
filterVisible.value = false
handleQuery() handleQuery()
} }
@@ -409,6 +274,15 @@ const openForm = (type: string, id?: number) => {
formRef.value.open(type, id) formRef.value.open(type, id)
} }
/** 卡片点击 */
const handleCardClick = (row: SaleOrderVO) => {
if (row.status === 20) {
openForm('detail', row.id)
} else if (row.status === 10) {
openForm('update', row.id)
}
}
/** 提交审批 */ /** 提交审批 */
const submitApprovalDialogRef = ref() const submitApprovalDialogRef = ref()
const handleSubmitApproval = (id: number) => { const handleSubmitApproval = (id: number) => {
@@ -427,32 +301,6 @@ const handleProcessApproval = (id: number) => {
processApprovalDialogRef.value.open(String(id), 'erp_sale_order') processApprovalDialogRef.value.open(String(id), 'erp_sale_order')
} }
/** 行点击操作 */
const handleRowClick = (row: SaleOrderVO, column: any, event: MouseEvent) => {
// 检查是否点击了按钮、链接或其他交互元素
const target = event.target as HTMLElement
if (
target.tagName === 'BUTTON' ||
target.tagName === 'A' ||
target.tagName === 'I' ||
target.tagName === 'svg' ||
target.closest('button') ||
target.closest('a') ||
target.closest('.el-button') ||
target.closest('.el-checkbox')
) {
return
}
// 已审核打开详情页面,未审核打开编辑页面
if (row.status === 20) {
openForm('detail', row.id)
} else if (row.status === 10) {
openForm('update', row.id)
}
}
/** 删除按钮操作 */ /** 删除按钮操作 */
const handleDelete = async (ids: number[]) => { const handleDelete = async (ids: number[]) => {
try { try {
@@ -463,7 +311,6 @@ const handleDelete = async (ids: number[]) => {
message.success(t('common.delSuccess')) message.success(t('common.delSuccess'))
// 刷新列表 // 刷新列表
await getList() await getList()
selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id))
} catch {} } catch {}
} }
@@ -495,12 +342,6 @@ const handleExport = async () => {
} }
} }
/** 选中操作 */
const selectionList = ref<SaleOrderVO[]>([])
const handleSelectionChange = (rows: SaleOrderVO[]) => {
selectionList.value = rows
}
/** 初始化 **/ /** 初始化 **/
onMounted(async () => { onMounted(async () => {
await getList() await getList()
@@ -509,6 +350,134 @@ onMounted(async () => {
customerList.value = await CustomerApi.getCustomerSimpleList() customerList.value = await CustomerApi.getCustomerSimpleList()
userList.value = await UserApi.getSimpleUserList() userList.value = await UserApi.getSimpleUserList()
}) })
// TODO 芋艿:可优化功能:列表界面,支持导入
// TODO 芋艿:可优化功能:详情界面,支持打印
</script> </script>
<style lang="scss" scoped>
.mobile-sale-order {
padding: 12px;
background: #f5f5f5;
min-height: 100vh;
}
.mobile-header {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
&__search {
flex: 1;
}
&__actions {
display: flex;
gap: 4px;
flex-shrink: 0;
}
}
.mobile-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-empty {
padding: 40px 0;
}
.mobile-card {
background: #fff;
border-radius: 10px;
padding: 14px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
&__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
&__no {
font-weight: 600;
font-size: 15px;
color: #303133;
}
&__body {
font-size: 13px;
}
&__row {
display: flex;
justify-content: space-between;
padding: 3px 0;
}
&__label {
color: #909399;
flex-shrink: 0;
margin-right: 12px;
}
&__value {
color: #606266;
text-align: right;
&--ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200px;
}
}
&__nums {
display: flex;
justify-content: space-around;
margin-top: 10px;
padding: 10px 0;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
}
&__num-item {
text-align: center;
}
&__num-val {
font-size: 15px;
font-weight: 600;
color: #303133;
&--price {
color: #e6a23c;
}
}
&__num-label {
font-size: 11px;
color: #909399;
margin-top: 2px;
}
&__footer {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 10px;
}
}
.mobile-pagination {
margin-top: 12px;
display: flex;
justify-content: center;
:deep(.el-pagination) {
flex-wrap: wrap;
justify-content: center;
}
}
</style>

View File

@@ -1,42 +1,35 @@
<template> <template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1440"> <el-drawer
<el-form v-model="dialogVisible"
ref="formRef" :title="dialogTitle"
:model="formData" direction="rtl"
:rules="formRules" size="100%"
label-width="100px" :close-on-press-escape="true"
v-loading="formLoading" :destroy-on-close="true"
:disabled="disabled" :append-to-body="true"
> class="mobile-form-drawer"
<el-row :gutter="20"> >
<el-col :span="8"> <div class="mobile-form" v-loading="formLoading">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-position="top"
:disabled="disabled"
>
<!-- 基本信息 -->
<div class="mobile-form__section">
<div class="mobile-form__section-title">基本信息</div>
<el-form-item label="出库单号" prop="no"> <el-form-item label="出库单号" prop="no">
<el-input disabled v-model="formData.no" placeholder="保存时自动生成" /> <el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出库时间" prop="outTime"> <el-form-item label="出库时间" prop="outTime">
<el-date-picker <el-date-picker v-model="formData.outTime" type="date" value-format="x" placeholder="选择出库时间" style="width: 100%" />
v-model="formData.outTime"
type="date"
value-format="x"
placeholder="选择出库时间"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="关联订单" prop="orderNo"> <el-form-item label="关联订单" prop="orderNo">
<!-- <el-input v-model="formData.orderNo" readonly>--> <el-input readonly>
<el-input readonly>
<template #prefix> <template #prefix>
<el-link <el-link v-if="formData.orderNo && formData.orderId" type="primary" :underline="false" @click.stop="openSaleOrderDetail">
v-if="formData.orderNo && formData.orderId"
type="primary"
:underline="false"
@click.stop="openSaleOrderDetail"
class="order-link"
>
{{ formData.orderNo }} {{ formData.orderNo }}
</el-link> </el-link>
</template> </template>
@@ -47,143 +40,67 @@
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="客户" prop="customerId"> <el-form-item label="客户" prop="customerId">
<el-select <el-select v-model="formData.customerId" clearable filterable disabled placeholder="请选择客户" style="width: 100%">
v-model="formData.customerId" <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
disabled
placeholder="请选择客户"
class="!w-1/1"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="销售人员" prop="saleUserId"> <el-form-item label="销售人员" prop="saleUserId">
<el-select <el-select v-model="formData.saleUserId" clearable filterable placeholder="请选择销售人员" style="width: 100%">
v-model="formData.saleUserId" <el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
clearable
filterable
placeholder="请选择销售人员"
class="!w-1/1"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input <el-input type="textarea" v-model="formData.remark" :rows="2" placeholder="请输入备注" />
type="textarea"
v-model="formData.remark"
:rows="1"
placeholder="请输入备注"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="附件" prop="fileUrl"> <el-form-item label="附件" prop="fileUrl">
<UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" />
</el-form-item> </el-form-item>
</el-col> </div>
</el-row>
<!-- 子表的表 --> <!-- 出库产品清 -->
<ContentWrap> <div class="mobile-form__section">
<el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> <div class="mobile-form__section-title">出库产品清单</div>
<el-tab-pane label="出库产品清单" name="item"> <SaleOutItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" />
<SaleOutItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> </div>
</el-tab-pane>
</el-tabs> <!-- 价格信息 -->
</ContentWrap> <div class="mobile-form__section">
<el-row :gutter="20"> <div class="mobile-form__section-title">价格信息</div>
<el-col :span="8">
<el-form-item label="优惠率(%" prop="discountPercent"> <el-form-item label="优惠率(%" prop="discountPercent">
<el-input-number <el-input-number v-model="formData.discountPercent" controls-position="right" :min="0" :precision="4" placeholder="请输入优惠率" style="width: 100%" />
v-model="formData.discountPercent"
controls-position="right"
:min="0"
:precision="4"
placeholder="请输入优惠率"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="收款优惠" prop="discountPrice"> <el-form-item label="收款优惠" prop="discountPrice">
<el-input <el-input disabled v-model="formData.discountPrice" :formatter="erpPriceInputFormatter" />
disabled
v-model="formData.discountPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="优惠后金额"> <el-form-item label="优惠后金额">
<el-input <el-input disabled :model-value="formData.totalPrice - formData.otherPrice" :formatter="erpPriceInputFormatter" />
disabled
:model-value="formData.totalPrice - formData.otherPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="其它费用" prop="otherPrice"> <el-form-item label="其它费用" prop="otherPrice">
<el-input-number <el-input-number v-model="formData.otherPrice" controls-position="right" :min="0" :precision="4" placeholder="请输入其它费用" style="width: 100%" />
v-model="formData.otherPrice"
controls-position="right"
:min="0"
:precision="4"
placeholder="请输入其它费用"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结算账户" prop="accountId"> <el-form-item label="结算账户" prop="accountId">
<el-select <el-select v-model="formData.accountId" clearable filterable placeholder="请选择结算账户" style="width: 100%">
v-model="formData.accountId" <el-option v-for="item in accountList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择结算账户"
class="!w-1/1"
>
<el-option
v-for="item in accountList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="应收金额"> <el-form-item label="应收金额">
<el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" />
</el-form-item> </el-form-item>
</el-col> </div>
</el-row> </el-form>
</el-form> </div>
<!-- 底部按钮 -->
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> <div class="mobile-form__footer">
<el-button @click="dialogVisible = false" style="flex:1"> </el-button>
</el-button> <el-button type="primary" @click="submitForm" :disabled="formLoading" v-if="!disabled" style="flex:2">
<el-button @click="dialogVisible = false"> </el-button>
</el-button>
</div>
</template> </template>
</Dialog> </el-drawer>
<!-- 可出库的订单列表 --> <!-- 可出库的订单列表 -->
<SaleOrderOutEnableList ref="saleOrderOutEnableListRef" @success="handleSaleOrderChange" /> <SaleOrderOutEnableList ref="saleOrderOutEnableListRef" @success="handleSaleOrderChange" />
@@ -365,3 +282,31 @@ const resetForm = () => {
formRef.value?.resetFields() formRef.value?.resetFields()
} }
</script> </script>
<style lang="scss" scoped>
.mobile-form {
padding: 12px;
}
.mobile-form__section {
background: #fff;
border-radius: 8px;
padding: 14px;
margin-bottom: 12px;
}
.mobile-form__section-title {
font-size: 15px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
}
.mobile-form__footer {
display: flex;
gap: 12px;
padding: 0 12px;
}
</style>

View File

@@ -4,18 +4,34 @@
:model="formData" :model="formData"
:rules="formRules" :rules="formRules"
v-loading="formLoading" v-loading="formLoading"
label-width="0px" label-position="top"
:inline-message="true" :inline-message="true"
:disabled="disabled" :disabled="disabled"
> >
<el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> <div class="mobile-item-list">
<el-table-column label="序号" type="index" align="center" width="60" /> <div
<el-table-column label="仓库名称" min-width="125"> v-for="(row, $index) in formData"
<template #default="{ row, $index }"> :key="$index"
class="mobile-item-card"
>
<div class="mobile-item-card__header">
<span class="mobile-item-card__index">#{{ $index + 1 }}</span>
<span class="mobile-item-card__name">{{ row.productName || '未选择产品' }}</span>
<el-button
:disabled="disabled || formData.length === 1"
@click="handleDelete($index)"
link
type="danger"
size="small"
>
删除
</el-button>
</div>
<div class="mobile-item-card__body">
<el-form-item <el-form-item
label="仓库"
:prop="`${$index}.warehouseId`" :prop="`${$index}.warehouseId`"
:rules="formRules.warehouseId" :rules="formRules.warehouseId"
class="mb-0px!"
> >
<el-select <el-select
v-model="row.warehouseId" v-model="row.warehouseId"
@@ -23,6 +39,7 @@
filterable filterable
placeholder="请选择仓库" placeholder="请选择仓库"
@change="onChangeWarehouse($event, row)" @change="onChangeWarehouse($event, row)"
style="width: 100%"
> >
<el-option <el-option
v-for="item in warehouseList" v-for="item in warehouseList"
@@ -32,163 +49,105 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> <div class="mobile-item-card__info-row">
</el-table-column> <span class="mobile-item-card__info-label">库存</span>
<el-table-column label="产品名称" min-width="180"> <span class="mobile-item-card__info-value">{{ erpCountInputFormatter(row.stockCount) }}</span>
<template #default="{ row }"> </div>
<el-form-item class="mb-0px!"> <div class="mobile-item-card__info-row">
<el-input disabled v-model="row.productName" /> <span class="mobile-item-card__info-label">条码</span>
</el-form-item> <span class="mobile-item-card__info-value">{{ row.productBarCode || '-' }}</span>
</template> </div>
</el-table-column> <div class="mobile-item-card__info-row">
<el-table-column label="库存" min-width="100"> <span class="mobile-item-card__info-label">单位</span>
<template #default="{ row }"> <span class="mobile-item-card__info-value">{{ row.productUnitName || '-' }}</span>
<el-form-item class="mb-0px!"> </div>
<el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> <div class="mobile-item-card__info-row" v-if="row.totalCount != null">
</el-form-item> <span class="mobile-item-card__info-label">原数量</span>
</template> <span class="mobile-item-card__info-value">{{ erpCountInputFormatter(row.totalCount) }}</span>
</el-table-column> </div>
<div class="mobile-item-card__info-row" v-if="row.outCount != null">
<el-table-column label="条码" min-width="150"> <span class="mobile-item-card__info-label">已出库</span>
<template #default="{ row }"> <span class="mobile-item-card__info-value">{{ erpCountInputFormatter(row.outCount) }}</span>
<el-form-item class="mb-0px!"> </div>
<el-input disabled v-model="row.productBarCode" /> <div class="mobile-item-card__input-group">
</el-form-item> <el-form-item label="数量" :prop="`${$index}.count`" :rules="formRules.count">
</template> <el-input-number
</el-table-column> v-model="row.count"
<el-table-column label="单位" min-width="80"> controls-position="right"
<template #default="{ row }"> :min="0.0001"
<el-form-item class="mb-0px!"> :precision="4"
<el-input disabled v-model="row.productUnitName" /> style="width: 100%"
</el-form-item> />
</template> </el-form-item>
</el-table-column> <el-form-item label="产品单价" :prop="`${$index}.productPrice`">
<el-table-column <el-input-number
label="原数量" v-model="row.productPrice"
fixed="right" controls-position="right"
min-width="80" :min="0.0001"
v-if="formData[0]?.totalCount != null" :precision="4"
> style="width: 100%"
<template #default="{ row }"> />
<el-form-item class="mb-0px!"> </el-form-item>
<el-input disabled v-model="row.totalCount" :formatter="erpCountInputFormatter" /> </div>
</el-form-item> <div class="mobile-item-card__info-row">
</template> <span class="mobile-item-card__info-label">金额</span>
</el-table-column> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.totalProductPrice) }}</span>
<el-table-column </div>
label="已出库" <div class="mobile-item-card__info-row">
fixed="right" <span class="mobile-item-card__info-label">库存单价</span>
min-width="80" <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.stockUnitPrice) }}</span>
v-if="formData[0]?.outCount != null" </div>
> <div class="mobile-item-card__info-row">
<template #default="{ row }"> <span class="mobile-item-card__info-label">货值</span>
<el-form-item class="mb-0px!"> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.stockValue) }}</span>
<el-input disabled v-model="row.outCount" :formatter="erpCountInputFormatter" /> </div>
</el-form-item> <div class="mobile-item-card__info-row">
</template> <span class="mobile-item-card__info-label">毛利润</span>
</el-table-column> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.grossProfit) }}</span>
<el-table-column label="数量" prop="count" fixed="right" min-width="140"> </div>
<template #default="{ row, $index }"> <el-form-item label="税率(%" :prop="`${$index}.taxPercent`">
<el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!">
<el-input-number
v-model="row.count"
controls-position="right"
:min="0.0001"
:precision="4"
class="!w-100%"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="产品单价" fixed="right" min-width="120">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.productPrice`" class="mb-0px!">
<el-input-number
v-model="row.productPrice"
controls-position="right"
:min="0.0001"
:precision="4"
class="!w-100%"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="金额" prop="totalProductPrice" fixed="right" min-width="100">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.totalProductPrice`" class="mb-0px!">
<el-input
disabled
v-model="row.totalProductPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="库存单价" min-width="110" fixed="right">
<template #default="{ row }">
<el-form-item class="mb-0px!">
<el-input disabled v-model="row.stockUnitPrice" :formatter="erpPriceInputFormatter" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="货值" min-width="110" fixed="right">
<template #default="{ row }">
<el-form-item class="mb-0px!">
<el-input disabled v-model="row.stockValue" :formatter="erpPriceInputFormatter" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="毛利润" prop="grossProfit" fixed="right" min-width="110">
<template #default="{ row }">
<el-form-item class="mb-0px!">
<el-input disabled v-model="row.grossProfit" :formatter="erpPriceInputFormatter" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="税率(%" fixed="right" min-width="115">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.taxPercent`" class="mb-0px!">
<el-input-number <el-input-number
v-model="row.taxPercent" v-model="row.taxPercent"
controls-position="right" controls-position="right"
:min="0" :min="0"
:precision="4" :precision="4"
class="!w-100%" style="width: 100%"
/> />
</el-form-item> </el-form-item>
</template> <div class="mobile-item-card__info-row">
</el-table-column> <span class="mobile-item-card__info-label">税额</span>
<el-table-column label="税额" prop="taxPrice" fixed="right" min-width="120"> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.taxPrice) }}</span>
<template #default="{ row, $index }"> </div>
<el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> <div class="mobile-item-card__info-row">
<el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> <span class="mobile-item-card__info-label">税额合计</span>
<el-input disabled v-model="row.taxPrice" :formatter="erpPriceInputFormatter" /> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.totalPrice) }}</span>
</el-form-item> </div>
</el-form-item> <el-form-item label="备注" :prop="`${$index}.remark`">
</template>
</el-table-column>
<el-table-column label="税额合计" prop="totalPrice" fixed="right" min-width="100">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!">
<el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="备注" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.remark`" class="mb-0px!">
<el-input v-model="row.remark" placeholder="请输入备注" /> <el-input v-model="row.remark" placeholder="请输入备注" />
</el-form-item> </el-form-item>
</template> </div>
</el-table-column> </div>
<el-table-column align="center" fixed="right" label="操作" width="60">
<template #default="{ $index }"> <!-- 合计 -->
<el-button :disabled="formData.length === 1" @click="handleDelete($index)" link> <div class="mobile-item-summary" v-if="formData.length > 0">
<div class="mobile-item-summary__row">
</el-button> <span>合计数量</span>
</template> <span>{{ erpCountInputFormatter(summaryData.count) }}</span>
</el-table-column> </div>
</el-table> <div class="mobile-item-summary__row">
<span>合计金额</span>
<span>{{ erpPriceInputFormatter(summaryData.totalProductPrice) }}</span>
</div>
<div class="mobile-item-summary__row">
<span>毛利润</span>
<span>{{ erpPriceInputFormatter(summaryData.grossProfit) }}</span>
</div>
<div class="mobile-item-summary__row mobile-item-summary__row--total">
<span>税额合计</span>
<span>{{ erpPriceInputFormatter(summaryData.totalPrice) }}</span>
</div>
</div>
</div>
</el-form> </el-form>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -267,27 +226,15 @@ watch(
) )
/** 合计 */ /** 合计 */
const getSummaries = (param: SummaryMethodProps) => { const summaryData = computed(() => {
const { columns, data } = param return {
const sums: string[] = [] count: getSumValue(formData.value.map((item) => Number(item.count))),
columns.forEach((column, index: number) => { totalProductPrice: getSumValue(formData.value.map((item) => Number(item.totalProductPrice))),
if (index === 0) { taxPrice: getSumValue(formData.value.map((item) => Number(item.taxPrice))),
sums[index] = '合计' totalPrice: getSumValue(formData.value.map((item) => Number(item.totalPrice))),
return grossProfit: getSumValue(formData.value.map((item) => Number(item.grossProfit)))
} }
if (['count', 'totalProductPrice', 'taxPrice', 'totalPrice', 'grossProfit'].includes(column.property)) { })
const sum = getSumValue(data.map((item) => Number(item[column.property])))
sums[index] =
column.property === 'count'
? erpCountInputFormatter(sum)
: erpPriceInputFormatter(sum)
} else {
sums[index] = ''
}
})
return sums
}
/** 新增按钮操作 */ /** 新增按钮操作 */
const handleAdd = () => { const handleAdd = () => {
@@ -363,3 +310,82 @@ onMounted(async () => {
defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus) defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus)
}) })
</script> </script>
<style lang="scss" scoped>
.mobile-item-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-item-card {
background: #f9fafb;
border-radius: 8px;
border: 1px solid #ebeef5;
overflow: hidden;
&__header {
display: flex;
align-items: center;
padding: 10px 12px;
background: #f0f2f5;
gap: 8px;
}
&__index {
font-size: 13px;
font-weight: 600;
color: #409eff;
flex-shrink: 0;
}
&__name {
flex: 1;
font-size: 14px;
font-weight: 500;
color: #303133;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__body {
padding: 10px 12px;
}
&__info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 4px 0;
font-size: 13px;
}
&__info-label {
color: #909399;
flex-shrink: 0;
}
&__info-value {
color: #606266;
text-align: right;
}
&__input-group {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
}
.mobile-item-summary {
background: #fff;
border-radius: 8px;
border: 1px solid #ebeef5;
padding: 10px 12px;
&__row {
display: flex;
justify-content: space-between;
padding: 4px 0;
font-size: 13px;
color: #606266;
&--total {
font-weight: 600;
color: #303133;
border-top: 1px solid #ebeef5;
padding-top: 8px;
margin-top: 4px;
}
}
}
</style>

View File

@@ -1,149 +1,148 @@
<!-- 可收款的销售出库单列表 --> <!-- 可收款的销售出库单列表 -->
<template> <template>
<Dialog <el-drawer
title="选择销售出库(仅展示可收款)"
v-model="dialogVisible" v-model="dialogVisible"
:appendToBody="true" title="选择销售出库(仅展示可收款)"
:scroll="true" direction="rtl"
width="1080" size="100%"
:close-on-press-escape="true"
:destroy-on-close="true"
> >
<ContentWrap> <div class="mobile-enable-list">
<!-- 搜索工作 --> <!-- 搜索栏 -->
<el-form <div class="mobile-enable-list__search">
class="-mb-15px" <el-input
:model="queryParams" v-model="queryParams.no"
ref="queryFormRef" placeholder="搜索出库单号"
:inline="true" clearable
label-width="68px" @keyup.enter="handleQuery"
> :prefix-icon="Search"
<el-form-item label="出库单号" prop="no"> />
<el-input <el-button :icon="Filter" circle @click="filterVisible = true" />
v-model="queryParams.no" </div>
placeholder="请输入出库单号"
clearable <!-- 卡片列表 -->
@keyup.enter="handleQuery" <div class="mobile-enable-list__body" v-loading="loading">
class="!w-160px" <el-empty v-if="list.length === 0 && !loading" description="暂无可收款出库单" />
/> <div
</el-form-item> v-for="item in list"
:key="item.no"
class="mobile-enable-list__card"
:class="{ 'mobile-enable-list__card--selected': selectionList.includes(item) }"
@click="handleToggleSelection(item)"
>
<div class="mobile-enable-list__card-check">
<el-checkbox :model-value="selectionList.includes(item)" />
</div>
<div class="mobile-enable-list__card-content">
<div class="mobile-enable-list__card-no">{{ item.no }}</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">客户</span>
<span>{{ item.customerName || '-' }}</span>
</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">产品</span>
<span class="mobile-enable-list__card-ellipsis">{{ item.productNames || '-' }}</span>
</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">出库时间</span>
<span>{{ formatDate2(item.outTime) }}</span>
</div>
<div class="mobile-enable-list__card-nums">
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val mobile-enable-list__card-num-val--price">
¥{{ erpPriceInputFormatter(item.totalPrice) }}
</div>
<div class="mobile-enable-list__card-num-label">应收金额</div>
</div>
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val mobile-enable-list__card-num-val--price">
¥{{ erpPriceInputFormatter(item.receiptPrice || 0) }}
</div>
<div class="mobile-enable-list__card-num-label">已收金额</div>
</div>
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val mobile-enable-list__card-num-val--price">
<span v-if="(item.receiptPrice || 0) >= item.totalPrice">0</span>
<el-tag v-else type="danger">
¥{{ erpPriceInputFormatter(item.totalPrice - (item.receiptPrice || 0)) }}
</el-tag>
</div>
<div class="mobile-enable-list__card-num-label">未收金额</div>
</div>
</div>
</div>
</div>
</div>
<!-- 分页 -->
<div class="mobile-enable-list__pagination" v-if="total > 0">
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
:page-sizes="[10, 20]"
layout="total, prev, pager, next"
:pager-count="5"
@pagination="getList"
/>
</div>
</div>
<!-- 筛选抽屉 -->
<el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="60%" :append-to-body="true">
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
<el-form-item label="产品" prop="productId"> <el-form-item label="产品" prop="productId">
<el-select <el-select v-model="queryParams.productId" clearable filterable placeholder="请选择产品" style="width:100%">
v-model="queryParams.productId" <el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择产品"
class="!w-160px"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="出库时间" prop="orderTime"> <el-form-item label="出库时间" prop="outTime">
<el-date-picker <el-date-picker
v-model="queryParams.outTime" v-model="queryParams.outTime"
value-format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
type="daterange" type="daterange"
start-placeholder="开始日期" start-placeholder="开始日期"
end-placeholder="结束日期" end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" :default-time="['00:00:00', '23:59:59']"
class="!w-160px" style="width:100%"
/> />
</el-form-item> </el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
</el-form> </el-form>
</ContentWrap> <template #footer>
<el-button @click="resetQuery">重置</el-button>
<el-button type="primary" @click="filterVisible = false; handleQuery()">确认筛选</el-button>
</template>
</el-drawer>
<ContentWrap>
<el-table
ref="tableRef"
v-loading="loading"
:data="list"
:show-overflow-tooltip="true"
:stripe="true"
@selection-change="handleSelectionChange"
>
<el-table-column width="30" label="选择" type="selection" />
<el-table-column min-width="180" label="出库单号" align="center" prop="no" />
<el-table-column label="客户" align="center" prop="customerName" />
<el-table-column label="产品信息" align="center" prop="productNames" min-width="200" />
<el-table-column
label="出库时间"
align="center"
prop="outTime"
:formatter="dateFormatter2"
width="120px"
/>
<el-table-column label="创建人" align="center" prop="creatorName" />
<el-table-column
label="应收金额"
align="center"
prop="totalPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column
label="已收金额"
align="center"
prop="receiptPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column label="未收金额" align="center">
<template #default="scope">
<span v-if="scope.row.receiptPrice === scope.row.totalPrice">0</span>
<el-tag type="danger" v-else>
{{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.receiptPrice) }}
</el-tag>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNo"
:total="total"
@pagination="getList"
/>
</ContentWrap>
<template #footer> <template #footer>
<el-button :disabled="!selectionList.length" type="primary" @click="submitForm"> <el-button :disabled="!selectionList.length" type="primary" @click="submitForm">
</el-button> </el-button>
<el-button @click="dialogVisible = false"> </el-button> <el-button @click="dialogVisible = false"> </el-button>
</template> </template>
</Dialog> </el-drawer>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ElTable } from 'element-plus' import { Search, Filter } from '@element-plus/icons-vue'
import { dateFormatter2 } from '@/utils/formatTime'
import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils'
import { ProductApi, ProductVO } from '@/api/erp/product/product'
import { SaleOutApi, SaleOutVO } from '@/api/erp/sale/out' import { SaleOutApi, SaleOutVO } from '@/api/erp/sale/out'
import { SaleOutwarehouseApi, SaleOutwarehouseVO } from '@/api/erp/sale/outwarehouse' import { SaleOutwarehouseApi, SaleOutwarehouseVO } from '@/api/erp/sale/outwarehouse'
import { ProductApi, ProductVO } from '@/api/erp/product/product'
defineOptions({ name: 'SaleOutReceiptEnableList' }) import { formatDate } from '@/utils/formatTime'
import { erpPriceInputFormatter } from '@/utils'
const props = defineProps({
includeOutwarehouse: {
type: Boolean,
default: false
}
})
type ReceiptOutRow = (SaleOutVO | SaleOutwarehouseVO) & { type ReceiptOutRow = (SaleOutVO | SaleOutwarehouseVO) & {
customerName?: string customerName?: string
receiptPrice?: number receiptPrice?: number
productNames?: string productNames?: string
} }
const list = ref<ReceiptOutRow[]>([]) // 列表的数据
const tableRef = ref<InstanceType<typeof ElTable>>() const list = ref<ReceiptOutRow[]>([])
const total = ref(0) // 列表的总页数 const total = ref(0)
const loading = ref(false) // 列表的加载中 const loading = ref(false)
const dialogVisible = ref(false) // 弹窗的是否展示 const dialogVisible = ref(false)
const filterVisible = ref(false)
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@@ -153,28 +152,33 @@ const queryParams = reactive({
receiptEnable: true, receiptEnable: true,
customerId: undefined customerId: undefined
}) })
const currentNo = ref<string | undefined>(undefined) const queryFormRef = ref()
const queryFormRef = ref() // 搜索的表单 const productList = ref<ProductVO[]>([])
const productList = ref<ProductVO[]>([]) // 产品列表
/** 选中操作 */
const selectionList = ref<ReceiptOutRow[]>([]) const selectionList = ref<ReceiptOutRow[]>([])
const handleSelectionChange = (rows: ReceiptOutRow[]) => { const currentNo = ref<string | undefined>(undefined)
selectionList.value = rows
const formatDate2 = (date: any) => {
if (!date) return '-'
return formatDate(new Date(date), 'YYYY-MM-DD')
}
// 切换选中状态
const handleToggleSelection = (row: ReceiptOutRow) => {
const index = selectionList.value.indexOf(row)
if (index > -1) selectionList.value.splice(index, 1)
else selectionList.value.push(row)
} }
/** 打开弹窗 */ /** 打开弹窗 */
const open = async (customerId?: number, no?: string) => { const open = async (customerId?: number, no?: string) => {
dialogVisible.value = true dialogVisible.value = true
await nextTick() // 等待,避免 queryFormRef 为空 await nextTick()
// 加载可出库的订单列表
queryParams.customerId = customerId queryParams.customerId = customerId
currentNo.value = no currentNo.value = no
await resetQuery() await resetQuery()
// 加载产品列表
productList.value = await ProductApi.getProductSimpleList() productList.value = await ProductApi.getProductSimpleList()
} }
defineExpose({ open }) // 提供 open 方法,用于打开弹窗 defineExpose({ open })
/** 提交选择 */ /** 提交选择 */
const emits = defineEmits<{ const emits = defineEmits<{
@@ -184,46 +188,31 @@ const submitForm = () => {
try { try {
emits('success', selectionList.value) emits('success', selectionList.value)
} finally { } finally {
// 关闭弹窗
dialogVisible.value = false dialogVisible.value = false
} }
} }
/** 加载列表 */ /** 加载列表 */
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const saleOutData = await SaleOutApi.getSaleOutPage(queryParams) const saleOutData = await SaleOutApi.getSaleOutPage(queryParams)
let outwarehouseList: ReceiptOutRow[] = [] let outwarehouseList: ReceiptOutRow[] = []
let outwarehouseTotal = 0 let outwarehouseTotal = 0
if (props.includeOutwarehouse) { const includeOutwarehouse = false // 如果需要可通过props控制
if (includeOutwarehouse) {
const saleOutwarehouseData = await SaleOutwarehouseApi.getSaleOutwarehousePage(queryParams) const saleOutwarehouseData = await SaleOutwarehouseApi.getSaleOutwarehousePage(queryParams)
outwarehouseList = (saleOutwarehouseData.list || []).map((item: SaleOutwarehouseVO) => { outwarehouseList = (saleOutwarehouseData.list || []).map((item: SaleOutwarehouseVO) => {
const row = item as ReceiptOutRow const row = item as ReceiptOutRow
if (!row.productNames && item.itemList && item.itemList.length > 0) { if (!row.productNames && item.itemList && item.itemList.length) {
const names = item.itemList row.productNames = Array.from(new Set(item.itemList.map((it) => it.productName))).join('、')
.map((it) => it.productName)
.filter((name) => !!name)
row.productNames = Array.from(new Set(names)).join('、')
} }
return row return row
}) })
outwarehouseTotal = saleOutwarehouseData.total || 0 outwarehouseTotal = saleOutwarehouseData.total || 0
} }
list.value = [ list.value = [...(saleOutData.list || []), ...outwarehouseList]
...(saleOutData.list || []),
...outwarehouseList
] as ReceiptOutRow[]
total.value = (saleOutData.total || 0) + outwarehouseTotal total.value = (saleOutData.total || 0) + outwarehouseTotal
if (currentNo.value) {
await nextTick()
const match = list.value.find((item) => item.no === currentNo.value)
if (match) {
tableRef.value?.clearSelection()
tableRef.value?.toggleRowSelection(match, true)
selectionList.value = [match]
}
}
} finally { } finally {
loading.value = false loading.value = false
} }
@@ -231,7 +220,7 @@ const getList = async () => {
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value?.resetFields()
handleQuery() handleQuery()
} }
@@ -242,3 +231,101 @@ const handleQuery = () => {
getList() getList()
} }
</script> </script>
<style lang="scss" scoped>
/* 与可入库/出库/退货列表相同样式 */
.mobile-enable-list {
padding: 12px;
&__search {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
}
&__body {
display: flex;
flex-direction: column;
gap: 10px;
}
&__card {
display: flex;
background: #fff;
border-radius: 10px;
padding: 12px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
border: 2px solid transparent;
transition: border-color 0.2s;
&--selected {
border-color: var(--el-color-primary);
}
}
&__card-check {
flex-shrink: 0;
padding-right: 8px;
display: flex;
align-items: flex-start;
padding-top: 2px;
}
&__card-content {
flex: 1;
min-width: 0;
}
&__card-no {
font-weight: 600;
font-size: 14px;
color: #303133;
margin-bottom: 6px;
}
&__card-row {
display: flex;
justify-content: space-between;
font-size: 13px;
color: #606266;
padding: 2px 0;
}
&__card-label {
color: #909399;
flex-shrink: 0;
margin-right: 10px;
}
&__card-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 180px;
text-align: right;
}
&__card-nums {
display: flex;
justify-content: space-around;
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid #f0f0f0;
}
&__card-num {
text-align: center;
}
&__card-num-val {
font-size: 14px;
font-weight: 600;
color: #303133;
&--price {
color: #e6a23c;
}
}
&__card-num-label {
font-size: 11px;
color: #909399;
margin-top: 2px;
}
&__pagination {
margin-top: 12px;
display: flex;
justify-content: center;
:deep(.el-pagination) {
flex-wrap: wrap;
justify-content: center;
}
}
}
</style>

View File

@@ -1,314 +1,158 @@
<template> <template>
<doc-alert title="【销售】销售订单、出库、退货" url="https://doc.iocoder.cn/erp/sale/" /> <div class="mobile-sale-out">
<!-- 顶部操作栏 -->
<ContentWrap> <div class="mobile-header">
<!-- 搜索工作栏 --> <div class="mobile-header__search">
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="出库单号" prop="no">
<el-input <el-input
v-model="queryParams.no" v-model="queryParams.no"
placeholder="请输入出库单号" placeholder="搜索出库单号"
clearable clearable
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
class="!w-240px" :prefix-icon="Search"
/> />
</el-form-item> </div>
<el-form-item label="产品" prop="productId"> <div class="mobile-header__actions">
<el-select <el-button :icon="Filter" circle @click="filterVisible = true" />
v-model="queryParams.productId"
clearable
filterable
placeholder="请选择产品"
class="!w-240px"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="出库时间" prop="outTime">
<el-date-picker
v-model="queryParams.outTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-select
v-model="queryParams.customerId"
clearable
filterable
placeholder="请选择供客户"
class="!w-240px"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="仓库" prop="warehouseId">
<el-select
v-model="queryParams.warehouseId"
clearable
filterable
placeholder="请选择仓库"
class="!w-240px"
>
<el-option
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="创建人" prop="creator">
<el-select
v-model="queryParams.creator"
clearable
filterable
placeholder="请选择创建人"
class="!w-240px"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="关联订单" prop="orderNo">
<el-input
v-model="queryParams.orderNo"
placeholder="请输入关联订单"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="结算账户" prop="accountId">
<el-select
v-model="queryParams.accountId"
clearable
filterable
placeholder="请选择结算账户"
class="!w-240px"
>
<el-option
v-for="item in accountList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="收款状态" prop="receiptStatus">
<el-select
v-model="queryParams.receiptStatus"
placeholder="请选择有款状态"
clearable
class="!w-240px"
>
<el-option label="未收款" value="0" />
<el-option label="部分收款" value="1" />
<el-option label="全部收款" value="2" />
</el-select>
</el-form-item>
<el-form-item label="审核状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable class="!w-240px">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="queryParams.remark"
placeholder="请输入备注"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button <el-button
type="primary" type="primary"
plain :icon="Plus"
circle
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['erp:sale-out:create']" v-hasPermi="['erp:sale-out:create']"
> />
<Icon icon="ep:plus" class="mr-5px" /> 新增 </div>
</el-button> </div>
<el-button
type="success" <!-- 卡片列表 -->
plain <div class="mobile-list" v-loading="loading">
@click="handleExport" <div v-if="list.length === 0 && !loading" class="mobile-empty">
:loading="exportLoading" <el-empty description="暂无销售出库" />
v-hasPermi="['erp:sale-out:export']" </div>
> <div
<Icon icon="ep:download" class="mr-5px" /> 导出 v-for="item in list"
</el-button> :key="item.id"
<el-button class="mobile-card"
type="danger" @click="handleCardClick(item)"
plain >
@click="handleDelete(selectionList.map((item) => item.id))" <div class="mobile-card__header">
v-hasPermi="['erp:sale-out:delete']" <span class="mobile-card__no">{{ item.no }}</span>
:disabled="selectionList.length === 0" <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="item.status" />
> </div>
<Icon icon="ep:delete" class="mr-5px" /> 删除 <div class="mobile-card__body">
</el-button> <div class="mobile-card__row">
<el-button <span class="mobile-card__label">客户</span>
type="info" <span class="mobile-card__value">{{ item.customerName || '-' }}</span>
plain </div>
@click="handlePrint" <div class="mobile-card__row">
v-hasPermi="['erp:sale-out:query']" <span class="mobile-card__label">产品</span>
:disabled="selectionList.length === 0" <span class="mobile-card__value mobile-card__value--ellipsis">{{ item.productNames || '-' }}</span>
> </div>
<Icon icon="ep:printer" class="mr-5px" /> 打印 <div class="mobile-card__row">
</el-button> <span class="mobile-card__label">出库时间</span>
</el-form-item> <span class="mobile-card__value">{{ formatDate2(item.outTime) }}</span>
</el-form> </div>
</ContentWrap> <div class="mobile-card__row">
<span class="mobile-card__label">创建人</span>
<span class="mobile-card__value">{{ item.creatorName || '-' }}</span>
</div>
<div class="mobile-card__nums">
<div class="mobile-card__num-item">
<div class="mobile-card__num-val">{{ erpCountInputFormatter(item.totalCount) }}</div>
<div class="mobile-card__num-label">总数量</div>
</div>
<div class="mobile-card__num-item">
<div class="mobile-card__num-val mobile-card__num-val--price">¥{{ erpPriceInputFormatter(item.totalPrice) }}</div>
<div class="mobile-card__num-label">应收</div>
</div>
<div class="mobile-card__num-item">
<div class="mobile-card__num-val">¥{{ erpPriceInputFormatter(item.receiptPrice) }}</div>
<div class="mobile-card__num-label">已收</div>
</div>
<div class="mobile-card__num-item">
<div class="mobile-card__num-val" :class="{ 'mobile-card__num-val--danger': item.receiptPrice !== item.totalPrice }">
¥{{ erpPriceInputFormatter(item.totalPrice - item.receiptPrice) }}
</div>
<div class="mobile-card__num-label">未收</div>
</div>
</div>
</div>
<div class="mobile-card__footer">
<el-button size="small" @click.stop="openForm('detail', item.id)" v-hasPermi="['erp:sale-out:query']">详情</el-button>
<el-button size="small" type="primary" @click.stop="openForm('update', item.id)" v-hasPermi="['erp:sale-out:update']" :disabled="item.status === 20">编辑</el-button>
<el-button size="small" type="primary" @click.stop="handleUpdateStatus(item.id, 20)" v-hasPermi="['erp:sale-out:update-status']" v-if="item.status === 10">审批</el-button>
<el-button size="small" type="danger" @click.stop="handleUpdateStatus(item.id, 10)" v-hasPermi="['erp:sale-out:update-status']" v-if="item.status === 20">反审批</el-button>
<el-button size="small" type="danger" @click.stop="handleDelete([item.id])" v-hasPermi="['erp:sale-out:delete']">删除</el-button>
</div>
</div>
</div>
<!-- 列表 -->
<ContentWrap>
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
>
<el-table-column width="30" label="选择" type="selection" />
<el-table-column min-width="180" label="出库单号" align="center" prop="no" />
<el-table-column label="产品信息" align="center" prop="productNames" min-width="200" />
<el-table-column label="客户" align="center" prop="customerName" />
<el-table-column
label="出库时间"
align="center"
prop="outTime"
:formatter="dateFormatter2"
width="120px"
sortable
/>
<el-table-column label="创建人" align="center" prop="creatorName" />
<el-table-column
label="总数量"
align="center"
prop="totalCount"
:formatter="erpCountTableColumnFormatter"
/>
<el-table-column
label="应收金额"
align="center"
prop="totalPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column
label="已收金额"
align="center"
prop="receiptPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column label="未收金额" align="center">
<template #default="scope">
<span v-if="scope.row.receiptPrice === scope.row.totalPrice">0</span>
<el-tag type="danger" v-else>
{{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.receiptPrice) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="审核状态" align="center" fixed="right" width="90" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" width="220">
<template #default="scope">
<el-button
link
@click="openForm('detail', scope.row.id)"
v-hasPermi="['erp:sale-out:query']"
>
详情
</el-button>
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['erp:sale-out:update']"
:disabled="scope.row.status === 20"
>
编辑
</el-button>
<el-button
link
type="primary"
@click="handleUpdateStatus(scope.row.id, 20)"
v-hasPermi="['erp:sale-out:update-status']"
v-if="scope.row.status === 10"
>
审批
</el-button>
<el-button
link
type="danger"
@click="handleUpdateStatus(scope.row.id, 10)"
v-hasPermi="['erp:sale-out:update-status']"
v-else
>
反审批
</el-button>
<el-button
link
type="danger"
@click="handleDelete([scope.row.id])"
v-hasPermi="['erp:sale-out:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 --> <!-- 分页 -->
<Pagination <div class="mobile-pagination" v-if="total > 0">
:total="total" <Pagination
v-model:page="queryParams.pageNo" :total="total"
v-model:limit="queryParams.pageSize" v-model:page="queryParams.pageNo"
@pagination="getList" v-model:limit="queryParams.pageSize"
/> :page-sizes="[10, 20]"
</ContentWrap> layout="total, prev, pager, next"
:pager-count="5"
@pagination="getList"
/>
</div>
<!-- 表单弹窗添加/修改 --> <!-- 筛选抽屉 -->
<SaleOutForm ref="formRef" @success="getList" /> <el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="70%">
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
<el-form-item label="产品" prop="productId">
<el-select v-model="queryParams.productId" clearable filterable placeholder="请选择产品" style="width:100%">
<el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-select v-model="queryParams.customerId" clearable filterable placeholder="请选择客户" style="width:100%">
<el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="出库时间" prop="outTime">
<el-date-picker v-model="queryParams.outTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" style="width:100%" />
</el-form-item>
<el-form-item label="仓库" prop="warehouseId">
<el-select v-model="queryParams.warehouseId" clearable filterable placeholder="请选择仓库" style="width:100%">
<el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="创建人" prop="creator">
<el-select v-model="queryParams.creator" clearable filterable placeholder="请选择创建人" style="width:100%">
<el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="审核状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width:100%">
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="收款状态" prop="receiptStatus">
<el-select v-model="queryParams.receiptStatus" placeholder="请选择" clearable style="width:100%">
<el-option label="未收款" value="0" />
<el-option label="部分收款" value="1" />
<el-option label="全部收款" value="2" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="resetQuery">重置</el-button>
<el-button type="primary" @click="handleFilterConfirm">确认筛选</el-button>
</template>
</el-drawer>
<!-- 表单弹窗添加/修改 -->
<SaleOutForm ref="formRef" @success="getList" />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Search, Filter, Plus } from '@element-plus/icons-vue'
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter2 } from '@/utils/formatTime' import { formatDate } from '@/utils/formatTime'
import download from '@/utils/download' import download from '@/utils/download'
import { SaleOutApi, SaleOutVO } from '@/api/erp/sale/out' import { SaleOutApi, SaleOutVO } from '@/api/erp/sale/out'
import SaleOutForm from './SaleOutForm.vue' import SaleOutForm from './SaleOutForm.vue'
@@ -316,16 +160,12 @@ import { ProductApi, ProductVO } from '@/api/erp/product/product'
import { UserVO } from '@/api/system/user' import { UserVO } from '@/api/system/user'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
import { import {
erpCountTableColumnFormatter, erpCountInputFormatter,
erpPriceInputFormatter, erpPriceInputFormatter
erpPriceTableColumnFormatter
} from '@/utils' } from '@/utils'
import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer'
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
import { AccountApi, AccountVO } from '@/api/erp/finance/account' import { AccountApi, AccountVO } from '@/api/erp/finance/account'
import {PurchaseOrderVO} from "@/api/erp/purchase/order";
import { useMessage } from '@/hooks/web/useMessage'
import { useI18n } from '@/hooks/web/useI18n'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import { useCache, CACHE_KEY } from '@/hooks/web/useCache' import { useCache, CACHE_KEY } from '@/hooks/web/useCache'
import { onActivated } from 'vue' import { onActivated } from 'vue'
@@ -339,6 +179,7 @@ const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中 const loading = ref(true) // 列表的加载中
const list = ref<SaleOutVO[]>([]) // 列表的数据 const list = ref<SaleOutVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数 const total = ref(0) // 列表的总页数
const filterVisible = ref(false) // 筛选抽屉
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@@ -362,6 +203,11 @@ const userList = ref<UserVO[]>([]) // 用户列表
const warehouseList = ref<WarehouseVO[]>([]) // 仓库列表 const warehouseList = ref<WarehouseVO[]>([]) // 仓库列表
const accountList = ref<AccountVO[]>([]) // 账户列表 const accountList = ref<AccountVO[]>([]) // 账户列表
const formatDate2 = (date: any) => {
if (!date) return '-'
return formatDate(new Date(date), 'YYYY-MM-DD')
}
const applyStorageQuery = () => { const applyStorageQuery = () => {
const noValue = sessionStorage.getItem('erp_sale_out_no') const noValue = sessionStorage.getItem('erp_sale_out_no')
if (noValue && noValue.trim()) { if (noValue && noValue.trim()) {
@@ -394,7 +240,13 @@ const handleQuery = () => {
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value?.resetFields()
handleQuery()
}
/** 筛选确认 */
const handleFilterConfirm = () => {
filterVisible.value = false
handleQuery() handleQuery()
} }
@@ -404,6 +256,15 @@ const openForm = (type: string, id?: number) => {
formRef.value.open(type, id) formRef.value.open(type, id)
} }
/** 卡片点击 */
const handleCardClick = (row: SaleOutVO) => {
if (row.status === 20) {
openForm('detail', row.id)
} else if (row.status === 10) {
openForm('update', row.id)
}
}
/** 删除按钮操作 */ /** 删除按钮操作 */
const handleDelete = async (ids: number[]) => { const handleDelete = async (ids: number[]) => {
try { try {
@@ -414,33 +275,8 @@ const handleDelete = async (ids: number[]) => {
message.success(t('common.delSuccess')) message.success(t('common.delSuccess'))
// 刷新列表 // 刷新列表
await getList() await getList()
selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id))
} catch {} } catch {}
} }
/** 行点击操作 */
const handleRowClick = (row: SaleOutVO, column: any, event: MouseEvent) => {
// 检查是否点击了按钮、链接或其他交互元素
const target = event.target as HTMLElement
if (
target.tagName === 'BUTTON' ||
target.tagName === 'A' ||
target.tagName === 'I' ||
target.tagName === 'svg' ||
target.closest('button') ||
target.closest('a') ||
target.closest('.el-button') ||
target.closest('.el-checkbox')
) {
return
}
// 已审核打开详情页面,未审核打开编辑页面
if (row.status === 20) {
openForm('detail', row.id)
} else if (row.status === 10) {
openForm('update', row.id)
}
}
/** 审批/反审批操作 */ /** 审批/反审批操作 */
const handleUpdateStatus = async (id: number, status: number) => { const handleUpdateStatus = async (id: number, status: number) => {
try { try {
@@ -469,12 +305,6 @@ const handleExport = async () => {
} }
} }
/** 选中操作 */
const selectionList = ref<SaleOutVO[]>([])
const handleSelectionChange = (rows: SaleOutVO[]) => {
selectionList.value = rows
}
/** 获取打印设置 */ /** 获取打印设置 */
const getPrintSettings = async () => { const getPrintSettings = async () => {
const { wsCache } = useCache() const { wsCache } = useCache()
@@ -659,3 +489,137 @@ onActivated(() => {
// TODO 芋艿:可优化功能:列表界面,支持导入 // TODO 芋艿:可优化功能:列表界面,支持导入
// TODO 芋艿:可优化功能:详情界面,支持打印 // TODO 芋艿:可优化功能:详情界面,支持打印
</script> </script>
<style lang="scss" scoped>
.mobile-sale-out {
padding: 12px;
background: #f5f5f5;
min-height: 100vh;
}
.mobile-header {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
&__search {
flex: 1;
}
&__actions {
display: flex;
gap: 4px;
flex-shrink: 0;
}
}
.mobile-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-empty {
padding: 40px 0;
}
.mobile-card {
background: #fff;
border-radius: 10px;
padding: 14px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
&__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
&__no {
font-weight: 600;
font-size: 15px;
color: #303133;
}
&__body {
font-size: 13px;
}
&__row {
display: flex;
justify-content: space-between;
padding: 3px 0;
}
&__label {
color: #909399;
flex-shrink: 0;
margin-right: 12px;
}
&__value {
color: #606266;
text-align: right;
&--ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200px;
}
}
&__nums {
display: flex;
justify-content: space-around;
margin-top: 10px;
padding: 10px 0;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
}
&__num-item {
text-align: center;
}
&__num-val {
font-size: 15px;
font-weight: 600;
color: #303133;
&--price {
color: #e6a23c;
}
&--danger {
color: #f56c6c;
}
}
&__num-label {
font-size: 11px;
color: #909399;
margin-top: 2px;
}
&__footer {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 10px;
}
}
.mobile-pagination {
margin-top: 12px;
display: flex;
justify-content: center;
:deep(.el-pagination) {
flex-wrap: wrap;
justify-content: center;
}
}
</style>

View File

@@ -1,209 +1,109 @@
<template> <template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1440"> <el-drawer
<el-form v-model="dialogVisible"
ref="formRef" :title="dialogTitle"
:model="formData" direction="rtl"
:rules="formRules" size="100%"
label-width="100px" :close-on-press-escape="true"
v-loading="formLoading" :destroy-on-close="true"
:disabled="disabled" :append-to-body="true"
> class="mobile-form-drawer"
<el-row :gutter="20"> >
<el-col :span="8"> <div class="mobile-form" v-loading="formLoading">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-position="top"
:disabled="disabled"
>
<!-- 基本信息 -->
<div class="mobile-form__section">
<div class="mobile-form__section-title">基本信息</div>
<el-form-item label="出库单号" prop="no"> <el-form-item label="出库单号" prop="no">
<el-input disabled v-model="formData.no" placeholder="保存时自动生成" /> <el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出库时间" prop="outTime"> <el-form-item label="出库时间" prop="outTime">
<el-date-picker <el-date-picker v-model="formData.outTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择出库时间" style="width: 100%" />
v-model="formData.outTime"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择出库时间"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="关联明细" prop="stockRecordIds"> <el-form-item label="关联明细" prop="stockRecordIds">
<el-input v-model="formData.stockRecordText" readonly> <el-input v-model="formData.stockRecordText" readonly>
<template #append> <template #append>
<el-button @click="openStockRecordList"> <el-button @click="openStockRecordList">
<Icon icon="ep:search" /> 选择 <Icon icon="ep:search" /> 选择
</el-button> </el-button>
<!-- <el-button type="primary" @click="addProductDirectly">-->
<!-- <Icon icon="ep:plus" /> 直接添加产品-->
<!-- </el-button>-->
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="仓库" prop="warehouseId"> <el-form-item label="仓库" prop="warehouseId">
<el-select <el-select v-model="formData.warehouseId" clearable filterable placeholder="请选择仓库" style="width: 100%">
v-model="formData.warehouseId" <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择仓库"
class="!w-1/1"
>
<el-option
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="客户" prop="customerId"> <el-form-item label="客户" prop="customerId">
<el-select <el-select v-model="formData.customerId" clearable filterable placeholder="请选择客户" style="width: 100%">
v-model="formData.customerId" <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择客户"
class="!w-1/1"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="销售人员" prop="saleUserId"> <el-form-item label="销售人员" prop="saleUserId">
<el-select <el-select v-model="formData.saleUserId" clearable filterable placeholder="请选择销售人员" style="width: 100%">
v-model="formData.saleUserId" <el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
clearable
filterable
placeholder="请选择销售人员"
class="!w-1/1"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input <el-input type="textarea" v-model="formData.remark" :rows="2" placeholder="请输入备注" />
type="textarea"
v-model="formData.remark"
:rows="1"
placeholder="请输入备注"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="附件" prop="fileUrl"> <el-form-item label="附件" prop="fileUrl">
<UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" />
</el-form-item> </el-form-item>
</el-col> </div>
</el-row>
<!-- 子表的表 --> <!-- 出库产品清 -->
<ContentWrap> <div class="mobile-form__section">
<el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> <div class="mobile-form__section-title">出库产品清单</div>
<el-tab-pane label="出库产品清单" name="item"> <SaleOutwarehouseItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" />
<SaleOutwarehouseItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> </div>
</el-tab-pane>
</el-tabs> <!-- 价格信息 -->
</ContentWrap> <div class="mobile-form__section">
<el-row :gutter="20"> <div class="mobile-form__section-title">价格信息</div>
<el-col :span="8">
<el-form-item label="优惠率(%" prop="discountPercent"> <el-form-item label="优惠率(%" prop="discountPercent">
<el-input-number <el-input-number v-model="formData.discountPercent" controls-position="right" :min="0" :precision="2" placeholder="请输入优惠率" style="width: 100%" />
v-model="formData.discountPercent"
controls-position="right"
:min="0"
:precision="2"
placeholder="请输入优惠率"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="收款优惠" prop="discountPrice"> <el-form-item label="收款优惠" prop="discountPrice">
<el-input <el-input disabled v-model="formData.discountPrice" :formatter="erpPriceInputFormatter" />
disabled
v-model="formData.discountPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="优惠后金额"> <el-form-item label="优惠后金额">
<el-input <el-input disabled :model-value="formData.totalPrice - formData.otherPrice" :formatter="erpPriceInputFormatter" />
disabled
:model-value="formData.totalPrice - formData.otherPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="其它费用" prop="otherPrice"> <el-form-item label="其它费用" prop="otherPrice">
<el-input-number <el-input-number v-model="formData.otherPrice" controls-position="right" :min="0" :precision="2" placeholder="请输入其它费用" style="width: 100%" />
v-model="formData.otherPrice"
controls-position="right"
:min="0"
:precision="2"
placeholder="请输入其它费用"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结算账户" prop="accountId"> <el-form-item label="结算账户" prop="accountId">
<el-select <el-select v-model="formData.accountId" clearable filterable placeholder="请选择结算账户" style="width: 100%">
v-model="formData.accountId" <el-option v-for="item in accountList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择结算账户"
class="!w-1/1"
>
<el-option
v-for="item in accountList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="应收金额"> <el-form-item label="应收金额">
<el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" />
</el-form-item> </el-form-item>
</el-col> <el-form-item label="总金额(反算单价)">
<el-col :span="8"> <el-input-number v-model="formData.reverseCalculationAmount" :min="0" :precision="4" style="width: 100%" placeholder="输入总金额反算单价" @change="handleReverseCalculation" />
<el-form-item label="总金额">
<el-input-number
v-model="formData.reverseCalculationAmount"
:min="0"
:precision="4"
class="!w-1/1"
placeholder="输入总金额反算单价"
@change="handleReverseCalculation"
/>
</el-form-item> </el-form-item>
</el-col> </div>
</el-row> </el-form>
</el-form> </div>
<!-- 底部按钮 -->
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> <div class="mobile-form__footer">
<el-button @click="dialogVisible = false" style="flex:1"> </el-button>
</el-button> <el-button type="primary" @click="submitForm" :disabled="formLoading" v-if="!disabled" style="flex:2">
<el-button @click="dialogVisible = false"> </el-button>
</el-button>
</div>
</template> </template>
</Dialog> </el-drawer>
<!-- 库存批次选择弹窗 --> <!-- 库存批次选择弹窗 -->
<StockBatchSelectionDialog ref="stockBatchSelectionRef" @success="handleBatchSelectionChange" /> <StockBatchSelectionDialog ref="stockBatchSelectionRef" @success="handleBatchSelectionChange" />
@@ -578,3 +478,31 @@ const resetForm = () => {
formRef.value?.resetFields() formRef.value?.resetFields()
} }
</script> </script>
<style lang="scss" scoped>
.mobile-form {
padding: 12px;
}
.mobile-form__section {
background: #fff;
border-radius: 8px;
padding: 14px;
margin-bottom: 12px;
}
.mobile-form__section-title {
font-size: 15px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
}
.mobile-form__footer {
display: flex;
gap: 12px;
padding: 0 12px;
}
</style>

View File

@@ -4,18 +4,34 @@
:model="formData" :model="formData"
:rules="formRules" :rules="formRules"
v-loading="formLoading" v-loading="formLoading"
label-width="0px" label-position="top"
:inline-message="true" :inline-message="true"
:disabled="disabled" :disabled="disabled"
> >
<el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> <div class="mobile-item-list">
<el-table-column label="序号" type="index" align="center" width="60" /> <div
<el-table-column label="仓库名称" min-width="125"> v-for="(row, $index) in formData"
<template #default="{ row, $index }"> :key="$index"
class="mobile-item-card"
>
<div class="mobile-item-card__header">
<span class="mobile-item-card__index">#{{ $index + 1 }}</span>
<span class="mobile-item-card__name">{{ row.productName || '未选择产品' }}</span>
<el-button
:disabled="disabled || formData.length === 1 || !!row.stockRecordId"
@click="handleDelete($index)"
link
type="danger"
size="small"
>
删除
</el-button>
</div>
<div class="mobile-item-card__body">
<el-form-item <el-form-item
label="仓库"
:prop="`${$index}.warehouseId`" :prop="`${$index}.warehouseId`"
:rules="formRules.warehouseId" :rules="formRules.warehouseId"
class="mb-0px!"
> >
<el-select <el-select
v-model="row.warehouseId" v-model="row.warehouseId"
@@ -23,6 +39,7 @@
filterable filterable
placeholder="请选择仓库" placeholder="请选择仓库"
@change="onChangeWarehouse($event, row)" @change="onChangeWarehouse($event, row)"
style="width: 100%"
> >
<el-option <el-option
v-for="item in warehouseList" v-for="item in warehouseList"
@@ -32,24 +49,18 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> <el-form-item
</el-table-column> label="产品"
<el-table-column label="批号" min-width="120"> :prop="`${$index}.productId`"
<template #default="{ row }"> :rules="formRules.productId"
<el-form-item class="mb-0px!"> >
<el-input disabled v-model="row.batchCode" placeholder="批次编号" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="产品名称" min-width="180">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!">
<el-select <el-select
v-model="row.productId" v-model="row.productId"
clearable clearable
filterable filterable
placeholder="请选择产品" placeholder="请选择产品"
@change="onChangeProduct($event, row)" @change="onChangeProduct($event, row)"
style="width: 100%"
> >
<el-option <el-option
v-for="item in productList" v-for="item in productList"
@@ -59,114 +70,91 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> <div class="mobile-item-card__info-row" v-if="row.batchCode">
</el-table-column> <span class="mobile-item-card__info-label">批号</span>
<el-table-column label="库存" min-width="100"> <span class="mobile-item-card__info-value">{{ row.batchCode }}</span>
<template #default="{ row }"> </div>
<el-form-item class="mb-0px!"> <div class="mobile-item-card__info-row">
<el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> <span class="mobile-item-card__info-label">库存</span>
</el-form-item> <span class="mobile-item-card__info-value">{{ erpCountInputFormatter(row.stockCount) }}</span>
</template> </div>
</el-table-column> <div class="mobile-item-card__info-row">
<el-table-column label="条码" min-width="150"> <span class="mobile-item-card__info-label">条码</span>
<template #default="{ row }"> <span class="mobile-item-card__info-value">{{ row.productBarCode || '-' }}</span>
<el-form-item class="mb-0px!"> </div>
<el-input disabled v-model="row.productBarCode" /> <div class="mobile-item-card__info-row">
</el-form-item> <span class="mobile-item-card__info-label">单位</span>
</template> <span class="mobile-item-card__info-value">{{ row.productUnitName || '-' }}</span>
</el-table-column> </div>
<el-table-column label="单位" min-width="80"> <div class="mobile-item-card__input-group">
<template #default="{ row }"> <el-form-item label="数量" :prop="`${$index}.count`" :rules="formRules.count">
<el-form-item class="mb-0px!"> <el-input-number
<el-input disabled v-model="row.productUnitName" /> v-model="row.count"
</el-form-item> controls-position="right"
</template> :min="0"
</el-table-column> :precision="4"
<el-table-column label="数量" prop="count" fixed="right" min-width="140"> style="width: 100%"
<template #default="{ row, $index }"> :disabled="!!row.stockRecordId"
<el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!"> />
<el-input-number </el-form-item>
v-model="row.count" <el-form-item label="产品单价" :prop="`${$index}.productPrice`">
controls-position="right" <el-input-number
:min="0" v-model="row.productPrice"
:precision="4" controls-position="right"
class="!w-100%" :min="0"
:disabled="!!row.stockRecordId" :precision="8"
/> style="width: 100%"
</el-form-item> />
</template> </el-form-item>
</el-table-column> </div>
<el-table-column label="产品单价" fixed="right" min-width="120"> <div class="mobile-item-card__info-row">
<template #default="{ row, $index }"> <span class="mobile-item-card__info-label">金额</span>
<el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.totalProductPrice) }}</span>
<el-input-number </div>
v-model="row.productPrice" <el-form-item label="税率(%" :prop="`${$index}.taxPercent`">
controls-position="right"
:min="0"
:precision="8"
class="!w-100%"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="金额" prop="totalProductPrice" fixed="right" min-width="100">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.totalProductPrice`" class="mb-0px!">
<el-input
disabled
v-model="row.totalProductPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="税率(%" fixed="right" min-width="115">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.taxPercent`" class="mb-0px!">
<el-input-number <el-input-number
v-model="row.taxPercent" v-model="row.taxPercent"
controls-position="right" controls-position="right"
:min="0" :min="0"
:precision="2" :precision="2"
class="!w-100%" style="width: 100%"
/> />
</el-form-item> </el-form-item>
</template> <div class="mobile-item-card__info-row">
</el-table-column> <span class="mobile-item-card__info-label">税额</span>
<el-table-column label="税额" prop="taxPrice" fixed="right" min-width="120"> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.taxPrice) }}</span>
<template #default="{ row, $index }"> </div>
<el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> <div class="mobile-item-card__info-row">
<el-input disabled v-model="row.taxPrice" :formatter="erpPriceInputFormatter" /> <span class="mobile-item-card__info-label">税额合计</span>
</el-form-item> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.totalPrice) }}</span>
</template> </div>
</el-table-column> <el-form-item label="备注" :prop="`${$index}.remark`">
<el-table-column label="税额合计" prop="totalPrice" fixed="right" min-width="100">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!">
<el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="备注" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.remark`" class="mb-0px!">
<el-input v-model="row.remark" placeholder="请输入备注" /> <el-input v-model="row.remark" placeholder="请输入备注" />
</el-form-item> </el-form-item>
</template> </div>
</el-table-column> </div>
<el-table-column align="center" fixed="right" label="操作" width="120">
<template #header> <!-- 合计 -->
<el-button type="success" @click="handleAdd"> <div class="mobile-item-summary" v-if="formData.length > 0">
<Icon icon="ep:plus" class="mr-5px" /> 新增 <div class="mobile-item-summary__row">
</el-button> <span>合计数量</span>
</template> <span>{{ erpCountInputFormatter(summaryData.count) }}</span>
<template #default="{ $index, row }"> </div>
<el-button :disabled="formData.length === 1 || !!row.stockRecordId" @click="handleDelete($index)" link type="danger"> <div class="mobile-item-summary__row">
<Icon icon="ep:delete" /> 删除 <span>合计金额</span>
</el-button> <span>{{ erpPriceInputFormatter(summaryData.totalProductPrice) }}</span>
</template> </div>
</el-table-column> <div class="mobile-item-summary__row mobile-item-summary__row--total">
</el-table> <span>税额合计</span>
<span>{{ erpPriceInputFormatter(summaryData.totalPrice) }}</span>
</div>
</div>
<!-- 添加按钮 -->
<div class="mobile-item-add" v-if="!disabled">
<el-button @click="handleAdd" round>+ 添加出库产品</el-button>
</div>
</div>
</el-form> </el-form>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -236,25 +224,14 @@ watch(
) )
/** 合计 */ /** 合计 */
const getSummaries = (param) => { const summaryData = computed(() => {
const { columns, data } = param return {
const sums = [] count: getSumValue(formData.value.map((item) => Number(item.count))),
columns.forEach((column, index) => { totalProductPrice: getSumValue(formData.value.map((item) => Number(item.totalProductPrice))),
if (index === 0) { taxPrice: getSumValue(formData.value.map((item) => Number(item.taxPrice))),
sums[index] = '合计' totalPrice: getSumValue(formData.value.map((item) => Number(item.totalPrice)))
return }
} })
if (['count', 'totalProductPrice', 'taxPrice', 'totalPrice'].includes(column.property)) {
const sum = getSumValue(data.map((item) => Number(item[column.property])))
sums[index] =
column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum)
} else {
sums[index] = ''
}
})
return sums
}
/** 新增按钮操作 */ /** 新增按钮操作 */
const handleAdd = () => { const handleAdd = () => {
@@ -338,3 +315,86 @@ onMounted(async () => {
productList.value = await ProductApi.getProductSimpleList() productList.value = await ProductApi.getProductSimpleList()
}) })
</script> </script>
<style lang="scss" scoped>
.mobile-item-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-item-card {
background: #f9fafb;
border-radius: 8px;
border: 1px solid #ebeef5;
overflow: hidden;
&__header {
display: flex;
align-items: center;
padding: 10px 12px;
background: #f0f2f5;
gap: 8px;
}
&__index {
font-size: 13px;
font-weight: 600;
color: #409eff;
flex-shrink: 0;
}
&__name {
flex: 1;
font-size: 14px;
font-weight: 500;
color: #303133;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__body {
padding: 10px 12px;
}
&__info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 4px 0;
font-size: 13px;
}
&__info-label {
color: #909399;
flex-shrink: 0;
}
&__info-value {
color: #606266;
text-align: right;
}
&__input-group {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
}
.mobile-item-summary {
background: #fff;
border-radius: 8px;
border: 1px solid #ebeef5;
padding: 10px 12px;
&__row {
display: flex;
justify-content: space-between;
padding: 4px 0;
font-size: 13px;
color: #606266;
&--total {
font-weight: 600;
color: #303133;
border-top: 1px solid #ebeef5;
padding-top: 8px;
margin-top: 4px;
}
}
}
.mobile-item-add {
text-align: center;
padding: 8px 0;
}
</style>

View File

@@ -1,381 +1,231 @@
<template> <template>
<doc-alert title="【销售】销售订单、出库、退货" url="https://doc.iocoder.cn/erp/sale/" /> <div class="mobile-sale-outwarehouse">
<!-- 顶部操作栏 -->
<ContentWrap> <div class="mobile-header">
<!-- 搜索工作栏 --> <div class="mobile-header__search">
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="出库单号" prop="no">
<el-input <el-input
v-model="queryParams.no" v-model="queryParams.no"
placeholder="请输入出库单号" placeholder="搜索出库单号"
clearable clearable
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
class="!w-240px" :prefix-icon="Search"
/> />
</el-form-item> </div>
<el-form-item label="产品" prop="productId"> <div class="mobile-header__actions">
<el-select <el-button :icon="Filter" circle @click="filterVisible = true" />
v-model="queryParams.productId"
clearable
filterable
placeholder="请选择产品"
class="!w-240px"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="出库时间" prop="outTime">
<el-date-picker
v-model="queryParams.outTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-select
v-model="queryParams.customerId"
clearable
filterable
placeholder="请选择客户"
class="!w-240px"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="仓库" prop="warehouseId">
<el-select
v-model="queryParams.warehouseId"
clearable
filterable
placeholder="请选择仓库"
class="!w-240px"
>
<el-option
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
clearable
placeholder="请选择状态"
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ERP_SALE_OUT_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="收款状态" prop="receiptStatus">
<el-select
v-model="queryParams.receiptStatus"
clearable
placeholder="请选择收款状态"
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ERP_RECEIPT_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="账户" prop="accountId">
<el-select
v-model="queryParams.accountId"
clearable
filterable
placeholder="请选择账户"
class="!w-240px"
>
<el-option
v-for="item in accountList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="queryParams.remark"
placeholder="请输入备注"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="创建者" prop="creator">
<el-input
v-model="queryParams.creator"
placeholder="请输入创建者"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" /> 重置</el-button>
<el-button <el-button
type="primary" type="primary"
plain :icon="Plus"
circle
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['erp:sale-outwarehouse:create']" v-hasPermi="['erp:sale-outwarehouse:create']"
> />
<Icon icon="ep:plus" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['erp:sale-outwarehouse:export']"
>
<Icon icon="ep:download" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" @row-click="handleRowClick">
<el-table-column label="出库单号" align="center" prop="no" min-width="180">
<template #default="scope">
<span>{{ scope.row.no }}</span>
</template>
</el-table-column>
<el-table-column label="客户" align="center" prop="customerName" min-width="180">
<template #default="scope">
<span>{{ scope.row.customerName }}</span>
</template>
</el-table-column>
<el-table-column label="产品" align="center" min-width="120">
<template #default="scope">
<div v-if="scope.row.itemList && scope.row.itemList.length > 0">
<div v-for="(productName, index) in getUniqueProductNames(scope.row.itemList)" :key="index" class="mb-1">
{{ productName }}
</div>
</div>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="出库时间" align="center" prop="outTime" min-width="180" sortable>
<template #default="scope">
<span>{{ formatDate(scope.row.outTime, 'YYYY-MM-DD HH:mm:ss') }}</span>
</template>
</el-table-column>
<el-table-column label="仓库" align="center" prop="warehouseNames" min-width="180">
<template #default="scope">
<div v-if="scope.row.warehouseNames">
<div v-for="(warehouse, index) in scope.row.warehouseNames.split(',')" :key="index">
{{ warehouse }}
</div>
</div>
<span v-else>{{ scope.row.warehouseName || '' }}</span>
</template>
</el-table-column>
<el-table-column label="合计数量" align="center" prop="totalCount" min-width="100">
<template #default="scope">
<span>{{ erpCountTableColumnFormatter(null, null, scope.row.totalCount, null) }}</span>
</template>
</el-table-column>
<el-table-column label="合计金额" align="center" prop="totalPrice" min-width="120">
<template #default="scope">
<span>{{ erpPriceTableColumnFormatter(null, null, scope.row.totalPrice, null) }}</span>
</template>
</el-table-column>
<el-table-column label="收款状态" align="center" prop="receiptStatus" min-width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_RECEIPT_STATUS" :value="scope.row.receiptStatus" />
</template>
</el-table-column>
<el-table-column label="已收款金额" align="center" prop="receiptPrice" min-width="120">
<template #default="scope">
<span>{{ erpPriceTableColumnFormatter(null, null, scope.row.receiptPrice, null) }}</span>
</template>
</el-table-column>
<el-table-column label="出库状态" align="center" prop="status" min-width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
width="350"
fixed="right"
>
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['erp:sale-outwarehouse:update']"
:disabled="scope.row.status === 20"
>
<Icon icon="ep:edit" />修改
</el-button>
<el-button
link
type="primary"
@click="openForm('detail', scope.row.id)"
v-hasPermi="['erp:sale-outwarehouse:query']"
>
<Icon icon="ep:view" />详情
</el-button>
<el-button
link
type="primary"
@click="handleUpdateStatus(scope.row.id, scope.row.status === 10 ? 20 : 10)"
v-if="scope.row.status === 10 || scope.row.status === 20"
v-hasPermi="['erp:sale-outwarehouse:update-status']"
>
<Icon icon="ep:check" />{{ scope.row.status === 10 ? '审核' : '反审核' }}
</el-button>
<el-button
link
type="success"
@click="openReceiptForm(scope.row)"
v-if="scope.row.status === 20"
v-hasPermi="['erp:sale-outwarehouse:update']"
>
<Icon icon="ep:money" />收款
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['erp:sale-outwarehouse:delete']"
>
<Icon icon="ep:delete" />删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<SaleOutwarehouseForm ref="formRef" @success="getList" />
<!-- 收款表单弹窗 -->
<el-dialog
v-model="receiptDialogVisible"
title="收款"
width="700px"
@closed="receiptDialogVisible = false"
>
<div v-if="currentOutwarehouse">
<div class="mb-4 p-4 bg-gray-50 rounded">
<div class="flex justify-between mb-2">
<div><strong>单号</strong>{{ currentOutwarehouse.no }}</div>
<div><strong>客户</strong>{{ currentOutwarehouse.customerName }}</div>
</div>
<div class="flex justify-between mb-2">
<div><strong>合计金额</strong>{{ erpPriceTableColumnFormatter(null, null, currentOutwarehouse.totalPrice, null) }}</div>
<div><strong>已收款</strong>{{ erpPriceTableColumnFormatter(null, null, currentOutwarehouse.receiptPrice, null) }}</div>
</div>
<div>
<strong>未收款</strong>{{ erpPriceTableColumnFormatter(null, null, (currentOutwarehouse.totalPrice || 0) - (currentOutwarehouse.receiptPrice || 0), null) }}
</div>
</div> </div>
</div>
<el-form :model="receiptForm" label-width="100px"> <!-- 卡片列表 -->
<el-form-item label="收款金额" required> <div class="mobile-list" v-loading="loading">
<el-input-number <div v-if="list.length === 0 && !loading" class="mobile-empty">
v-model="receiptForm.amount" <el-empty description="暂无销售出库" />
:min="0" </div>
:precision="2" <div
:step="0.01" v-for="item in list"
:max="(currentOutwarehouse.totalPrice || 0) - (currentOutwarehouse.receiptPrice || 0)" :key="item.id"
style="width: 100%" class="mobile-card"
/> @click="handleCardClick(item)"
</el-form-item> >
<el-form-item label="收款日期" required> <div class="mobile-card__header">
<el-date-picker <span class="mobile-card__no">{{ item.no }}</span>
v-model="receiptForm.date" <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="item.status" />
type="date" </div>
value-format="YYYY-MM-DD" <div class="mobile-card__body">
style="width: 100%" <div class="mobile-card__row">
/> <span class="mobile-card__label">客户</span>
</el-form-item> <span class="mobile-card__value">{{ item.customerName || '-' }}</span>
<el-form-item label="备注"> </div>
<el-input <div class="mobile-card__row">
v-model="receiptForm.remark" <span class="mobile-card__label">产品</span>
type="textarea" <span class="mobile-card__value mobile-card__value--ellipsis">
:rows="2" {{ item.itemList && item.itemList.length > 0 ? getUniqueProductNames(item.itemList).join(', ') : '-' }}
placeholder="请输入备注" </span>
style="width: 100%" </div>
/> <div class="mobile-card__row">
</el-form-item> <span class="mobile-card__label">出库时间</span>
</el-form> <span class="mobile-card__value">{{ formatDate(item.outTime, 'YYYY-MM-DD') }}</span>
</div>
<div class="mt-4"> <div class="mobile-card__row">
<h3 class="mb-2 font-bold">收款记录</h3> <span class="mobile-card__label">仓库</span>
<el-table :data="receiptHistory" border style="width: 100%"> <span class="mobile-card__value">{{ item.warehouseNames || item.warehouseName || '-' }}</span>
<el-table-column prop="date" label="收款日期" width="120" /> </div>
<el-table-column prop="amount" label="收款金额"> <div class="mobile-card__row">
<template #default="scope"> <span class="mobile-card__label">收款状态</span>
{{ erpPriceTableColumnFormatter(null, null, scope.row.amount, null) }} <dict-tag :type="DICT_TYPE.ERP_RECEIPT_STATUS" :value="item.receiptStatus" />
</template> </div>
</el-table-column> <div class="mobile-card__nums">
<el-table-column prop="remainAmount" label="剩余未收款"> <div class="mobile-card__num-item">
<template #default="scope"> <div class="mobile-card__num-val">{{ erpCountTableColumnFormatter(null, null, item.totalCount, null) }}</div>
{{ erpPriceTableColumnFormatter(null, null, scope.row.remainAmount, null) }} <div class="mobile-card__num-label">数量</div>
</template> </div>
</el-table-column> <div class="mobile-card__num-item">
<el-table-column prop="remark" label="备注" /> <div class="mobile-card__num-val mobile-card__num-val--price">¥{{ erpPriceTableColumnFormatter(null, null, item.totalPrice, null) }}</div>
</el-table> <div class="mobile-card__num-label">合计</div>
<div v-if="!receiptHistory.length" class="text-center py-4 text-gray-500"> </div>
暂无收款记录 <div class="mobile-card__num-item">
<div class="mobile-card__num-val">¥{{ erpPriceTableColumnFormatter(null, null, item.receiptPrice, null) }}</div>
<div class="mobile-card__num-label">已收</div>
</div>
<div class="mobile-card__num-item">
<div class="mobile-card__num-val" :class="{ 'mobile-card__num-val--danger': (item.totalPrice || 0) - (item.receiptPrice || 0) > 0 }">
¥{{ erpPriceTableColumnFormatter(null, null, (item.totalPrice || 0) - (item.receiptPrice || 0), null) }}
</div>
<div class="mobile-card__num-label">未收</div>
</div>
</div>
</div>
<div class="mobile-card__footer">
<el-button size="small" @click.stop="openForm('detail', item.id)" v-hasPermi="['erp:sale-outwarehouse:query']">详情</el-button>
<el-button size="small" type="primary" @click.stop="openForm('update', item.id)" v-hasPermi="['erp:sale-outwarehouse:update']" :disabled="item.status === 20">修改</el-button>
<el-button size="small" type="primary" @click.stop="handleUpdateStatus(item.id, item.status === 10 ? 20 : 10)" v-if="item.status === 10 || item.status === 20" v-hasPermi="['erp:sale-outwarehouse:update-status']">
{{ item.status === 10 ? '审核' : '反审核' }}
</el-button>
<el-button size="small" type="success" @click.stop="openReceiptForm(item)" v-if="item.status === 20" v-hasPermi="['erp:sale-outwarehouse:update']">收款</el-button>
<el-button size="small" type="danger" @click.stop="handleDelete(item.id)" v-hasPermi="['erp:sale-outwarehouse:delete']">删除</el-button>
</div> </div>
</div> </div>
</div> </div>
<template #footer>
<span class="dialog-footer"> <!-- 分页 -->
<div class="mobile-pagination" v-if="total > 0">
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
:page-sizes="[10, 20]"
layout="total, prev, pager, next"
:pager-count="5"
@pagination="getList"
/>
</div>
<!-- 筛选抽屉 -->
<el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="70%">
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
<el-form-item label="产品" prop="productId">
<el-select v-model="queryParams.productId" clearable filterable placeholder="请选择产品" style="width:100%">
<el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-select v-model="queryParams.customerId" clearable filterable placeholder="请选择客户" style="width:100%">
<el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="出库时间" prop="outTime">
<el-date-picker v-model="queryParams.outTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" style="width:100%" />
</el-form-item>
<el-form-item label="仓库" prop="warehouseId">
<el-select v-model="queryParams.warehouseId" clearable filterable placeholder="请选择仓库" style="width:100%">
<el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="出库状态" prop="status">
<el-select v-model="queryParams.status" clearable placeholder="请选择状态" style="width:100%">
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.ERP_SALE_OUT_STATUS)" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="收款状态" prop="receiptStatus">
<el-select v-model="queryParams.receiptStatus" clearable placeholder="请选择收款状态" style="width:100%">
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.ERP_RECEIPT_STATUS)" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="账户" prop="accountId">
<el-select v-model="queryParams.accountId" clearable filterable placeholder="请选择账户" style="width:100%">
<el-option v-for="item in accountList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="resetQuery">重置</el-button>
<el-button type="primary" @click="handleFilterConfirm">确认筛选</el-button>
</template>
</el-drawer>
<!-- 表单弹窗添加/修改 -->
<SaleOutwarehouseForm ref="formRef" @success="getList" />
<!-- 收款表单弹窗 -->
<el-dialog
v-model="receiptDialogVisible"
title="收款"
width="90%"
@closed="receiptDialogVisible = false"
>
<div v-if="currentOutwarehouse">
<div class="mobile-receipt-info">
<div class="mobile-receipt-info__row">
<span class="mobile-receipt-info__label">单号</span>
<span>{{ currentOutwarehouse.no }}</span>
</div>
<div class="mobile-receipt-info__row">
<span class="mobile-receipt-info__label">客户</span>
<span>{{ currentOutwarehouse.customerName }}</span>
</div>
<div class="mobile-receipt-info__row">
<span class="mobile-receipt-info__label">合计金额</span>
<span>{{ erpPriceTableColumnFormatter(null, null, currentOutwarehouse.totalPrice, null) }}</span>
</div>
<div class="mobile-receipt-info__row">
<span class="mobile-receipt-info__label">已收款</span>
<span>{{ erpPriceTableColumnFormatter(null, null, currentOutwarehouse.receiptPrice, null) }}</span>
</div>
<div class="mobile-receipt-info__row">
<span class="mobile-receipt-info__label">未收款</span>
<span class="mobile-receipt-info__danger">{{ erpPriceTableColumnFormatter(null, null, (currentOutwarehouse.totalPrice || 0) - (currentOutwarehouse.receiptPrice || 0), null) }}</span>
</div>
</div>
<el-form :model="receiptForm" label-position="top" style="margin-top: 12px">
<el-form-item label="收款金额" required>
<el-input-number
v-model="receiptForm.amount"
:min="0"
:precision="2"
:step="0.01"
:max="(currentOutwarehouse.totalPrice || 0) - (currentOutwarehouse.receiptPrice || 0)"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="收款日期" required>
<el-date-picker v-model="receiptForm.date" type="date" value-format="YYYY-MM-DD" style="width: 100%" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="receiptForm.remark" type="textarea" :rows="2" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div style="margin-top: 12px">
<div style="font-weight: 600; margin-bottom: 8px">收款记录</div>
<div v-if="receiptHistory.length > 0">
<div v-for="(record, idx) in receiptHistory" :key="idx" class="mobile-receipt-record">
<div class="mobile-receipt-record__row">
<span>{{ record.date }}</span>
<span class="mobile-receipt-record__amount">¥{{ erpPriceTableColumnFormatter(null, null, record.amount, null) }}</span>
</div>
<div class="mobile-receipt-record__detail" v-if="record.remark">{{ record.remark }}</div>
</div>
</div>
<div v-else style="text-align: center; padding: 16px; color: #909399;">暂无收款记录</div>
</div>
</div>
<template #footer>
<el-button @click="receiptDialogVisible = false">取消</el-button> <el-button @click="receiptDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitReceipt">确定</el-button> <el-button type="primary" @click="submitReceipt">确定</el-button>
</span> </template>
</template> </el-dialog>
</el-dialog> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Search, Filter, Plus } from '@element-plus/icons-vue'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { SaleOutwarehouseApi, SaleOutwarehouseVO, SaleOutwarehouseReceiptVO } from '@/api/erp/sale/outwarehouse' import { SaleOutwarehouseApi, SaleOutwarehouseVO, SaleOutwarehouseReceiptVO } from '@/api/erp/sale/outwarehouse'
import SaleOutwarehouseForm from './SaleOutwarehouseForm.vue' import SaleOutwarehouseForm from './SaleOutwarehouseForm.vue'
@@ -403,6 +253,7 @@ const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中 const loading = ref(true) // 列表的加载中
const list = ref<SaleOutwarehouseVO[]>([]) // 列表的数据 const list = ref<SaleOutwarehouseVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数 const total = ref(0) // 列表的总页数
const filterVisible = ref(false) // 筛选抽屉
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@@ -531,7 +382,13 @@ const handleQuery = () => {
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value?.resetFields()
handleQuery()
}
/** 筛选确认 */
const handleFilterConfirm = () => {
filterVisible.value = false
handleQuery() handleQuery()
} }
@@ -551,31 +408,15 @@ const openForm = (type: string, id?: number) => {
} }
} }
/** 卡片点击 */
/** 行点击操作 */ const handleCardClick = (row: SaleOutwarehouseVO) => {
const handleRowClick = (row: SaleOutwarehouseVO, column: any, event: MouseEvent) => {
// 检查是否点击了按钮、链接或其他交互元素
const target = event.target as HTMLElement
if (
target.tagName === 'BUTTON' ||
target.tagName === 'A' ||
target.tagName === 'I' ||
target.tagName === 'svg' ||
target.closest('button') ||
target.closest('a') ||
target.closest('.el-button') ||
target.closest('.el-checkbox')
) {
return
}
// 已审核打开详情页面,未审核打开编辑页面
if (row.status === 20) { if (row.status === 20) {
openForm('detail', row.id) openForm('detail', row.id)
} else if (row.status === 10) { } else if (row.status === 10) {
openForm('update', row.id) openForm('update', row.id)
} }
} }
/** 更新状态操作 */ /** 更新状态操作 */
const handleUpdateStatus = async (id: number, status: number) => { const handleUpdateStatus = async (id: number, status: number) => {
try { try {
@@ -731,3 +572,183 @@ onActivated(() => {
} }
}) })
</script> </script>
<style lang="scss" scoped>
.mobile-sale-outwarehouse {
padding: 12px;
background: #f5f5f5;
min-height: 100vh;
}
.mobile-header {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
&__search {
flex: 1;
}
&__actions {
display: flex;
gap: 4px;
flex-shrink: 0;
}
}
.mobile-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-empty {
padding: 40px 0;
}
.mobile-card {
background: #fff;
border-radius: 10px;
padding: 14px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
&__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
&__no {
font-weight: 600;
font-size: 15px;
color: #303133;
}
&__body {
font-size: 13px;
}
&__row {
display: flex;
justify-content: space-between;
padding: 3px 0;
}
&__label {
color: #909399;
flex-shrink: 0;
margin-right: 12px;
}
&__value {
color: #606266;
text-align: right;
&--ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200px;
}
}
&__nums {
display: flex;
justify-content: space-around;
margin-top: 10px;
padding: 10px 0;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
}
&__num-item {
text-align: center;
}
&__num-val {
font-size: 15px;
font-weight: 600;
color: #303133;
&--price {
color: #e6a23c;
}
&--danger {
color: #f56c6c;
}
}
&__num-label {
font-size: 11px;
color: #909399;
margin-top: 2px;
}
&__footer {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 10px;
}
}
.mobile-pagination {
margin-top: 12px;
display: flex;
justify-content: center;
:deep(.el-pagination) {
flex-wrap: wrap;
justify-content: center;
}
}
.mobile-receipt-info {
background: #f5f7fa;
border-radius: 8px;
padding: 12px;
&__row {
display: flex;
justify-content: space-between;
padding: 4px 0;
font-size: 13px;
}
&__label {
color: #909399;
}
&__danger {
color: #f56c6c;
font-weight: 600;
}
}
.mobile-receipt-record {
background: #f5f7fa;
border-radius: 6px;
padding: 10px;
margin-bottom: 8px;
&__row {
display: flex;
justify-content: space-between;
font-size: 13px;
}
&__amount {
font-weight: 600;
color: #67c23a;
}
&__detail {
font-size: 12px;
color: #909399;
margin-top: 4px;
}
}
</style>

View File

@@ -1,128 +1,81 @@
<template> <template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1080"> <el-drawer
<el-form v-model="dialogVisible"
ref="formRef" :title="dialogTitle"
:model="formData" direction="rtl"
:rules="formRules" size="100%"
label-width="100px" :close-on-press-escape="true"
v-loading="formLoading" :destroy-on-close="true"
:disabled="disabled" :append-to-body="true"
> class="mobile-form-drawer"
<el-row :gutter="20"> >
<el-col :span="8"> <div class="mobile-form" v-loading="formLoading">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-position="top"
:disabled="disabled"
>
<!-- 基本信息 -->
<div class="mobile-form__section">
<div class="mobile-form__section-title">基本信息</div>
<el-form-item label="计划编号" prop="no"> <el-form-item label="计划编号" prop="no">
<el-input disabled v-model="formData.no" placeholder="保存时自动生成" /> <el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="计划名称" prop="name"> <el-form-item label="计划名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入计划名称" /> <el-input v-model="formData.name" placeholder="请输入计划名称" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="客户" prop="customerId"> <el-form-item label="客户" prop="customerId">
<el-select <el-select v-model="formData.customerId" clearable filterable placeholder="请选择客户" style="width: 100%">
v-model="formData.customerId" <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择客户"
class="!w-1/1"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="目标金额" prop="targetAmount"> <el-form-item label="目标金额" prop="targetAmount">
<el-input-number <el-input-number v-model="formData.targetAmount" controls-position="right" :min="0" :precision="4" placeholder="请输入目标金额" style="width: 100%" />
v-model="formData.targetAmount"
controls-position="right"
:min="0"
:precision="4"
placeholder="请输入目标金额"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="开始时间" prop="startTime"> <el-form-item label="开始时间" prop="startTime">
<el-date-picker <el-date-picker v-model="formData.startTime" type="date" value-format="x" placeholder="选择开始时间" style="width: 100%" />
v-model="formData.startTime"
type="date"
value-format="x"
placeholder="选择开始时间"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结束时间" prop="endTime"> <el-form-item label="结束时间" prop="endTime">
<el-date-picker <el-date-picker v-model="formData.endTime" type="date" value-format="x" placeholder="选择结束时间" style="width: 100%" />
v-model="formData.endTime"
type="date"
value-format="x"
placeholder="选择结束时间"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="审批人" prop="approverId"> <el-form-item label="审批人" prop="approverId">
<el-select <el-select v-model="formData.approverId" clearable filterable placeholder="请选择审批人" style="width: 100%">
v-model="formData.approverId" <el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
clearable
filterable
placeholder="请选择审批人"
class="!w-1/1"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input <el-input type="textarea" v-model="formData.remark" :rows="2" placeholder="请输入备注" />
type="textarea"
v-model="formData.remark"
:rows="1"
placeholder="请输入备注"
/>
</el-form-item> </el-form-item>
</el-col> </div>
</el-row>
<!-- 子表的表单 --> <!-- 计划产品明细 -->
<ContentWrap> <div class="mobile-form__section">
<el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> <div class="mobile-form__section-title">计划产品明细</div>
<el-tab-pane label="计划产品明细" name="item"> <SalePlanItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" />
<SalePlanItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> </div>
</el-tab-pane>
</el-tabs> <!-- 合计 -->
</ContentWrap> <div class="mobile-form__section">
<el-row :gutter="20"> <div class="mobile-form__section-title">合计信息</div>
<el-col :span="8">
<el-form-item label="合计金额"> <el-form-item label="合计金额">
<el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" />
</el-form-item> </el-form-item>
</el-col> </div>
</el-row> </el-form>
</el-form> </div>
<!-- 底部按钮 -->
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> <div class="mobile-form__footer">
<el-button @click="dialogVisible = false" style="flex:1"> </el-button>
</el-button> <el-button type="primary" @click="submitForm" :disabled="formLoading" v-if="!disabled" style="flex:2">
<el-button @click="dialogVisible = false"> </el-button>
</el-button>
</div>
</template> </template>
</Dialog> </el-drawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { SalePlanApi, SalePlanVO } from '@/api/erp/sale/plan' import { SalePlanApi, SalePlanVO } from '@/api/erp/sale/plan'
@@ -253,3 +206,31 @@ const resetForm = () => {
formRef.value?.resetFields() formRef.value?.resetFields()
} }
</script> </script>
<style lang="scss" scoped>
.mobile-form {
padding: 12px;
}
.mobile-form__section {
background: #fff;
border-radius: 8px;
padding: 14px;
margin-bottom: 12px;
}
.mobile-form__section-title {
font-size: 15px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
}
.mobile-form__footer {
display: flex;
gap: 12px;
padding: 0 12px;
}
</style>

View File

@@ -4,21 +4,42 @@
:model="formData" :model="formData"
:rules="formRules" :rules="formRules"
v-loading="formLoading" v-loading="formLoading"
label-width="0px" label-position="top"
:inline-message="true" :inline-message="true"
:disabled="disabled" :disabled="disabled"
> >
<el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> <div class="mobile-item-list">
<el-table-column label="序号" type="index" align="center" width="60" /> <div
<el-table-column label="产品名称" min-width="180"> v-for="(row, $index) in formData"
<template #default="{ row, $index }"> :key="$index"
<el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!"> class="mobile-item-card"
>
<div class="mobile-item-card__header">
<span class="mobile-item-card__index">#{{ $index + 1 }}</span>
<span class="mobile-item-card__name">{{ row.productName || '未选择产品' }}</span>
<el-button
:disabled="disabled || formData.length === 1"
@click="handleDelete($index)"
link
type="danger"
size="small"
>
删除
</el-button>
</div>
<div class="mobile-item-card__body">
<el-form-item
label="产品"
:prop="`${$index}.productId`"
:rules="formRules.productId"
>
<el-select <el-select
v-model="row.productId" v-model="row.productId"
clearable clearable
filterable filterable
@change="onChangeProduct($event, row)" @change="onChangeProduct($event, row)"
placeholder="请选择产品" placeholder="请选择产品"
style="width: 100%"
> >
<el-option <el-option
v-for="item in productList" v-for="item in productList"
@@ -28,69 +49,58 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> <div class="mobile-item-card__info-row">
</el-table-column> <span class="mobile-item-card__info-label">单位</span>
<el-table-column label="单位" min-width="80"> <span class="mobile-item-card__info-value">{{ row.productUnitName || '-' }}</span>
<template #default="{ row }"> </div>
<el-form-item class="mb-0px!"> <div class="mobile-item-card__input-group">
<el-input disabled v-model="row.productUnitName" /> <el-form-item label="计划销量" :prop="`${$index}.planCount`" :rules="formRules.planCount">
</el-form-item> <el-input-number
</template> v-model="row.planCount"
</el-table-column> controls-position="right"
<el-table-column label="计划销量" prop="planCount" fixed="right" min-width="140"> :min="0"
<template #default="{ row, $index }"> :precision="4"
<el-form-item :prop="`${$index}.planCount`" :rules="formRules.planCount" class="mb-0px!"> style="width: 100%"
<el-input-number />
v-model="row.planCount" </el-form-item>
controls-position="right" <el-form-item label="单价" :prop="`${$index}.productPrice`" :rules="formRules.productPrice">
:min="0" <el-input-number
:precision="4" v-model="row.productPrice"
class="!w-100%" controls-position="right"
/> :min="0"
</el-form-item> :precision="4"
</template> style="width: 100%"
</el-table-column> />
<el-table-column label="单价" fixed="right" min-width="120"> </el-form-item>
<template #default="{ row, $index }"> </div>
<el-form-item :prop="`${$index}.productPrice`" :rules="formRules.productPrice" class="mb-0px!"> <div class="mobile-item-card__info-row">
<el-input-number <span class="mobile-item-card__info-label">金额</span>
v-model="row.productPrice" <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.totalPrice) }}</span>
controls-position="right" </div>
:min="0" <el-form-item label="备注" :prop="`${$index}.remark`">
:precision="4"
class="!w-100%"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="金额" prop="totalPrice" fixed="right" min-width="120">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!">
<el-input
disabled
v-model="row.totalPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="备注" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.remark`" class="mb-0px!">
<el-input v-model="row.remark" placeholder="请输入备注" /> <el-input v-model="row.remark" placeholder="请输入备注" />
</el-form-item> </el-form-item>
</template> </div>
</el-table-column> </div>
<el-table-column align="center" fixed="right" label="操作" width="60">
<template #default="{ $index }"> <!-- 合计 -->
<el-button @click="handleDelete($index)" link></el-button> <div class="mobile-item-summary" v-if="formData.length > 0">
</template> <div class="mobile-item-summary__row">
</el-table-column> <span>合计数量</span>
</el-table> <span>{{ erpPriceInputFormatter(summaryData.planCount) }}</span>
</div>
<div class="mobile-item-summary__row mobile-item-summary__row--total">
<span>合计金额</span>
<span>{{ erpPriceInputFormatter(summaryData.totalPrice) }}</span>
</div>
</div>
<!-- 添加按钮 -->
<div class="mobile-item-add" v-if="!disabled">
<el-button @click="handleAdd" round>+ 添加计划产品</el-button>
</div>
</div>
</el-form> </el-form>
<el-row justify="center" class="mt-3" v-if="!disabled">
<el-button @click="handleAdd" round>+ 添加计划产品</el-button>
</el-row>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ProductApi, ProductVO } from '@/api/erp/product/product' import { ProductApi, ProductVO } from '@/api/erp/product/product'
@@ -139,24 +149,12 @@ watch(
) )
/** 合计 */ /** 合计 */
const getSummaries = (param: SummaryMethodProps) => { const summaryData = computed(() => {
const { columns, data } = param return {
const sums: string[] = [] planCount: getSumValue(formData.value.map((item) => Number(item.planCount))),
columns.forEach((column, index: number) => { totalPrice: getSumValue(formData.value.map((item) => Number(item.totalPrice)))
if (index === 0) { }
sums[index] = '合计' })
return
}
if (['planCount', 'totalPrice'].includes(column.property)) {
const sum = getSumValue(data.map((item) => Number(item[column.property])))
sums[index] = erpPriceInputFormatter(sum)
} else {
sums[index] = ''
}
})
return sums
}
/** 新增按钮操作 */ /** 新增按钮操作 */
const handleAdd = () => { const handleAdd = () => {
@@ -181,6 +179,7 @@ const handleDelete = (index: number) => {
const onChangeProduct = (productId, row) => { const onChangeProduct = (productId, row) => {
const product = productList.value.find((item) => item.id === productId) const product = productList.value.find((item) => item.id === productId)
if (product) { if (product) {
row.productName = product.name
row.productUnitName = product.unitName row.productUnitName = product.unitName
row.productPrice = product.salePrice row.productPrice = product.salePrice
} }
@@ -201,3 +200,86 @@ onMounted(async () => {
} }
}) })
</script> </script>
<style lang="scss" scoped>
.mobile-item-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-item-card {
background: #f9fafb;
border-radius: 8px;
border: 1px solid #ebeef5;
overflow: hidden;
&__header {
display: flex;
align-items: center;
padding: 10px 12px;
background: #f0f2f5;
gap: 8px;
}
&__index {
font-size: 13px;
font-weight: 600;
color: #409eff;
flex-shrink: 0;
}
&__name {
flex: 1;
font-size: 14px;
font-weight: 500;
color: #303133;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__body {
padding: 10px 12px;
}
&__info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 4px 0;
font-size: 13px;
}
&__info-label {
color: #909399;
flex-shrink: 0;
}
&__info-value {
color: #606266;
text-align: right;
}
&__input-group {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
}
.mobile-item-summary {
background: #fff;
border-radius: 8px;
border: 1px solid #ebeef5;
padding: 10px 12px;
&__row {
display: flex;
justify-content: space-between;
padding: 4px 0;
font-size: 13px;
color: #606266;
&--total {
font-weight: 600;
color: #303133;
border-top: 1px solid #ebeef5;
padding-top: 8px;
margin-top: 4px;
}
}
}
.mobile-item-add {
text-align: center;
padding: 8px 0;
}
</style>

View File

@@ -1,295 +1,168 @@
<template> <template>
<ContentWrap> <div class="mobile-sale-plan">
<!-- 搜索工作栏 --> <!-- 顶部操作栏 -->
<el-form <div class="mobile-header">
class="-mb-15px" <div class="mobile-header__search">
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="计划编号" prop="no">
<el-input <el-input
v-model="queryParams.no" v-model="queryParams.no"
placeholder="请输入计划编号" placeholder="搜索计划编号"
clearable clearable
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
class="!w-240px" :prefix-icon="Search"
/> />
</el-form-item> </div>
<el-form-item label="计划名称" prop="name"> <div class="mobile-header__actions">
<el-input <el-button :icon="Filter" circle @click="filterVisible = true" />
v-model="queryParams.name"
placeholder="请输入计划名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-select
v-model="queryParams.customerId"
clearable
filterable
placeholder="请选择客户"
class="!w-240px"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable class="!w-240px">
<el-option label="草稿" :value="10" />
<el-option label="已审核" :value="20" />
<!-- <el-option label="已批准" :value="30" />-->
<el-option label="已驳回" :value="40" />
</el-select>
</el-form-item>
<el-form-item label="计划时间" prop="planTime">
<el-date-picker
v-model="queryParams.planTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="创建人" prop="creator">
<el-select
v-model="queryParams.creator"
clearable
filterable
placeholder="请选择创建人"
class="!w-240px"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button <el-button
type="primary" type="primary"
plain :icon="Plus"
circle
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['erp:sale-plan:create']" v-hasPermi="['erp:sale-plan:create']"
> />
<Icon icon="ep:plus" class="mr-5px" /> 新增 </div>
</el-button> </div>
<el-button
type="success" <!-- 卡片列表 -->
plain <div class="mobile-list" v-loading="loading">
@click="handleExport" <div v-if="list.length === 0 && !loading" class="mobile-empty">
:loading="exportLoading" <el-empty description="暂无销售计划" />
v-hasPermi="['erp:sale-plan:export']" </div>
> <div
<Icon icon="ep:download" class="mr-5px" /> 导出 v-for="item in list"
</el-button> :key="item.id"
<el-button class="mobile-card"
type="danger" @click="openForm('detail', item.id)"
plain >
@click="handleDelete(selectionList.map((item) => item.id))" <div class="mobile-card__header">
v-hasPermi="['erp:sale-plan:delete']" <span class="mobile-card__no">{{ item.no }}</span>
:disabled="selectionList.length === 0" <span>
> <el-tag v-if="item.status === 10" type="info" size="small">草稿</el-tag>
<Icon icon="ep:delete" class="mr-5px" /> 删除 <el-tag v-else-if="item.status === 20" type="warning" size="small">已审核</el-tag>
</el-button> <el-tag v-else-if="item.status === 40" type="danger" size="small">已驳回</el-tag>
</el-form-item> </span>
</el-form> </div>
</ContentWrap> <div class="mobile-card__body">
<div class="mobile-card__row">
<span class="mobile-card__label">计划名称</span>
<span class="mobile-card__value">{{ item.name || '-' }}</span>
</div>
<div class="mobile-card__row">
<span class="mobile-card__label">客户</span>
<span class="mobile-card__value">{{ item.customerName || '-' }}</span>
</div>
<div class="mobile-card__row">
<span class="mobile-card__label">时间</span>
<span class="mobile-card__value">{{ formatDate2Fn(item.startTime) }} ~ {{ formatDate2Fn(item.endTime) }}</span>
</div>
<div class="mobile-card__row">
<span class="mobile-card__label">完成状态</span>
<span>
<el-tag v-if="item.completionStatus === 0" type="info" size="small">未开始</el-tag>
<el-tag v-else-if="item.completionStatus === 1" type="warning" size="small">进行中</el-tag>
<el-tag v-else-if="item.completionStatus === 2" type="success" size="small">已完成</el-tag>
<el-tag v-else-if="item.completionStatus === 3" type="danger" size="small">已超期</el-tag>
</span>
</div>
<div class="mobile-card__progress">
<div class="mobile-card__row">
<span class="mobile-card__label">进度</span>
<span class="mobile-card__value">{{ item.progress || 0 }}%</span>
</div>
<el-progress :percentage="item.progress || 0" :status="item.progress >= 100 ? 'success' : ''" :stroke-width="6" />
</div>
<div class="mobile-card__nums">
<div class="mobile-card__num-item">
<div class="mobile-card__num-val mobile-card__num-val--price">¥{{ erpPriceInputFormatter(item.targetAmount) }}</div>
<div class="mobile-card__num-label">目标金额</div>
</div>
<div class="mobile-card__num-item">
<div class="mobile-card__num-val">¥{{ erpPriceInputFormatter(item.completedAmount) }}</div>
<div class="mobile-card__num-label">已完成</div>
</div>
</div>
</div>
<div class="mobile-card__footer">
<el-button size="small" @click.stop="openForm('detail', item.id)" v-hasPermi="['erp:sale-plan:query']">详情</el-button>
<el-button size="small" type="primary" @click.stop="openForm('update', item.id)" v-hasPermi="['erp:sale-plan:update']" :disabled="item.status === 30">编辑</el-button>
<el-button size="small" type="success" @click.stop="handleApprove(item.id)" v-hasPermi="['erp:sale-plan:update-status']" v-if="item.status === 10">审核</el-button>
<el-button size="small" type="success" @click.stop="handleSubmitApproval(item.id)" v-hasPermi="['erp:sale-plan:submit-approval']" v-if="item.status === 10 && !item.hasApprovalRecords">提交审批</el-button>
<el-button size="small" type="info" @click.stop="handleViewApproval(item.id)" v-hasPermi="['erp:sale-plan:query-approval']" v-if="item.hasApprovalRecords">审批记录</el-button>
<el-button size="small" type="primary" @click.stop="handleProcessApproval(item.id)" v-hasPermi="['erp:approval-record:process']" v-if="item.hasApprovalRecords && item.status !== 20">处理审批</el-button>
<el-button size="small" type="danger" @click.stop="handleDelete([item.id])" v-hasPermi="['erp:sale-plan:delete']">删除</el-button>
</div>
</div>
</div>
<!-- 列表 -->
<ContentWrap>
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
@selection-change="handleSelectionChange"
>
<el-table-column width="30" label="选择" type="selection" />
<el-table-column min-width="180" label="计划编号" align="center" prop="no" />
<el-table-column label="计划名称" align="center" prop="name" min-width="150" />
<el-table-column label="客户" align="center" prop="customerName" min-width="120" />
<el-table-column
label="目标金额"
align="center"
prop="targetAmount"
:formatter="erpPriceTableColumnFormatter"
min-width="120"
/>
<el-table-column
label="已完成总额"
align="center"
prop="completedAmount"
:formatter="erpPriceTableColumnFormatter"
min-width="120"
/>
<el-table-column label="进度" align="center" prop="progress" min-width="120">
<template #default="scope">
<el-progress
:percentage="scope.row.progress || 0"
:status="scope.row.progress >= 100 ? 'success' : ''"
/>
</template>
</el-table-column>
<el-table-column label="完成状态" align="center" prop="completionStatus" min-width="100">
<template #default="scope">
<el-tag v-if="scope.row.completionStatus === 0" type="info">未开始</el-tag>
<el-tag v-else-if="scope.row.completionStatus === 1" type="warning">进行中</el-tag>
<el-tag v-else-if="scope.row.completionStatus === 2" type="success">已完成</el-tag>
<el-tag v-else-if="scope.row.completionStatus === 3" type="danger">已超期</el-tag>
</template>
</el-table-column>
<el-table-column
label="开始时间"
align="center"
prop="startTime"
:formatter="dateFormatter2"
width="120px"
/>
<el-table-column
label="结束时间"
align="center"
prop="endTime"
:formatter="dateFormatter2"
width="120px"
/>
<el-table-column label="审批人" align="center" prop="approverName" min-width="100" />
<el-table-column label="创建人" align="center" prop="creatorName" min-width="100" />
<el-table-column label="状态" align="center" width="90" prop="status">
<template #default="scope">
<el-tag v-if="scope.row.status === 10" type="info">草稿</el-tag>
<el-tag v-else-if="scope.row.status === 20" type="warning">已审核</el-tag>
<!-- <el-tag v-else-if="scope.row.status === 30" type="success">已批准</el-tag>-->
<el-tag v-else-if="scope.row.status === 40" type="danger">已驳回</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" width="380">
<template #default="scope">
<el-button
link
@click="openForm('detail', scope.row.id)"
v-hasPermi="['erp:sale-plan:query']"
>
详情
</el-button>
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['erp:sale-plan:update']"
:disabled="scope.row.status === 30"
>
编辑
</el-button>
<!-- <el-button-->
<!-- link-->
<!-- type="warning"-->
<!-- @click="handleSubmit(scope.row.id)"-->
<!-- v-hasPermi="['erp:sale-plan:update-status']"-->
<!-- v-if="scope.row.status === 10"-->
<!-- >-->
<!-- 提交-->
<!-- </el-button>-->
<el-button
link
type="success"
@click="handleApprove(scope.row.id)"
v-hasPermi="['erp:sale-plan:update-status']"
v-if="scope.row.status === 10"
>
审核
</el-button>
<el-button
link
type="success"
@click="handleSubmitApproval(scope.row.id)"
v-hasPermi="['erp:sale-plan:submit-approval']"
v-if="scope.row.status === 10 && !scope.row.hasApprovalRecords"
>
提交审批
</el-button>
<el-button
link
type="info"
@click="handleViewApproval(scope.row.id)"
v-hasPermi="['erp:sale-plan:query-approval']"
v-if="scope.row.hasApprovalRecords"
>
审批记录
</el-button>
<el-button
link
type="primary"
@click="handleProcessApproval(scope.row.id)"
v-hasPermi="['erp:approval-record:process']"
v-if="scope.row.hasApprovalRecords && scope.row.status !== 20"
>
处理审批
</el-button>
<!-- <el-button-->
<!-- link-->
<!-- type="danger"-->
<!-- @click="handleReject(scope.row.id)"-->
<!-- v-hasPermi="['erp:sale-plan:update-status']"-->
<!-- v-if="scope.row.status === 20"-->
<!-- >-->
<!-- 驳回-->
<!-- </el-button>-->
<el-button
link
type="danger"
@click="handleDelete([scope.row.id])"
v-hasPermi="['erp:sale-plan:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 --> <!-- 分页 -->
<Pagination <div class="mobile-pagination" v-if="total > 0">
:total="total" <Pagination
v-model:page="queryParams.pageNo" :total="total"
v-model:limit="queryParams.pageSize" v-model:page="queryParams.pageNo"
@pagination="getList" v-model:limit="queryParams.pageSize"
/> :page-sizes="[10, 20]"
</ContentWrap> layout="total, prev, pager, next"
:pager-count="5"
@pagination="getList"
/>
</div>
<!-- 表单弹窗添加/修改 --> <!-- 筛选抽屉 -->
<SalePlanForm ref="formRef" @success="getList" /> <el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="70%">
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
<el-form-item label="计划名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入计划名称" clearable />
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-select v-model="queryParams.customerId" clearable filterable placeholder="请选择客户" style="width:100%">
<el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width:100%">
<el-option label="草稿" :value="10" />
<el-option label="已审核" :value="20" />
<el-option label="已驳回" :value="40" />
</el-select>
</el-form-item>
<el-form-item label="计划时间" prop="planTime">
<el-date-picker v-model="queryParams.planTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" style="width:100%" />
</el-form-item>
<el-form-item label="创建人" prop="creator">
<el-select v-model="queryParams.creator" clearable filterable placeholder="请选择创建人" style="width:100%">
<el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="resetQuery">重置</el-button>
<el-button type="primary" @click="handleFilterConfirm">确认筛选</el-button>
</template>
</el-drawer>
<!-- 提交审批对话框 --> <!-- 表单弹窗添加/修改 -->
<SubmitApprovalDialog ref="submitApprovalDialogRef" @success="getList" /> <SalePlanForm ref="formRef" @success="getList" />
<!-- 审批记录对话框 --> <!-- 提交审批对话框 -->
<ApprovalRecordsDialog ref="approvalDialogRef" /> <SubmitApprovalDialog ref="submitApprovalDialogRef" @success="getList" />
<!-- 处理审批对话框 --> <!-- 审批记录对话框 -->
<ProcessApprovalDialog ref="processApprovalDialogRef" @success="getList" /> <ApprovalRecordsDialog ref="approvalDialogRef" />
<!-- 处理审批对话框 -->
<ProcessApprovalDialog ref="processApprovalDialogRef" @success="getList" />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { dateFormatter2 } from '@/utils/formatTime' import { Search, Filter, Plus } from '@element-plus/icons-vue'
import { formatDate } from '@/utils/formatTime'
import download from '@/utils/download' import download from '@/utils/download'
import { SalePlanApi, SalePlanVO } from '@/api/erp/sale/plan' import { SalePlanApi, SalePlanVO } from '@/api/erp/sale/plan'
import SalePlanForm from './SalePlanForm.vue' import SalePlanForm from './SalePlanForm.vue'
import { UserVO } from '@/api/system/user' import { UserVO } from '@/api/system/user'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
import { erpPriceTableColumnFormatter } from '@/utils' import { erpPriceInputFormatter } from '@/utils'
import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer'
import { SubmitApprovalDialog, ApprovalRecordsDialog, ProcessApprovalDialog } from '@/components/Approval' import { SubmitApprovalDialog, ApprovalRecordsDialog, ProcessApprovalDialog } from '@/components/Approval'
import { ApprovalRecordApi, ApprovalRecordVO } from '@/api/erp/approval/index' import { ApprovalRecordApi, ApprovalRecordVO } from '@/api/erp/approval/index'
@@ -303,6 +176,12 @@ const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中 const loading = ref(true) // 列表的加载中
const list = ref<SalePlanVO[]>([]) // 列表的数据 const list = ref<SalePlanVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数 const total = ref(0) // 列表的总页数
const filterVisible = ref(false) // 筛选抽屉
const formatDate2Fn = (date: any) => {
if (!date) return '-'
return formatDate(new Date(date), 'YYYY-MM-DD')
}
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@@ -358,7 +237,13 @@ const handleQuery = () => {
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value?.resetFields()
handleQuery()
}
/** 筛选确认 */
const handleFilterConfirm = () => {
filterVisible.value = false
handleQuery() handleQuery()
} }
@@ -378,7 +263,6 @@ const handleDelete = async (ids: number[]) => {
message.success(t('common.delSuccess')) message.success(t('common.delSuccess'))
// 刷新列表 // 刷新列表
await getList() await getList()
selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id))
} catch {} } catch {}
} }
@@ -444,12 +328,6 @@ const handleExport = async () => {
} }
} }
/** 选中操作 */
const selectionList = ref<SalePlanVO[]>([])
const handleSelectionChange = (rows: SalePlanVO[]) => {
selectionList.value = rows
}
/** 初始化 **/ /** 初始化 **/
onMounted(async () => { onMounted(async () => {
await getList() await getList()
@@ -458,3 +336,130 @@ onMounted(async () => {
userList.value = await UserApi.getSimpleUserList() userList.value = await UserApi.getSimpleUserList()
}) })
</script> </script>
<style lang="scss" scoped>
.mobile-sale-plan {
padding: 12px;
background: #f5f5f5;
min-height: 100vh;
}
.mobile-header {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
&__search {
flex: 1;
}
&__actions {
display: flex;
gap: 4px;
flex-shrink: 0;
}
}
.mobile-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-empty {
padding: 40px 0;
}
.mobile-card {
background: #fff;
border-radius: 10px;
padding: 14px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
&__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
&__no {
font-weight: 600;
font-size: 15px;
color: #303133;
}
&__body {
font-size: 13px;
}
&__row {
display: flex;
justify-content: space-between;
padding: 3px 0;
}
&__label {
color: #909399;
flex-shrink: 0;
margin-right: 12px;
}
&__value {
color: #606266;
text-align: right;
}
&__progress {
margin-top: 6px;
}
&__nums {
display: flex;
justify-content: space-around;
margin-top: 10px;
padding: 10px 0;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
}
&__num-item {
text-align: center;
}
&__num-val {
font-size: 15px;
font-weight: 600;
color: #303133;
&--price {
color: #e6a23c;
}
}
&__num-label {
font-size: 11px;
color: #909399;
margin-top: 2px;
}
&__footer {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 10px;
}
}
.mobile-pagination {
margin-top: 12px;
display: flex;
justify-content: center;
:deep(.el-pagination) {
flex-wrap: wrap;
justify-content: center;
}
}
</style>

View File

@@ -1,40 +1,35 @@
<template> <template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1440"> <el-drawer
<el-form v-model="dialogVisible"
ref="formRef" :title="dialogTitle"
:model="formData" direction="rtl"
:rules="formRules" size="100%"
label-width="100px" :close-on-press-escape="true"
v-loading="formLoading" :destroy-on-close="true"
:disabled="disabled" :append-to-body="true"
> class="mobile-form-drawer"
<el-row :gutter="20"> >
<el-col :span="8"> <div class="mobile-form" v-loading="formLoading">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-position="top"
:disabled="disabled"
>
<!-- 基本信息 -->
<div class="mobile-form__section">
<div class="mobile-form__section-title">基本信息</div>
<el-form-item label="退货单号" prop="no"> <el-form-item label="退货单号" prop="no">
<el-input disabled v-model="formData.no" placeholder="保存时自动生成" /> <el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="退货时间" prop="returnTime"> <el-form-item label="退货时间" prop="returnTime">
<el-date-picker <el-date-picker v-model="formData.returnTime" type="date" value-format="x" placeholder="选择退货时间" style="width: 100%" />
v-model="formData.returnTime"
type="date"
value-format="x"
placeholder="选择退货时间"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="关联订单" prop="orderNo"> <el-form-item label="关联订单" prop="orderNo">
<el-input readonly> <el-input readonly>
<template #prefix> <template #prefix>
<el-link <el-link v-if="formData.orderId" type="primary" @click.stop="openSaleOrderDetail" :underline="false">
v-if="formData.orderId"
type="primary"
@click.stop="openSaleOrderDetail"
:underline="false"
>
{{ formData.orderNo }} {{ formData.orderNo }}
</el-link> </el-link>
</template> </template>
@@ -45,143 +40,67 @@
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="客户" prop="customerId"> <el-form-item label="客户" prop="customerId">
<el-select <el-select v-model="formData.customerId" clearable filterable disabled placeholder="请选择客户" style="width: 100%">
v-model="formData.customerId" <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
disabled
placeholder="请选择客户"
class="!w-1/1"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="销售人员" prop="saleUserId"> <el-form-item label="销售人员" prop="saleUserId">
<el-select <el-select v-model="formData.saleUserId" clearable filterable placeholder="请选择销售人员" style="width: 100%">
v-model="formData.saleUserId" <el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
clearable
filterable
placeholder="请选择销售人员"
class="!w-1/1"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input <el-input type="textarea" v-model="formData.remark" :rows="2" placeholder="请输入备注" />
type="textarea"
v-model="formData.remark"
:rows="1"
placeholder="请输入备注"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="附件" prop="fileUrl"> <el-form-item label="附件" prop="fileUrl">
<UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" /> <UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" />
</el-form-item> </el-form-item>
</el-col> </div>
</el-row>
<!-- 子表的表 --> <!-- 退货产品清 -->
<ContentWrap> <div class="mobile-form__section">
<el-tabs v-model="subTabsName" class="-mt-15px -mb-10px"> <div class="mobile-form__section-title">退货产品清单</div>
<el-tab-pane label="退货产品清单" name="item"> <SaleReturnItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" />
<SaleReturnItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" /> </div>
</el-tab-pane>
</el-tabs> <!-- 价格信息 -->
</ContentWrap> <div class="mobile-form__section">
<el-row :gutter="20"> <div class="mobile-form__section-title">价格信息</div>
<el-col :span="8">
<el-form-item label="优惠率(%" prop="discountPercent"> <el-form-item label="优惠率(%" prop="discountPercent">
<el-input-number <el-input-number v-model="formData.discountPercent" controls-position="right" :min="0" :precision="4" placeholder="请输入优惠率" style="width: 100%" />
v-model="formData.discountPercent"
controls-position="right"
:min="0"
:precision="4"
placeholder="请输入优惠率"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="退款优惠" prop="discountPrice"> <el-form-item label="退款优惠" prop="discountPrice">
<el-input <el-input disabled v-model="formData.discountPrice" :formatter="erpPriceInputFormatter" />
disabled
v-model="formData.discountPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="优惠后金额"> <el-form-item label="优惠后金额">
<el-input <el-input disabled :model-value="formData.totalPrice - formData.otherPrice" :formatter="erpPriceInputFormatter" />
disabled
:model-value="formData.totalPrice - formData.otherPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="其它费用" prop="otherPrice"> <el-form-item label="其它费用" prop="otherPrice">
<el-input-number <el-input-number v-model="formData.otherPrice" controls-position="right" :min="0" :precision="4" placeholder="请输入其它费用" style="width: 100%" />
v-model="formData.otherPrice"
controls-position="right"
:min="0"
:precision="4"
placeholder="请输入其它费用"
class="!w-1/1"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结算账户" prop="accountId"> <el-form-item label="结算账户" prop="accountId">
<el-select <el-select v-model="formData.accountId" clearable filterable placeholder="请选择结算账户" style="width: 100%">
v-model="formData.accountId" <el-option v-for="item in accountList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择结算账户"
class="!w-1/1"
>
<el-option
v-for="item in accountList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="应退金额" prop="totalPrice"> <el-form-item label="应退金额" prop="totalPrice">
<el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" /> <el-input disabled v-model="formData.totalPrice" :formatter="erpPriceInputFormatter" />
</el-form-item> </el-form-item>
</el-col> </div>
</el-row> </el-form>
</el-form> </div>
<!-- 底部按钮 -->
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled"> <div class="mobile-form__footer">
<el-button @click="dialogVisible = false" style="flex:1"> </el-button>
</el-button> <el-button type="primary" @click="submitForm" :disabled="formLoading" v-if="!disabled" style="flex:2">
<el-button @click="dialogVisible = false"> </el-button>
</el-button>
</div>
</template> </template>
</Dialog> </el-drawer>
<!-- 可退货的订单列表 --> <!-- 可退货的订单列表 -->
<SaleOrderReturnEnableList ref="saleOrderReturnEnableListRef" @success="handleSaleOrderChange" /> <SaleOrderReturnEnableList ref="saleOrderReturnEnableListRef" @success="handleSaleOrderChange" />
@@ -361,3 +280,31 @@ const resetForm = () => {
formRef.value?.resetFields() formRef.value?.resetFields()
} }
</script> </script>
<style lang="scss" scoped>
.mobile-form {
padding: 12px;
}
.mobile-form__section {
background: #fff;
border-radius: 8px;
padding: 14px;
margin-bottom: 12px;
}
.mobile-form__section-title {
font-size: 15px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
}
.mobile-form__footer {
display: flex;
gap: 12px;
padding: 0 12px;
}
</style>

View File

@@ -4,18 +4,34 @@
:model="formData" :model="formData"
:rules="formRules" :rules="formRules"
v-loading="formLoading" v-loading="formLoading"
label-width="0px" label-position="top"
:inline-message="true" :inline-message="true"
:disabled="disabled" :disabled="disabled"
> >
<el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px"> <div class="mobile-item-list">
<el-table-column label="序号" type="index" align="center" width="60" /> <div
<el-table-column label="仓库名称" min-width="125"> v-for="(row, $index) in formData"
<template #default="{ row, $index }"> :key="$index"
class="mobile-item-card"
>
<div class="mobile-item-card__header">
<span class="mobile-item-card__index">#{{ $index + 1 }}</span>
<span class="mobile-item-card__name">{{ row.productName || '未选择产品' }}</span>
<el-button
:disabled="disabled || formData.length === 1"
@click="handleDelete($index)"
link
type="danger"
size="small"
>
删除
</el-button>
</div>
<div class="mobile-item-card__body">
<el-form-item <el-form-item
label="仓库"
:prop="`${$index}.warehouseId`" :prop="`${$index}.warehouseId`"
:rules="formRules.warehouseId" :rules="formRules.warehouseId"
class="mb-0px!"
> >
<el-select <el-select
v-model="row.warehouseId" v-model="row.warehouseId"
@@ -23,6 +39,7 @@
filterable filterable
placeholder="请选择仓库" placeholder="请选择仓库"
@change="onChangeWarehouse($event, row)" @change="onChangeWarehouse($event, row)"
style="width: 100%"
> >
<el-option <el-option
v-for="item in warehouseList" v-for="item in warehouseList"
@@ -32,141 +49,89 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> <div class="mobile-item-card__info-row">
</el-table-column> <span class="mobile-item-card__info-label">库存</span>
<el-table-column label="产品名称" min-width="180"> <span class="mobile-item-card__info-value">{{ erpCountInputFormatter(row.stockCount) }}</span>
<template #default="{ row }"> </div>
<el-form-item class="mb-0px!"> <div class="mobile-item-card__info-row">
<el-input disabled v-model="row.productName" /> <span class="mobile-item-card__info-label">条码</span>
</el-form-item> <span class="mobile-item-card__info-value">{{ row.productBarCode || '-' }}</span>
</template> </div>
</el-table-column> <div class="mobile-item-card__info-row">
<el-table-column label="库存" min-width="100"> <span class="mobile-item-card__info-label">单位</span>
<template #default="{ row }"> <span class="mobile-item-card__info-value">{{ row.productUnitName || '-' }}</span>
<el-form-item class="mb-0px!"> </div>
<el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" /> <div class="mobile-item-card__info-row" v-if="row.outCount != null">
</el-form-item> <span class="mobile-item-card__info-label">已出库</span>
</template> <span class="mobile-item-card__info-value">{{ erpCountInputFormatter(row.outCount) }}</span>
</el-table-column> </div>
<el-table-column label="条码" min-width="150"> <div class="mobile-item-card__info-row" v-if="row.returnCount != null">
<template #default="{ row }"> <span class="mobile-item-card__info-label">已退货</span>
<el-form-item class="mb-0px!"> <span class="mobile-item-card__info-value">{{ erpCountInputFormatter(row.returnCount) }}</span>
<el-input disabled v-model="row.productBarCode" /> </div>
</el-form-item> <div class="mobile-item-card__input-group">
</template> <el-form-item label="数量" :prop="`${$index}.count`" :rules="formRules.count">
</el-table-column> <el-input-number
<el-table-column label="单位" min-width="80"> v-model="row.count"
<template #default="{ row }"> controls-position="right"
<el-form-item class="mb-0px!"> :min="0.0001"
<el-input disabled v-model="row.productUnitName" /> :precision="4"
</el-form-item> style="width: 100%"
</template> />
</el-table-column> </el-form-item>
<el-table-column <el-form-item label="产品单价" :prop="`${$index}.productPrice`">
label="已出库" <el-input-number
fixed="right" v-model="row.productPrice"
min-width="80" controls-position="right"
v-if="formData[0]?.outCount != null" :min="0.0001"
> :precision="4"
<template #default="{ row }"> style="width: 100%"
<el-form-item class="mb-0px!"> />
<el-input disabled v-model="row.outCount" :formatter="erpCountInputFormatter" /> </el-form-item>
</el-form-item> </div>
</template> <div class="mobile-item-card__info-row">
</el-table-column> <span class="mobile-item-card__info-label">金额</span>
<el-table-column <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.totalProductPrice) }}</span>
label="已退货" </div>
fixed="right" <el-form-item label="税率(%" :prop="`${$index}.taxPercent`">
min-width="80"
v-if="formData[0]?.returnCount != null"
>
<template #default="{ row }">
<el-form-item class="mb-0px!">
<el-input disabled v-model="row.returnCount" :formatter="erpCountInputFormatter" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="数量" prop="count" fixed="right" min-width="140">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!">
<el-input-number
v-model="row.count"
controls-position="right"
:min="0.0001"
:precision="4"
class="!w-100%"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="产品单价" fixed="right" min-width="120">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.productPrice`" class="mb-0px!">
<el-input-number
v-model="row.productPrice"
controls-position="right"
:min="0.0001"
:precision="4"
class="!w-100%"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="金额" prop="totalProductPrice" fixed="right" min-width="100">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.totalProductPrice`" class="mb-0px!">
<el-input
disabled
v-model="row.totalProductPrice"
:formatter="erpPriceInputFormatter"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="税率(%" fixed="right" min-width="115">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.taxPercent`" class="mb-0px!">
<el-input-number <el-input-number
v-model="row.taxPercent" v-model="row.taxPercent"
controls-position="right" controls-position="right"
:min="0" :min="0"
:precision="4" :precision="4"
class="!w-100%" style="width: 100%"
/> />
</el-form-item> </el-form-item>
</template> <div class="mobile-item-card__info-row">
</el-table-column> <span class="mobile-item-card__info-label">税额</span>
<el-table-column label="税额" prop="taxPrice" fixed="right" min-width="120"> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.taxPrice) }}</span>
<template #default="{ row, $index }"> </div>
<el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> <div class="mobile-item-card__info-row">
<el-form-item :prop="`${$index}.taxPrice`" class="mb-0px!"> <span class="mobile-item-card__info-label">税额合计</span>
<el-input disabled v-model="row.taxPrice" :formatter="erpPriceInputFormatter" /> <span class="mobile-item-card__info-value">{{ erpPriceInputFormatter(row.totalPrice) }}</span>
</el-form-item> </div>
</el-form-item> <el-form-item label="备注" :prop="`${$index}.remark`">
</template>
</el-table-column>
<el-table-column label="税额合计" prop="totalPrice" fixed="right" min-width="100">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!">
<el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="备注" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.remark`" class="mb-0px!">
<el-input v-model="row.remark" placeholder="请输入备注" /> <el-input v-model="row.remark" placeholder="请输入备注" />
</el-form-item> </el-form-item>
</template> </div>
</el-table-column> </div>
<el-table-column align="center" fixed="right" label="操作" width="60">
<template #default="{ $index }"> <!-- 合计 -->
<el-button :disabled="formData.length === 1" @click="handleDelete($index)" link> <div class="mobile-item-summary" v-if="formData.length > 0">
<div class="mobile-item-summary__row">
</el-button> <span>合计数量</span>
</template> <span>{{ erpCountInputFormatter(summaryData.count) }}</span>
</el-table-column> </div>
</el-table> <div class="mobile-item-summary__row">
<span>合计金额</span>
<span>{{ erpPriceInputFormatter(summaryData.totalProductPrice) }}</span>
</div>
<div class="mobile-item-summary__row mobile-item-summary__row--total">
<span>税额合计</span>
<span>{{ erpPriceInputFormatter(summaryData.totalPrice) }}</span>
</div>
</div>
</div>
</el-form> </el-form>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -233,25 +198,14 @@ watch(
) )
/** 合计 */ /** 合计 */
const getSummaries = (param: SummaryMethodProps) => { const summaryData = computed(() => {
const { columns, data } = param return {
const sums: string[] = [] count: getSumValue(formData.value.map((item) => Number(item.count))),
columns.forEach((column, index: number) => { totalProductPrice: getSumValue(formData.value.map((item) => Number(item.totalProductPrice))),
if (index === 0) { taxPrice: getSumValue(formData.value.map((item) => Number(item.taxPrice))),
sums[index] = '合计' totalPrice: getSumValue(formData.value.map((item) => Number(item.totalPrice)))
return }
} })
if (['count', 'totalProductPrice', 'taxPrice', 'totalPrice'].includes(column.property)) {
const sum = getSumValue(data.map((item) => Number(item[column.property])))
sums[index] =
column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum)
} else {
sums[index] = ''
}
})
return sums
}
/** 新增按钮操作 */ /** 新增按钮操作 */
const handleAdd = () => { const handleAdd = () => {
@@ -298,3 +252,82 @@ onMounted(async () => {
defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus) defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus)
}) })
</script> </script>
<style lang="scss" scoped>
.mobile-item-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-item-card {
background: #f9fafb;
border-radius: 8px;
border: 1px solid #ebeef5;
overflow: hidden;
&__header {
display: flex;
align-items: center;
padding: 10px 12px;
background: #f0f2f5;
gap: 8px;
}
&__index {
font-size: 13px;
font-weight: 600;
color: #409eff;
flex-shrink: 0;
}
&__name {
flex: 1;
font-size: 14px;
font-weight: 500;
color: #303133;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__body {
padding: 10px 12px;
}
&__info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 4px 0;
font-size: 13px;
}
&__info-label {
color: #909399;
flex-shrink: 0;
}
&__info-value {
color: #606266;
text-align: right;
}
&__input-group {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
}
.mobile-item-summary {
background: #fff;
border-radius: 8px;
border: 1px solid #ebeef5;
padding: 10px 12px;
&__row {
display: flex;
justify-content: space-between;
padding: 4px 0;
font-size: 13px;
color: #606266;
&--total {
font-weight: 600;
color: #303133;
border-top: 1px solid #ebeef5;
padding-top: 8px;
margin-top: 4px;
}
}
}
</style>

View File

@@ -1,134 +1,141 @@
<!-- 可退款的销售退货单列表 --> <!-- 可退款的销售退货单列表 -->
<template> <template>
<Dialog <el-drawer
title="选择销售退货(仅展示可退款)"
v-model="dialogVisible" v-model="dialogVisible"
:appendToBody="true" title="选择销售退货(仅展示可退款)"
:scroll="true" direction="rtl"
width="1080" size="100%"
:close-on-press-escape="true"
:destroy-on-close="true"
> >
<ContentWrap> <div class="mobile-enable-list">
<!-- 搜索工作 --> <!-- 搜索栏 -->
<el-form <div class="mobile-enable-list__search">
class="-mb-15px" <el-input
:model="queryParams" v-model="queryParams.no"
ref="queryFormRef" placeholder="搜索退货单号"
:inline="true" clearable
label-width="68px" @keyup.enter="handleQuery"
> :prefix-icon="Search"
<el-form-item label="退货单号" prop="no"> />
<el-input <el-button :icon="Filter" circle @click="filterVisible = true" />
v-model="queryParams.no" </div>
placeholder="请输入退货单号"
clearable <!-- 卡片列表 -->
@keyup.enter="handleQuery" <div class="mobile-enable-list__body" v-loading="loading">
class="!w-160px" <el-empty v-if="list.length === 0 && !loading" description="暂无可退款退货单" />
/> <div
</el-form-item> v-for="item in list"
:key="item.no"
class="mobile-enable-list__card"
:class="{ 'mobile-enable-list__card--selected': selectionList.includes(item) }"
@click="handleToggleSelection(item)"
>
<div class="mobile-enable-list__card-check">
<el-checkbox :model-value="selectionList.includes(item)" />
</div>
<div class="mobile-enable-list__card-content">
<div class="mobile-enable-list__card-no">{{ item.no }}</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">客户</span>
<span>{{ item.customerName || '-' }}</span>
</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">产品</span>
<span class="mobile-enable-list__card-ellipsis">{{ item.productNames || '-' }}</span>
</div>
<div class="mobile-enable-list__card-row">
<span class="mobile-enable-list__card-label">退货时间</span>
<span>{{ formatDate2(item.returnTime) }}</span>
</div>
<div class="mobile-enable-list__card-nums">
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val mobile-enable-list__card-num-val--price">
¥{{ erpPriceInputFormatter(item.totalPrice) }}
</div>
<div class="mobile-enable-list__card-num-label">应退金额</div>
</div>
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val mobile-enable-list__card-num-val--price">
¥{{ erpPriceInputFormatter(item.refundPrice || 0) }}
</div>
<div class="mobile-enable-list__card-num-label">已退金额</div>
</div>
<div class="mobile-enable-list__card-num">
<div class="mobile-enable-list__card-num-val mobile-enable-list__card-num-val--price">
<span v-if="(item.refundPrice || 0) >= item.totalPrice">0</span>
<el-tag v-else type="danger">
¥{{ erpPriceInputFormatter(item.totalPrice - (item.refundPrice || 0)) }}
</el-tag>
</div>
<div class="mobile-enable-list__card-num-label">未退金额</div>
</div>
</div>
</div>
</div>
</div>
<!-- 分页 -->
<div class="mobile-enable-list__pagination" v-if="total > 0">
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
:page-sizes="[10, 20]"
layout="total, prev, pager, next"
:pager-count="5"
@pagination="getList"
/>
</div>
</div>
<!-- 筛选抽屉 -->
<el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="60%" :append-to-body="true">
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
<el-form-item label="产品" prop="productId"> <el-form-item label="产品" prop="productId">
<el-select <el-select v-model="queryParams.productId" clearable filterable placeholder="请选择产品" style="width:100%">
v-model="queryParams.productId" <el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
clearable
filterable
placeholder="请选择产品"
class="!w-160px"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="退货时间" prop="orderTime"> <el-form-item label="退货时间" prop="returnTime">
<el-date-picker <el-date-picker
v-model="queryParams.returnTime" v-model="queryParams.returnTime"
value-format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
type="daterange" type="daterange"
start-placeholder="开始日期" start-placeholder="开始日期"
end-placeholder="结束日期" end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" :default-time="['00:00:00', '23:59:59']"
class="!w-160px" style="width:100%"
/> />
</el-form-item> </el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
</el-form> </el-form>
</ContentWrap> <template #footer>
<el-button @click="resetQuery">重置</el-button>
<el-button type="primary" @click="filterVisible = false; handleQuery()">确认筛选</el-button>
</template>
</el-drawer>
<ContentWrap>
<el-table
v-loading="loading"
:data="list"
:show-overflow-tooltip="true"
:stripe="true"
@selection-change="handleSelectionChange"
>
<el-table-column width="30" label="选择" type="selection" />
<el-table-column min-width="180" label="退货单号" align="center" prop="no" />
<el-table-column label="客户" align="center" prop="customerName" />
<el-table-column label="产品信息" align="center" prop="productNames" min-width="200" />
<el-table-column
label="退货时间"
align="center"
prop="returnTime"
:formatter="dateFormatter2"
width="120px"
/>
<el-table-column label="创建人" align="center" prop="creatorName" />
<el-table-column
label="应退金额"
align="center"
prop="totalPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column
label="已退金额"
align="center"
prop="refundPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column label="未退金额" align="center">
<template #default="scope">
<span v-if="scope.row.refundPrice === scope.row.totalPrice">0</span>
<el-tag type="danger" v-else>
{{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.refundPrice) }}
</el-tag>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNo"
:total="total"
@pagination="getList"
/>
</ContentWrap>
<template #footer> <template #footer>
<el-button :disabled="!selectionList.length" type="primary" @click="submitForm"> <el-button :disabled="!selectionList.length" type="primary" @click="submitForm">
</el-button> </el-button>
<el-button @click="dialogVisible = false"> </el-button> <el-button @click="dialogVisible = false"> </el-button>
</template> </template>
</Dialog> </el-drawer>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ElTable } from 'element-plus' import { Search, Filter } from '@element-plus/icons-vue'
import { dateFormatter2 } from '@/utils/formatTime'
import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils'
import { ProductApi, ProductVO } from '@/api/erp/product/product' import { ProductApi, ProductVO } from '@/api/erp/product/product'
import { SaleReturnApi, SaleReturnVO } from '@/api/erp/sale/return' import { SaleReturnApi, SaleReturnVO } from '@/api/erp/sale/return'
import { formatDate } from '@/utils/formatTime'
import { erpPriceInputFormatter } from '@/utils'
defineOptions({ name: 'SaleReturnPaymentEnableList' }) const list = ref<SaleReturnVO[]>([])
const total = ref(0)
const list = ref<SaleReturnVO[]>([]) // 列表的数据 const loading = ref(false)
const total = ref(0) // 列表的总页数 const dialogVisible = ref(false)
const loading = ref(false) // 列表的加载中 const filterVisible = ref(false)
const dialogVisible = ref(false) // 弹窗的是否展示
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@@ -138,26 +145,31 @@ const queryParams = reactive({
refundEnable: true, refundEnable: true,
customerId: undefined customerId: undefined
}) })
const queryFormRef = ref() // 搜索的表单 const queryFormRef = ref()
const productList = ref<ProductVO[]>([]) // 产品列表 const productList = ref<ProductVO[]>([])
/** 选中操作 */
const selectionList = ref<SaleReturnVO[]>([]) const selectionList = ref<SaleReturnVO[]>([])
const handleSelectionChange = (rows: SaleReturnVO[]) => {
selectionList.value = rows const formatDate2 = (date: any) => {
if (!date) return '-'
return formatDate(new Date(date), 'YYYY-MM-DD')
}
// 切换选中状态
const handleToggleSelection = (row: SaleReturnVO) => {
const index = selectionList.value.indexOf(row)
if (index > -1) selectionList.value.splice(index, 1)
else selectionList.value.push(row)
} }
/** 打开弹窗 */ /** 打开弹窗 */
const open = async (customerId: number) => { const open = async (customerId: number) => {
dialogVisible.value = true dialogVisible.value = true
await nextTick() // 等待,避免 queryFormRef 为空 await nextTick()
// 加载列表
queryParams.customerId = customerId queryParams.customerId = customerId
await resetQuery() await resetQuery()
// 加载产品列表
productList.value = await ProductApi.getProductSimpleList() productList.value = await ProductApi.getProductSimpleList()
} }
defineExpose({ open }) // 提供 open 方法,用于打开弹窗 defineExpose({ open })
/** 提交选择 */ /** 提交选择 */
const emits = defineEmits<{ const emits = defineEmits<{
@@ -167,12 +179,11 @@ const submitForm = () => {
try { try {
emits('success', selectionList.value) emits('success', selectionList.value)
} finally { } finally {
// 关闭弹窗
dialogVisible.value = false dialogVisible.value = false
} }
} }
/** 加载列表 */ /** 加载列表 */
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
@@ -186,7 +197,7 @@ const getList = async () => {
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value?.resetFields()
handleQuery() handleQuery()
} }
@@ -197,3 +208,101 @@ const handleQuery = () => {
getList() getList()
} }
</script> </script>
<style lang="scss" scoped>
/* 与其他订单列表相同样式 */
.mobile-enable-list {
padding: 12px;
&__search {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
}
&__body {
display: flex;
flex-direction: column;
gap: 10px;
}
&__card {
display: flex;
background: #fff;
border-radius: 10px;
padding: 12px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
border: 2px solid transparent;
transition: border-color 0.2s;
&--selected {
border-color: var(--el-color-primary);
}
}
&__card-check {
flex-shrink: 0;
padding-right: 8px;
display: flex;
align-items: flex-start;
padding-top: 2px;
}
&__card-content {
flex: 1;
min-width: 0;
}
&__card-no {
font-weight: 600;
font-size: 14px;
color: #303133;
margin-bottom: 6px;
}
&__card-row {
display: flex;
justify-content: space-between;
font-size: 13px;
color: #606266;
padding: 2px 0;
}
&__card-label {
color: #909399;
flex-shrink: 0;
margin-right: 10px;
}
&__card-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 180px;
text-align: right;
}
&__card-nums {
display: flex;
justify-content: space-around;
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid #f0f0f0;
}
&__card-num {
text-align: center;
}
&__card-num-val {
font-size: 14px;
font-weight: 600;
color: #303133;
&--price {
color: #e6a23c;
}
}
&__card-num-label {
font-size: 11px;
color: #909399;
margin-top: 2px;
}
&__pagination {
margin-top: 12px;
display: flex;
justify-content: center;
:deep(.el-pagination) {
flex-wrap: wrap;
justify-content: center;
}
}
}
</style>

View File

@@ -1,310 +1,153 @@
<template> <template>
<doc-alert title="【销售】销售订单、出库、退货" url="https://doc.iocoder.cn/erp/sale/" /> <div class="mobile-sale-return">
<!-- 顶部操作栏 -->
<ContentWrap> <div class="mobile-header">
<!-- 搜索工作栏 --> <div class="mobile-header__search">
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="退货单号" prop="no">
<el-input <el-input
v-model="queryParams.no" v-model="queryParams.no"
placeholder="请输入退货单号" placeholder="搜索退货单号"
clearable clearable
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
class="!w-240px" :prefix-icon="Search"
/> />
</el-form-item> </div>
<el-form-item label="产品" prop="productId"> <div class="mobile-header__actions">
<el-select <el-button :icon="Filter" circle @click="filterVisible = true" />
v-model="queryParams.productId"
clearable
filterable
placeholder="请选择产品"
class="!w-240px"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="退货时间" prop="outTime">
<el-date-picker
v-model="queryParams.outTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-select
v-model="queryParams.customerId"
clearable
filterable
placeholder="请选择供客户"
class="!w-240px"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="仓库" prop="warehouseId">
<el-select
v-model="queryParams.warehouseId"
clearable
filterable
placeholder="请选择仓库"
class="!w-240px"
>
<el-option
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="创建人" prop="creator">
<el-select
v-model="queryParams.creator"
clearable
filterable
placeholder="请选择创建人"
class="!w-240px"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="关联订单" prop="orderNo">
<el-input
v-model="queryParams.orderNo"
placeholder="请输入关联订单"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="结算账户" prop="accountId">
<el-select
v-model="queryParams.accountId"
clearable
filterable
placeholder="请选择结算账户"
class="!w-240px"
>
<el-option
v-for="item in accountList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="退款状态" prop="refundStatus">
<el-select
v-model="queryParams.refundStatus"
placeholder="请选择退款状态"
clearable
class="!w-240px"
>
<el-option label="未退款" value="0" />
<el-option label="部分退款" value="1" />
<el-option label="全部退款" value="2" />
</el-select>
</el-form-item>
<el-form-item label="审核状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择审核状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="queryParams.remark"
placeholder="请输入备注"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button <el-button
type="primary" type="primary"
plain :icon="Plus"
circle
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['erp:sale-return:create']" v-hasPermi="['erp:sale-return:create']"
> />
<Icon icon="ep:plus" class="mr-5px" /> 新增 </div>
</el-button> </div>
<el-button
type="success" <!-- 卡片列表 -->
plain <div class="mobile-list" v-loading="loading">
@click="handleExport" <div v-if="list.length === 0 && !loading" class="mobile-empty">
:loading="exportLoading" <el-empty description="暂无销售退货" />
v-hasPermi="['erp:sale-return:export']" </div>
> <div
<Icon icon="ep:download" class="mr-5px" /> 导出 v-for="item in list"
</el-button> :key="item.id"
<el-button class="mobile-card"
type="danger" @click="handleCardClick(item)"
plain >
@click="handleDelete(selectionList.map((item) => item.id))" <div class="mobile-card__header">
v-hasPermi="['erp:sale-return:delete']" <span class="mobile-card__no">{{ item.no }}</span>
:disabled="selectionList.length === 0" <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="item.status" />
> </div>
<Icon icon="ep:delete" class="mr-5px" /> 删除 <div class="mobile-card__body">
</el-button> <div class="mobile-card__row">
</el-form-item> <span class="mobile-card__label">客户</span>
</el-form> <span class="mobile-card__value">{{ item.customerName || '-' }}</span>
</ContentWrap> </div>
<div class="mobile-card__row">
<span class="mobile-card__label">产品</span>
<span class="mobile-card__value mobile-card__value--ellipsis">{{ item.productNames || '-' }}</span>
</div>
<div class="mobile-card__row">
<span class="mobile-card__label">退货时间</span>
<span class="mobile-card__value">{{ formatDate2Fn(item.returnTime) }}</span>
</div>
<div class="mobile-card__row">
<span class="mobile-card__label">创建人</span>
<span class="mobile-card__value">{{ item.creatorName || '-' }}</span>
</div>
<div class="mobile-card__nums">
<div class="mobile-card__num-item">
<div class="mobile-card__num-val">{{ erpCountInputFormatter(item.totalCount) }}</div>
<div class="mobile-card__num-label">总数量</div>
</div>
<div class="mobile-card__num-item">
<div class="mobile-card__num-val mobile-card__num-val--price">¥{{ erpPriceInputFormatter(item.totalPrice) }}</div>
<div class="mobile-card__num-label">应退</div>
</div>
<div class="mobile-card__num-item">
<div class="mobile-card__num-val">¥{{ erpPriceInputFormatter(item.refundPrice) }}</div>
<div class="mobile-card__num-label">已退</div>
</div>
<div class="mobile-card__num-item">
<div class="mobile-card__num-val" :class="{ 'mobile-card__num-val--danger': item.refundPrice !== item.totalPrice }">
¥{{ erpPriceInputFormatter(item.totalPrice - item.refundPrice) }}
</div>
<div class="mobile-card__num-label">未退</div>
</div>
</div>
</div>
<div class="mobile-card__footer">
<el-button size="small" @click.stop="openForm('detail', item.id)" v-hasPermi="['erp:sale-return:query']">详情</el-button>
<el-button size="small" type="primary" @click.stop="openForm('update', item.id)" v-hasPermi="['erp:sale-return:update']" :disabled="item.status === 20">编辑</el-button>
<el-button size="small" type="primary" @click.stop="handleUpdateStatus(item.id, 20)" v-hasPermi="['erp:sale-return:update-status']" v-if="item.status === 10">审批</el-button>
<el-button size="small" type="danger" @click.stop="handleUpdateStatus(item.id, 10)" v-hasPermi="['erp:sale-return:update-status']" v-if="item.status === 20">反审批</el-button>
<el-button size="small" type="danger" @click.stop="handleDelete([item.id])" v-hasPermi="['erp:sale-return:delete']">删除</el-button>
</div>
</div>
</div>
<!-- 列表 -->
<ContentWrap>
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
>
<el-table-column width="30" label="选择" type="selection" />
<el-table-column min-width="180" label="退货单号" align="center" prop="no" />
<el-table-column label="产品信息" align="center" prop="productNames" min-width="200" />
<el-table-column label="客户" align="center" prop="customerName" />
<el-table-column
label="退货时间"
align="center"
prop="returnTime"
:formatter="dateFormatter2"
width="120px"
sortable
/>
<el-table-column label="创建人" align="center" prop="creatorName" />
<el-table-column
label="总数量"
align="center"
prop="totalCount"
:formatter="erpCountTableColumnFormatter"
/>
<el-table-column
label="应退金额"
align="center"
prop="totalPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column
label="已退金额"
align="center"
prop="refundPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column label="未退金额" align="center">
<template #default="scope">
<span v-if="scope.row.refundPrice === scope.row.totalPrice">0</span>
<el-tag type="danger" v-else>
{{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.refundPrice) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="审核状态" align="center" fixed="right" width="90" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" width="220">
<template #default="scope">
<el-button
link
@click="openForm('detail', scope.row.id)"
v-hasPermi="['erp:sale-return:query']"
>
详情
</el-button>
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['erp:sale-return:update']"
:disabled="scope.row.status === 20"
>
编辑
</el-button>
<el-button
link
type="primary"
@click="handleUpdateStatus(scope.row.id, 20)"
v-hasPermi="['erp:sale-return:update-status']"
v-if="scope.row.status === 10"
>
审批
</el-button>
<el-button
link
type="danger"
@click="handleUpdateStatus(scope.row.id, 10)"
v-hasPermi="['erp:sale-return:update-status']"
v-else
>
反审批
</el-button>
<el-button
link
type="danger"
@click="handleDelete([scope.row.id])"
v-hasPermi="['erp:sale-return:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 --> <!-- 分页 -->
<Pagination <div class="mobile-pagination" v-if="total > 0">
:total="total" <Pagination
v-model:page="queryParams.pageNo" :total="total"
v-model:limit="queryParams.pageSize" v-model:page="queryParams.pageNo"
@pagination="getList" v-model:limit="queryParams.pageSize"
/> :page-sizes="[10, 20]"
</ContentWrap> layout="total, prev, pager, next"
:pager-count="5"
@pagination="getList"
/>
</div>
<!-- 表单弹窗添加/修改 --> <!-- 筛选抽屉 -->
<SaleReturnForm ref="formRef" @success="getList" /> <el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="70%">
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
<el-form-item label="产品" prop="productId">
<el-select v-model="queryParams.productId" clearable filterable placeholder="请选择产品" style="width:100%">
<el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-select v-model="queryParams.customerId" clearable filterable placeholder="请选择客户" style="width:100%">
<el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="退货时间" prop="outTime">
<el-date-picker v-model="queryParams.outTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" style="width:100%" />
</el-form-item>
<el-form-item label="仓库" prop="warehouseId">
<el-select v-model="queryParams.warehouseId" clearable filterable placeholder="请选择仓库" style="width:100%">
<el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="审核状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width:100%">
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="退款状态" prop="refundStatus">
<el-select v-model="queryParams.refundStatus" placeholder="请选择" clearable style="width:100%">
<el-option label="未退款" value="0" />
<el-option label="部分退款" value="1" />
<el-option label="全部退款" value="2" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="resetQuery">重置</el-button>
<el-button type="primary" @click="handleFilterConfirm">确认筛选</el-button>
</template>
</el-drawer>
<!-- 表单弹窗添加/修改 -->
<SaleReturnForm ref="formRef" @success="getList" />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Search, Filter, Plus } from '@element-plus/icons-vue'
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter2 } from '@/utils/formatTime' import { formatDate } from '@/utils/formatTime'
import download from '@/utils/download' import download from '@/utils/download'
import { SaleReturnApi, SaleReturnVO } from '@/api/erp/sale/return' import { SaleReturnApi, SaleReturnVO } from '@/api/erp/sale/return'
import SaleReturnForm from './SaleReturnForm.vue' import SaleReturnForm from './SaleReturnForm.vue'
@@ -312,9 +155,8 @@ import { ProductApi, ProductVO } from '@/api/erp/product/product'
import { UserVO } from '@/api/system/user' import { UserVO } from '@/api/system/user'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
import { import {
erpCountTableColumnFormatter, erpCountInputFormatter,
erpPriceInputFormatter, erpPriceInputFormatter
erpPriceTableColumnFormatter
} from '@/utils' } from '@/utils'
import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer' import { CustomerApi, CustomerVO } from '@/api/erp/sale/customer'
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
@@ -329,6 +171,13 @@ const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中 const loading = ref(true) // 列表的加载中
const list = ref<SaleReturnVO[]>([]) // 列表的数据 const list = ref<SaleReturnVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数 const total = ref(0) // 列表的总页数
const filterVisible = ref(false) // 筛选抽屉
const formatDate2Fn = (date: any) => {
if (!date) return '-'
return formatDate(new Date(date), 'YYYY-MM-DD')
}
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@@ -372,7 +221,13 @@ const handleQuery = () => {
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value?.resetFields()
handleQuery()
}
/** 筛选确认 */
const handleFilterConfirm = () => {
filterVisible.value = false
handleQuery() handleQuery()
} }
@@ -382,24 +237,8 @@ const openForm = (type: string, id?: number) => {
formRef.value.open(type, id) formRef.value.open(type, id)
} }
/** 行点击操作 */ /** 卡片点击 */
const handleRowClick = (row: SaleReturnVO, column: any, event: MouseEvent) => { const handleCardClick = (row: SaleReturnVO) => {
// 检查是否点击了按钮、链接或其他交互元素
const target = event.target as HTMLElement
if (
target.tagName === 'BUTTON' ||
target.tagName === 'A' ||
target.tagName === 'I' ||
target.tagName === 'svg' ||
target.closest('button') ||
target.closest('a') ||
target.closest('.el-button') ||
target.closest('.el-checkbox')
) {
return
}
// 已审核打开详情页面,未审核打开编辑页面
if (row.status === 20) { if (row.status === 20) {
openForm('detail', row.id) openForm('detail', row.id)
} else if (row.status === 10) { } else if (row.status === 10) {
@@ -417,7 +256,6 @@ const handleDelete = async (ids: number[]) => {
message.success(t('common.delSuccess')) message.success(t('common.delSuccess'))
// 刷新列表 // 刷新列表
await getList() await getList()
selectionList.value = selectionList.value.filter((item) => !ids.includes(item.id))
} catch {} } catch {}
} }
@@ -449,12 +287,6 @@ const handleExport = async () => {
} }
} }
/** 选中操作 */
const selectionList = ref<SaleReturnVO[]>([])
const handleSelectionChange = (rows: SaleReturnVO[]) => {
selectionList.value = rows
}
/** 初始化 **/ /** 初始化 **/
onMounted(async () => { onMounted(async () => {
await getList() await getList()
@@ -468,3 +300,137 @@ onMounted(async () => {
// TODO 芋艿:可优化功能:列表界面,支持导入 // TODO 芋艿:可优化功能:列表界面,支持导入
// TODO 芋艿:可优化功能:详情界面,支持打印 // TODO 芋艿:可优化功能:详情界面,支持打印
</script> </script>
<style lang="scss" scoped>
.mobile-sale-return {
padding: 12px;
background: #f5f5f5;
min-height: 100vh;
}
.mobile-header {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
&__search {
flex: 1;
}
&__actions {
display: flex;
gap: 4px;
flex-shrink: 0;
}
}
.mobile-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-empty {
padding: 40px 0;
}
.mobile-card {
background: #fff;
border-radius: 10px;
padding: 14px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
&__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
&__no {
font-weight: 600;
font-size: 15px;
color: #303133;
}
&__body {
font-size: 13px;
}
&__row {
display: flex;
justify-content: space-between;
padding: 3px 0;
}
&__label {
color: #909399;
flex-shrink: 0;
margin-right: 12px;
}
&__value {
color: #606266;
text-align: right;
&--ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200px;
}
}
&__nums {
display: flex;
justify-content: space-around;
margin-top: 10px;
padding: 10px 0;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
}
&__num-item {
text-align: center;
}
&__num-val {
font-size: 15px;
font-weight: 600;
color: #303133;
&--price {
color: #e6a23c;
}
&--danger {
color: #f56c6c;
}
}
&__num-label {
font-size: 11px;
color: #909399;
margin-top: 2px;
}
&__footer {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 10px;
}
}
.mobile-pagination {
margin-top: 12px;
display: flex;
justify-content: center;
:deep(.el-pagination) {
flex-wrap: wrap;
justify-content: center;
}
}
</style>