src/views/financialManagement/receivable/reconciliation.vue
@@ -55,7 +55,7 @@
      </PIMTable>
    </div>
    <el-dialog title="对账明细" v-model="detailDialogVisible" width="900px" append-to-body>
    <FormDialog title="对账明细" v-model="detailDialogVisible" width="900px" @confirm="printDetail" @cancel="detailDialogVisible = false" operationType="detail">
      <div class="statement-header">
        <h3>{{ currentCustomer }} 应收对账单</h3>
        <p>对账期间: {{ currentPeriod }}</p>
@@ -88,16 +88,72 @@
        <el-table-column prop="remark" label="备注" show-overflow-tooltip />
      </el-table>
      <template #footer>
        <el-button @click="detailDialogVisible = false">关闭</el-button>
        <el-button type="primary" @click="printDetail">打印</el-button>
        <el-button @click="detailDialogVisible = false">关闭</el-button>
      </template>
    </el-dialog>
    </FormDialog>
    <FormDialog title="生成对账单" v-model="generateDialogVisible" width="1000px" @confirm="confirmGenerate" @cancel="generateDialogVisible = false">
      <el-form :model="generateForm" label-width="100px">
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="选择客户" prop="customerId">
              <el-select v-model="generateForm.customerId" placeholder="请选择客户" style="width: 100%;" @change="onCustomerChange">
                <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="对账月份" prop="period">
              <el-date-picker v-model="generateForm.period" type="month" placeholder="选择月份" value-format="YYYY-MM" style="width: 100%;" @change="onPeriodChange" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div v-if="salesData.length > 0" class="sales-section">
        <div class="section-title">本月销售数据</div>
        <el-table :data="salesData" border style="width: 100%; margin-bottom: 15px;" v-loading="salesLoading" @selection-change="handleSalesSelectionChange">
          <el-table-column type="selection" width="55" align="center" />
          <el-table-column prop="date" label="日期" width="120" />
          <el-table-column prop="code" label="单据编号" width="150" />
          <el-table-column prop="type" label="类型" width="100">
            <template #default="{ row }">
              <el-tag :type="row.type === '出库' ? 'success' : row.type === '收款' ? 'primary' : 'danger'">{{ row.type }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="amount" label="金额" width="120">
            <template #default="{ row }">
              <span :class="row.type === '出库' ? 'text-primary' : row.type === '收款' ? 'text-success' : 'text-danger'">¥{{ formatMoney(row.amount) }}</span>
            </template>
          </el-table-column>
          <el-table-column prop="remark" label="备注" />
        </el-table>
        <div class="summary-row">
          <span>期初余额: <strong class="text-primary">¥{{ formatMoney(generateForm.beginBalance) }}</strong></span>
          <span>本期应收: <strong class="text-primary">¥{{ formatMoney(generateForm.currentReceivable) }}</strong></span>
          <span>本期收款: <strong class="text-success">¥{{ formatMoney(generateForm.currentReceipt) }}</strong></span>
          <span>期末余额: <strong :class="calculateEndBalance(generateForm.beginBalance, generateForm.currentReceivable, generateForm.currentReceipt) >= 0 ? 'text-success' : 'text-danger'">¥{{ formatMoney(calculateEndBalance(generateForm.beginBalance, generateForm.currentReceivable, generateForm.currentReceipt)) }}</strong></span>
        </div>
      </div>
      <div v-else-if="generateForm.customerId && !salesLoading" class="empty-tip">
        <el-empty description="该客户本月暂无销售数据" />
      </div>
      <template #footer>
        <el-button type="primary" @click="confirmGenerate" :disabled="!canGenerate">确认生成</el-button>
        <el-button @click="generateDialogVisible = false">取消</el-button>
      </template>
    </FormDialog>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import { ref, reactive, onMounted, computed } from "vue";
import { ElMessage } from "element-plus";
import FormDialog from "@/components/Dialog/FormDialog.vue";
defineOptions({
  name: "应收对账",
@@ -132,6 +188,24 @@
const currentPeriod = ref("");
const detailData = ref([]);
const generateDialogVisible = ref(false);
const salesLoading = ref(false);
const salesData = ref([]);
const selectedSales = ref([]);
const generateForm = reactive({
  customerId: "",
  customerName: "",
  period: "",
  beginBalance: 0,
  currentReceivable: 0,
  currentReceipt: 0,
});
const canGenerate = computed(() => {
  return generateForm.customerId && generateForm.period && selectedSales.value.length > 0;
});
const customerList = [
  { id: 1, name: "北京科技有限公司" },
  { id: 2, name: "上海贸易公司" },
@@ -144,6 +218,10 @@
  { id: 2, statementCode: "DZ202401002", customerId: 2, customerName: "上海贸易公司", period: "2024-01", beginBalance: 5000, currentReceivable: 12000, currentReceipt: 10000, endBalance: 7000 },
  { id: 3, statementCode: "DZ202402001", customerId: 1, customerName: "北京科技有限公司", period: "2024-02", beginBalance: 17000, currentReceivable: 20000, currentReceipt: 15000, endBalance: 22000 },
];
const calculateEndBalance = (beginBalance, currentReceivable, currentReceipt) => {
  return beginBalance + currentReceivable - currentReceipt;
};
const formatMoney = (value) => {
  if (value === undefined || value === null) return "0.00";
@@ -177,34 +255,133 @@
};
const generateStatement = () => {
  ElMessage.success("对账单生成成功");
  generateForm.customerId = "";
  generateForm.customerName = "";
  generateForm.period = "";
  generateForm.beginBalance = 0;
  generateForm.currentReceivable = 0;
  generateForm.currentReceipt = 0;
  salesData.value = [];
  selectedSales.value = [];
  generateDialogVisible.value = true;
};
const onCustomerChange = (customerId) => {
  const customer = customerList.find(item => item.id === customerId);
  if (customer) {
    generateForm.customerName = customer.name;
  }
  loadSalesData();
};
const onPeriodChange = () => {
  loadSalesData();
};
const loadSalesData = () => {
  if (!generateForm.customerId || !generateForm.period) {
    salesData.value = [];
    return;
  }
  salesLoading.value = true;
  setTimeout(() => {
    const mockSalesData = [
      { id: 1, date: generateForm.period + "-03", code: "CK2024001", type: "出库", amount: 8000, remark: "产品A销售" },
      { id: 2, date: generateForm.period + "-08", code: "SK2024001", type: "收款", amount: 5000, remark: "客户回款" },
      { id: 3, date: generateForm.period + "-12", code: "CK2024002", type: "出库", amount: 12000, remark: "产品B销售" },
      { id: 4, date: generateForm.period + "-15", code: "TH2024001", type: "退货", amount: 2000, remark: "质量问题退货" },
      { id: 5, date: generateForm.period + "-20", code: "CK2024003", type: "出库", amount: 5000, remark: "产品C销售" },
      { id: 6, date: generateForm.period + "-25", code: "SK2024002", type: "收款", amount: 8000, remark: "客户回款" },
    ];
    salesData.value = mockSalesData;
    const lastPeriod = getLastPeriod(generateForm.period);
    const lastStatement = mockData.find(item =>
      item.customerId === generateForm.customerId && item.period === lastPeriod
    );
    generateForm.beginBalance = lastStatement ? lastStatement.endBalance : 0;
    calculateSummary();
    salesLoading.value = false;
  }, 500);
};
const getLastPeriod = (period) => {
  const [year, month] = period.split("-").map(Number);
  if (month === 1) {
    return `${year - 1}-12`;
  }
  return `${year}-${String(month - 1).padStart(2, "0")}`;
};
const calculateSummary = () => {
  let receivable = 0;
  let receipt = 0;
  selectedSales.value.forEach(item => {
    if (item.type === "出库") {
      receivable += item.amount;
    } else if (item.type === "退货") {
      receivable -= item.amount;
    } else if (item.type === "收款") {
      receipt += item.amount;
    }
  });
  generateForm.currentReceivable = receivable;
  generateForm.currentReceipt = receipt;
};
const handleSalesSelectionChange = (selection) => {
  selectedSales.value = selection;
  calculateSummary();
};
const confirmGenerate = () => {
  const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
  const customer = customerList[Math.floor(Math.random() * customerList.length)];
  const endBalance = calculateEndBalance(generateForm.beginBalance, generateForm.currentReceivable, generateForm.currentReceipt);
  mockData.unshift({
    id: newId,
    statementCode: "DZ" + Date.now(),
    customerId: customer.id,
    customerName: customer.name,
    period: "2024-03",
    beginBalance: Math.floor(Math.random() * 10000),
    currentReceivable: Math.floor(Math.random() * 20000),
    currentReceipt: Math.floor(Math.random() * 15000),
    endBalance: Math.floor(Math.random() * 20000),
    customerId: generateForm.customerId,
    customerName: generateForm.customerName,
    period: generateForm.period,
    beginBalance: generateForm.beginBalance,
    currentReceivable: generateForm.currentReceivable,
    currentReceipt: generateForm.currentReceipt,
    endBalance,
  });
  generateDialogVisible.value = false;
  ElMessage.success("对账单生成成功");
  getTableData();
};
const viewDetail = (row) => {
  currentCustomer.value = row.customerName;
  currentPeriod.value = row.period;
  const saleOutAmount = Math.floor(row.currentReceivable * 0.6);
  const returnAmount = Math.floor(row.currentReceivable * 0.1);
  const firstReceipt = Math.floor(row.currentReceipt * 0.4);
  const secondReceipt = row.currentReceipt - firstReceipt;
  let runningBalance = row.beginBalance;
  detailData.value = [
    { date: row.period + "-01", type: "期初", code: "-", debit: 0, credit: 0, balance: row.beginBalance, remark: "期初余额" },
    { date: row.period + "-05", type: "出库", code: "CK2024001", debit: 5000, credit: 0, balance: row.beginBalance + 5000, remark: "" },
    { date: row.period + "-10", type: "收款", code: "SK2024001", debit: 0, credit: 3000, balance: row.beginBalance + 2000, remark: "" },
    { date: row.period + "-15", type: "出库", code: "CK2024002", debit: 8000, credit: 0, balance: row.beginBalance + 10000, remark: "" },
    { date: row.period + "-20", type: "退货", code: "TH2024001", debit: 0, credit: 2000, balance: row.beginBalance + 8000, remark: "" },
    { date: row.period + "-25", type: "收款", code: "SK2024002", credit: row.currentReceipt - 3000, balance: row.endBalance, remark: "" },
    { date: row.period + "-01", type: "期初", code: "-", debit: 0, credit: 0, balance: runningBalance, remark: "期初余额" },
    { date: row.period + "-05", type: "出库", code: "CK2024001", debit: saleOutAmount, credit: 0, balance: runningBalance += saleOutAmount, remark: "销售出库" },
    { date: row.period + "-10", type: "收款", code: "SK2024001", debit: 0, credit: firstReceipt, balance: runningBalance -= firstReceipt, remark: "客户回款" },
    { date: row.period + "-15", type: "出库", code: "CK2024002", debit: row.currentReceivable - saleOutAmount - returnAmount, credit: 0, balance: runningBalance += (row.currentReceivable - saleOutAmount - returnAmount), remark: "销售出库" },
    { date: row.period + "-20", type: "退货", code: "TH2024001", debit: 0, credit: returnAmount, balance: runningBalance -= returnAmount, remark: "销售退货" },
    { date: row.period + "-25", type: "收款", code: "SK2024002", debit: 0, credit: secondReceipt, balance: runningBalance -= secondReceipt, remark: "客户回款" },
  ];
  detailDialogVisible.value = true;
};
@@ -255,4 +432,38 @@
    margin: 0;
  }
}
.sales-section {
  margin-top: 20px;
  .section-title {
    font-size: 16px;
    font-weight: bold;
    margin-bottom: 15px;
    padding-left: 10px;
    border-left: 4px solid #409eff;
  }
}
.summary-row {
  display: flex;
  justify-content: space-around;
  padding: 15px;
  background-color: #f5f7fa;
  border-radius: 4px;
  margin-top: 15px;
  span {
    font-size: 14px;
    strong {
      font-size: 16px;
      margin-left: 5px;
    }
  }
}
.empty-tip {
  margin-top: 30px;
}
</style>