| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- <template>
- <ele-modal
- custom-class="ele-dialog-form long-dialog-form"
- :centered="true"
- :visible.sync="collectionDialogFlag"
- :title="title"
- :append-to-body="true"
- :close-on-click-modal="false"
- width="80%"
- :before-close="cancel"
- :maxable="true"
- :resizable="true"
- >
- <div style="margin: 10px 0; font-size: 14px; color: #606266;">
- <span>应收金额:{{ row.receivableTotalPrice || 0 }} 元</span>
- <span style="margin-left: 20px;">已收金额:{{ receivedAmount }} 元</span>
- <span style="margin-left: 20px;">未收金额:{{ unreceivedAmount }} 元</span>
- </div>
- <el-form ref="form" :model="form" class="table-form" label-width="100px">
- <el-row :gutter="12">
- <el-col :span="8">
- <el-form-item
- label="收款时间"
- prop="receivedDate"
- :rules="{ required: true, message: '请选择收款时间', trigger: 'change' }"
- >
- <el-date-picker
- v-model="form.receivedDate"
- type="date"
- placeholder="年/月/日"
- value-format="yyyy-MM-dd"
- style="width: 100%"
- size="small"
- :disabled="isView"
- />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="已收金额">
- <el-input
- :value="receivedAmount"
- placeholder="0"
- size="small"
- disabled
- />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="支付类型" prop="paymentType" :rules="{ required: true, message: '请选择支付类型', trigger: 'change' }">
- <DictSelection
- v-model="form.paymentType"
- dictName="支付类型"
- placeholder="请选择"
- class="payment-select"
- :disabled="isView"
- />
- </el-form-item>
- </el-col>
- <el-col :span="16">
- <el-form-item label="备注" prop="remark">
- <el-input
- v-model="form.remark"
- placeholder="请输入"
- size="small"
- :disabled="isView"
- />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="附件" prop="files">
- <fileMain v-model="form.files" :limit="1" :type="isView ? 'view' : 'add'"></fileMain>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <headerTitle title="应收明细" style="margin-top: 30px"></headerTitle>
- <el-form ref="detailForm" :model="{ flatList }">
- <ele-pro-table
- ref="detailTable"
- row-key="id"
- :needPage="false"
- :columns="columns"
- max-height="500px"
- :datasource="flatList"
- :selection.sync="selection"
- class="time-form"
- >
- <!-- 本次对账金额:唯一可填写字段 -->
- <template v-slot:statementAmount="scope">
- <el-input
- v-model="scope.row.statementAmount"
- type="number"
- placeholder="请输入"
- size="small"
- :disabled="isView"
- @input="handleAmountChange(scope.row, scope.$index)"
- />
- </template>
- <template v-slot:headerRequired="{ column }">
- <span class="is-required">{{ column.label }}</span>
- </template>
- </ele-pro-table>
- </el-form>
- <div slot="footer">
- <el-button type="primary" @click="save()">保存</el-button>
- <el-button @click="cancel">返回</el-button>
- </div>
- </ele-modal>
- </template>
- <script>
- import { pricingWayList } from '@/enum/dict.js';
- import { finReceivableSaveAPI, getProductListForReceiptAPI } from "@/api/financialManage/receivableManage";
- export default {
- name: "collectionDialog",
- components: {},
- props: {
- collectionDialogFlag: {
- type: Boolean,
- default: false
- },
- // 汇总区总金额(如预收金额/应收金额)
- totalPrice: {
- type: [Number, String],
- default: 0
- },
- // 汇总区总金额标签(如"预收金额"/"应收金额")
- totalLabel: {
- type: String,
- default: '预收金额'
- }
- },
- computed: {
- isView() {
- return this.dialogType === 'view';
- },
- // 已收金额 = 勾选的应收明细「本次对账金额」之和
- receivedAmount() {
- const sum = this.selection.reduce((pre, item) => {
- const val = parseFloat(item.statementAmount);
- return pre + (isNaN(val) ? 0 : val);
- }, 0);
- return sum.toFixed(2);
- },
- // 未收金额 = 应收金额 - 已收金额
- unreceivedAmount() {
- const total = parseFloat(this.row.receivableTotalPrice) || 0;
- const received = parseFloat(this.receivedAmount) || 0;
- return (total - received).toFixed(2);
- },
- queryDimension() {
- return this.form.queryDimension != null ? this.form.queryDimension : 1;
- },
- columns() {
- let columnsVersion = this.columnsVersion;
- return [
- {
- width: 45,
- type: 'selection',
- columnKey: 'selection',
- align: 'center',
- fixed: 'left'
- },
- {
- width: 60,
- label: '序号',
- type: 'index',
- columnKey: 'index',
- align: 'center',
- fixed: 'left'
- },
- {
- minWidth: 140,
- prop: 'orderNo',
- label: this.queryDimension == 3 ? '采购订单编码' : '销售订单编码',
- align: 'center',
- showOverflowTooltip: true
- },
- {
- minWidth: 140,
- prop: 'statementSubOrderNo',
- label: this.queryDimension == 3 ? '收货单编码' : this.queryDimension == 1 ? '发货单编码' : '调拨单编码',
- align: 'center',
- showOverflowTooltip: true
- },
- {
- minWidth: 120,
- prop: 'productOperateTime',
- label: this.queryDimension == 3 ? '收货日期' : this.queryDimension == 1 ? '发货日期' : '调拨单日期',
- align: 'center',
- showOverflowTooltip: true
- },
- {
- minWidth: 120,
- prop: 'productCode',
- label: '产品编码',
- align: 'center',
- showOverflowTooltip: true
- },
- {
- minWidth: 140,
- prop: 'productName',
- label: '产品名称',
- align: 'center',
- showOverflowTooltip: true
- },
- {
- minWidth: 120,
- prop: 'batchNo',
- label: '批次号',
- align: 'center',
- showOverflowTooltip: true
- },
- {
- minWidth: 110,
- prop: 'historicalStatementCount',
- label: '已对账数量',
- align: 'center'
- },
- {
- minWidth: 140,
- prop: 'statementCount',
- label: '数量',
- align: 'center'
- },
- {
- minWidth: 120,
- headerSlot: 'headerRequired',
- prop: 'statementAmount',
- label: '本次已收金额',
- align: 'center',
- slot: 'statementAmount'
- },
- {
- minWidth: 120,
- prop: 'totalCount',
- label: this.queryDimension == 3 ? '收货数量' : this.queryDimension == 1 ? '发货数量' : '调拨数量',
- align: 'center'
- },
- {
- minWidth: 140,
- prop: 'technologyRouteName',
- label: '工艺路线',
- align: 'center',
- showOverflowTooltip: true
- },
- {
- minWidth: 120,
- prop: 'singlePrice',
- label: '单价',
- align: 'center'
- },
- {
- minWidth: 100,
- prop: 'taxRate',
- label: '税率',
- align: 'center'
- },
- {
- minWidth: 100,
- prop: 'noTaxSinglePrice',
- label: '不含税单价',
- align: 'center'
- },
- {
- minWidth: 100,
- prop: 'totalPrice',
- label: '合计',
- align: 'center'
- },
- {
- minWidth: 120,
- prop: 'discountRatio',
- label: '折让比例',
- align: 'center'
- },
- {
- minWidth: 120,
- prop: 'discountSinglePrice',
- label: '折让单价',
- align: 'center'
- },
- {
- minWidth: 120,
- prop: 'discountTotalPrice',
- label: '折让合计',
- align: 'center'
- },
- {
- minWidth: 100,
- prop: 'specification',
- label: '规格',
- align: 'center',
- showOverflowTooltip: true
- },
- {
- minWidth: 100,
- prop: 'modelType',
- label: '型号',
- align: 'center',
- showOverflowTooltip: true
- },
- {
- minWidth: 80,
- prop: 'color',
- label: '颜色',
- align: 'center',
- showOverflowTooltip: true
- },
- {
- minWidth: 120,
- prop: 'outInCount',
- label: '出库数量',
- align: 'center'
- },
- {
- minWidth: 120,
- prop: 'measuringUnit',
- label: '计量单位',
- align: 'center'
- },
- {
- minWidth: 120,
- prop: 'sendTotalWeight',
- label: '出库重量',
- align: 'center'
- },
- {
- minWidth: 120,
- prop: 'weightUnit',
- label: '重量单位',
- align: 'center'
- },
- {
- minWidth: 120,
- prop: 'pricingWay',
- label: '计价方式',
- align: 'center',
- formatter: (row, column) => {
- return pricingWayList.find((item) => item.id == row.pricingWay)?.name;
- }
- }
- ];
- }
- },
- data() {
- return {
- row: {},
- dialogType: '',
- title: '',
- loading: false,
- info: {},
- form: {
- id: '',
- queryDimension: 1,
- receivedDate: '',
- paymentType: '',
- files: [],
- remark: '',
- },
- rules: {},
- datasource: [],
- flatList: [],
- selection: [],
- totalAmount: 0,
- totalCount: 0,
- columnsVersion: 1
- }
- },
- watch: {
- datasource: {
- handler(newVal) {
- this.$nextTick(() => {
- const list = (newVal || []).map((item) => this.buildRow(item, item.orderNo || '', false));
- this.flatList = list;
- this.calcTotals();
- });
- },
- immediate: true
- }
- },
- created() {},
- methods: {
- // 初始化
- async open(row, type) {
- this.row = row || {};
- this.dialogType = type || 'update';
- this.title = this.dialogType === 'view' ? '收款详情' : '收款';
- await this.getInfo(row.id);
- },
- // 获取详情(收款专用接口:仅返回产品列表,不带表单主信息)
- async getInfo(id) {
- const data = await getProductListForReceiptAPI(id);
- // 新接口只返回产品列表
- this.datasource = Array.isArray(data) ? data : (data.productList || []);
- this.form = {
- ...this.form,
- id: data?.id || '',
- queryDimension: data?.queryDimension != null ? data.queryDimension : 1,
- receivedDate: data?.receivedDate || '',
- paymentType: data?.paymentType ?? '',
- files: data?.files || [],
- remark: data?.remark || ''
- };
- },
- // 构建单行派生字段
- buildRow(item, orderNo, isReturn) {
- const outboundCount = +item.totalCount || 0;
- const count = isReturn ? -Math.abs(outboundCount) : outboundCount;
- const statemented = +item.statementedCount || 0;
- let statementCount = item.statementCount;
- if (statementCount === undefined || statementCount === null || statementCount === '') {
- statementCount = count;
- }
- const singlePrice = +item.singlePrice;
- const discountRatio =
- item.discountRatio === undefined || item.discountRatio === null || item.discountRatio === ''
- ? 100
- : +item.discountRatio;
- const taxRate =
- item.taxRate === undefined || item.taxRate === null || item.taxRate === ''
- ? ''
- : +item.taxRate;
- const amount =
- Math.round(statementCount * singlePrice * (discountRatio / 100) * 100) / 100;
- const noTaxSinglePrice =
- singlePrice && taxRate ? +((singlePrice / (1 + taxRate / 100)).toFixed(4)) : '';
- const totalPrice = Math.round(statementCount * singlePrice * 100) / 100;
- const discountSinglePrice = Math.round(singlePrice * (discountRatio / 100) * 100) / 100;
- const discountTotalPrice = Math.round(totalPrice * (discountRatio / 100) * 100) / 100;
- this.$set(item, 'saleOrderNo', orderNo);
- this.$set(item, 'statementSubOrderNo', item.statementSubOrderNo || item.subOrderNo || '');
- this.$set(item, 'productOperateTime', item.productOperateTime || item.deliveryDate || '');
- this.$set(item, 'outboundCount', count);
- this.$set(item, 'statementedCount', statemented);
- this.$set(item, 'statementCount', statementCount);
- this.$set(item, 'singlePrice', singlePrice);
- this.$set(item, 'taxRate', taxRate);
- this.$set(item, 'discountRatio', discountRatio);
- this.$set(item, 'statementAmount', item?.receivedTotalPrice || amount);
- this.$set(item, 'noTaxSinglePrice', noTaxSinglePrice);
- this.$set(item, 'totalPrice', totalPrice);
- this.$set(item, 'discountSinglePrice', discountSinglePrice);
- this.$set(item, 'discountTotalPrice', discountTotalPrice);
- this.$set(item, 'isReturn', isReturn);
- return item;
- },
- // 汇总
- calcTotals() {
- const amount =
- this.flatList.reduce((pre, cur) => pre + Math.round((+cur.statementAmount || 0) * 100), 0) / 100;
- const count = this.flatList.reduce((pre, cur) => pre + (+cur.statementCount || 0), 0);
- this.totalAmount = amount;
- this.totalCount = count;
- },
- // 本次对账金额变化(唯一可编辑字段)
- handleAmountChange(row, index) {
- this.calcTotals();
- },
- // 获取勾选行数据
- getSelection() {
- return this.selection;
- },
- // 校验勾选行的本次对账金额必填
- validateSelection() {
- return new Promise((resolve, reject) => {
- if (!this.selection.length) {
- this.$message.warning('请先勾选需要提交的应收明细');
- reject(false);
- return;
- }
- const tips = [];
- this.selection.forEach((row, i) => {
- if (row.statementAmount === '' || row.statementAmount == null) {
- tips.push(`第${i + 1}行「本次对账金额」未填写`);
- }
- });
- if (tips.length) {
- this.$message.warning('勾选的应收明细存在未填写项:' + tips.join('、'));
- reject(false);
- } else {
- resolve(true);
- }
- });
- },
- async save() {
- // 1. 校验收款信息表单
- const formValid = await new Promise((resolve) => {
- this.$refs.form.validate((valid) => resolve(valid));
- });
- if (!formValid) {
- return this.$message.warning('请填写完整收款信息');
- }
- // 2. 获取勾选的应收明细并校验必填
- const selection = this.getSelection();
- if (!selection.length) {
- return this.$message.warning('请先勾选需要提交的应收明细');
- }
- const selectionValid = await this.validateSelection().catch(() => false);
- if (!selectionValid) return;
- this.loading = true;
- // 3. 提交:收款信息 + 勾选的应收明细(已收金额 = 勾选行本次对账金额之和)
- const params = {
- ...this.form,
- receivedTotalPrice: this.receivedAmount,
- receivableId: this.row.id,
- receivableCode: this.row.code,
- productList: selection
- };
- finReceivableSaveAPI(params)
- .then(() => {
- this.loading = false;
- this.$message.success('收款成功');
- this.cancel();
- this.done();
- })
- .catch(() => {
- this.loading = false;
- });
- },
- // 刷新主列表数据
- done() {
- this.$emit('reload');
- },
- // 关闭弹窗
- cancel() {
- this.$emit('update:collectionDialogFlag', false);
- }
- }
- }
- </script>
- <style scoped lang="scss">
- .detail-toolbar {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- margin-bottom: 10px;
- }
- </style>
|