wujianwei
2025-12-23 8194a67f3b9248cc80137c78bd3e005949ec38dc
Merge remote-tracking branch 'origin/cwxt_master' into cwxt_master
8个文件已添加
11个文件已修改
3221 ■■■■ 已修改文件
ui/admin-ui3/src/api/cwgl/receivableBillManagement.ts 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/api/cwgl/twoBankAccountConfig.ts 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/BillSettlementHistory/index.vue 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/DetailModal/index.vue 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/FeeDetailModal/index.vue 52 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/GenerateBillDialog/index.vue 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/NestedDetailDialog/index.vue 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/OperationLogModal/index.vue 89 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/Pagination/index.vue 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/SettlementDialog/index.vue 367 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/bankCardCate/index.vue 140 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/bankCardData/index.vue 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/components/subjectPeration/index.vue 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/main.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/views/cwgl/bankAccountConfig/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/views/cwgl/bankConfig/index.vue 318 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/views/cwgl/interiorBankAccountConfig/index.vue 306 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/views/cwgl/receivableBillManagement/index.vue 599 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/views/cwgl/receivableFeeManagement/index.vue 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/admin-ui3/src/api/cwgl/receivableBillManagement.ts
@@ -45,7 +45,13 @@
        data
    })
}
/* 作废 */
export const receivableBillManagementVoid:requestType = (id) => {
    return request({
        url: '/cwgl/receivableBillManagement/void/'+id,
        method: 'put',
    })
}
/**
 * 删除应收账单管理
 */
ui/admin-ui3/src/api/cwgl/twoBankAccountConfig.ts
New file
@@ -0,0 +1,67 @@
import request,{download,requestType} from "@/utils/request";
import {BaseEntityInterface} from "@/utils/globalInterface";
export interface BankAccountConfigI extends BaseEntityInterface{
            id ?:  number   ,            customerId ?:  number   ,            customerName ?:  string   ,            accountNo ?:  string   ,            accountName ?:  string   ,            bankName ?:  string   ,            branchName ?:  string   ,            accountType ?:  string   ,            currency ?:  string   ,            status ?:  string   ,            accountNumber ?:  string   ,            openingDate ?:  string   ,            bankCode ?:  string   ,            remark ?:  string   ,            isDefault ?:  number   ,            createBy ?:  string   ,            updateBy ?:  string   ,            createTime ?:  string   ,            updateTime ?:  string   ,            deleted ?:  number       }
/**
 * 查询银行账号配置列表
 */
export const listBankAccountConfig:requestType = (query) => {
    return request({
        url: '/cwgl/bankAccountConfig/list2',
        method:'get',
        params:query
    })
}
/**
 * 查询银行账号配置详细
 */
export const getBankAccountConfig:requestType = (id) => {
    return request({
        url: '/cwgl/bankAccountConfig2/' + id,
        method:'get'
    })
}
/**
 * 新增银行账号配置
 */
export const addBankAccountConfig:requestType = (data) => {
    return request({
        url: '/cwgl/bankAccountConfig2',
        method: 'post',
        data
    })
}
/**
 * 修改银行账号配置
 */
export const updateBankAccountConfig:requestType = (data) => {
    return request({
        url: '/cwgl/bankAccountConfig2',
        method: 'put',
        data
    })
}
/**
 * 删除银行账号配置
 */
export const delBankAccountConfig:requestType = (id) => {
    return request({
        url: '/cwgl/bankAccountConfig2/' + id,
        method: 'delete'
    })
}
/**
 * 导出银行账号配置
 */
export const exportBankAccountConfig:requestType = (query) => {
    return new Promise<any>(()=>{
        download('/cwgl/bankAccountConfig/export2',query);
    })
}
ui/admin-ui3/src/components/BillSettlementHistory/index.vue
New file
@@ -0,0 +1,199 @@
<template>
    <el-dialog v-model="visible" :title="type === 'receivable' ? '应收账单结算记录' : '应付账单结算记录'" width="1200px"
        destroy-on-close>
        <el-descriptions title="账单信息" :column="3" border class="mb-5">
            <el-descriptions-item label="系统编号">{{ billInfo.systemNo }}</el-descriptions-item>
            <el-descriptions-item label="账单名称">{{ billInfo.billName }}</el-descriptions-item>
            <el-descriptions-item :label="type === 'receivable' ? '客户名称' : '供应商名称'">
                {{ billInfo.customerName }}
            </el-descriptions-item>
            <el-descriptions-item label="单据数量">{{ billInfo.documentCount }}</el-descriptions-item>
            <el-descriptions-item label="应结算金额">
                <span class="text-bold">{{ billInfo.totalAmount }}</span>
            </el-descriptions-item>
            <el-descriptions-item label="币制">{{ billInfo.currency }}</el-descriptions-item>
            <el-descriptions-item :label="type === 'receivable' ? '已收金额' : '已付金额'">
                {{ billInfo.receivedAmount }}
            </el-descriptions-item>
            <el-descriptions-item :label="type === 'receivable' ? '待收金额' : '待付金额'">
                <span class="text-danger">{{ billInfo.pendingAmount }}</span>
            </el-descriptions-item>
            <el-descriptions-item label="减免金额">{{ billInfo.discountAmount }}</el-descriptions-item>
            <el-descriptions-item label="周期类型">{{ billInfo.periodType }}</el-descriptions-item>
            <el-descriptions-item label="业务期间">
                {{ billInfo.businessStartDate }} {{ billInfo.businessEndDate ? '-' + billInfo.businessEndDate : '' }}
            </el-descriptions-item>
            <el-descriptions-item label="账单周期">
                {{ billInfo.billingStartDate }} {{ billInfo.billingEndDate ? '-' + billInfo.billingEndDate : '' }}
            </el-descriptions-item>
            <el-descriptions-item label="账单生成日期">{{ billInfo.billGenerateDate }}</el-descriptions-item>
            <el-descriptions-item label="账单发送日期">{{ billInfo.billSendDate }}</el-descriptions-item>
            <el-descriptions-item label="账单到期日期">{{ billInfo.billDueDate }}</el-descriptions-item>
        </el-descriptions>
        <h3 class="section-title">结算明细</h3>
        <el-table v-loading="loading" :data="dataList" border stripe style="width: 100%">
            <el-table-column prop="settlementMethod" label="结算方式" align="center" width="100">
                <template #default="{ row }">
                    {{ dictFormat(sys_clearing_form, row.settlementMethod) }}
                </template>
            </el-table-column>
            <el-table-column prop="customerBank" :label="type === 'receivable' ? '客户开户行' : '供应商开户行'" align="center"
                min-width="150" />
            <el-table-column prop="customerBankAccount" :label="type === 'receivable' ? '客户银行账号' : '供应商银行账号'"
                align="center" min-width="180" />
            <el-table-column prop="receivingBank" label="收款账户开户行" align="center" min-width="150" />
            <el-table-column prop="receivingBankAccount" label="收款银行账户" align="center" min-width="180" />
            <el-table-column prop="settleDate" :label="type === 'receivable' ? '收款日期' : '付款日期'" align="center"
                width="110" />
            <el-table-column prop="settleAmount" :label="type === 'receivable' ? '收款金额' : '付款金额'" align="center"
                width="110">
                <template #default="{ row }">
                    <span class="text-bold">{{ row.settleAmount }}</span>
                </template>
            </el-table-column>
            <el-table-column prop="remainingAmount" :label="type === 'receivable' ? '收款后待收金额' : '付款后待付金额'"
                align="center" width="140" />
            <el-table-column prop="createTime" label="创建时间" align="center" width="160" />
            <el-table-column prop="createBy" label="创建人" align="center" width="100" />
        </el-table>
        <div class="pagination-container">
            <pagination v-show="pageF.total > 0" :total="pageF.total" v-model:page="queryParams.pageNum"
                v-model:limit="queryParams.pageSize" @pagination="getDataList" />
        </div>
        <template #footer>
            <el-button @click="visible = false">关闭</el-button>
        </template>
    </el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { getReceivableBillManagement } from "@/api/cwgl/receivableBillManagement";
import { listReceivableBillSettlementDetail } from "@/api/cwgl/receivableBillSettlementDetail";
import useCurrentInstance from "@/utils/useCurrentInstance";
const { proxy } = useCurrentInstance();
const { sys_clearing_form
 } = proxy.useDict('sys_clearing_form');
 const dictFormat = (dict: any, value: any) => {
    return proxy.selectDictLabel(dict, value);
}
const props = defineProps<{
    type: 'receivable' | 'payable'
}>()
const visible = ref(false)
const loading = ref(false)
const billInfo = ref<any>({})
const dataList = ref([])
// 分页与查询参数
const pageF = reactive({
    total: 0
})
const queryParams = reactive({
    pageNum: 1,
    pageSize: 10,
    billId: undefined
})
/** 查询结算历史列表 */
const getDataList = async () => {
    loading.value = true
    try {
        console.log(props.type);
        if (props.type === 'receivable') {
            getReceivableBillManagement(queryParams.billId).then(response => {
                if (response.code === 200) {
                    billInfo.value = response.data
                }
            })
            listReceivableBillSettlementDetail(queryParams).then(res => {
                if (res.code == 200) {
                    dataList.value = res.rows
                    pageF.total = res.total
                }
            })
        }
        // getReceivableBillManagement(queryParams).then(response => {
        //     billInfo.value = response.data
        //     dataList.value = response.data.settlementHistoryList
        //     pageF.total = response.data.total
        // })
        // 此处替换为你的实际接口调用  listReceivableBillSettlementDetail
        // const response = await getReceivableBillManagement(queryParams)
        // dataList.value = response.rows
        // pageF.total = response.total
    } finally {
        loading.value = false
    }
}
/** 打开弹窗 */
const open = (row: any) => {
    visible.value = true
    // console.log(row);
    console.log(props.type);
    // billInfo.value = { ...row }
    queryParams.billId = row.id
    queryParams.pageNum = 1
    getDataList()
}
defineExpose({ open })
</script>
<style scoped>
.mb-5 {
    margin-bottom: 20px;
}
.section-title {
    font-size: 16px;
    font-weight: bold;
    margin: 20px 0 15px 0;
    padding-left: 10px;
    border-left: 4px solid #409eff;
}
.text-bold {
    font-weight: bold;
}
.text-danger {
    color: #f56c6c;
    font-weight: bold;
}
.pagination-container {
    margin-top: 15px;
    display: flex;
    justify-content: flex-end;
}
:deep(.el-descriptions__label) {
    width: 120px;
    background-color: #f5f7fa !important;
}
/* 兼容你之前代码的单元格样式 */
::v-deep .el-descriptions__body .el-descriptions__table.is-bordered .el-descriptions__cell {
    padding: 8px 11px;
}
::v-deep .el-descriptions__body .el-descriptions__table.is-bordered .el-descriptions__cell {
    padding: 8px 11px;
    width: 200px;
}
</style>
ui/admin-ui3/src/components/DetailModal/index.vue
@@ -1,27 +1,21 @@
<template>
  <el-dialog
    v-model="visible"
    title="费用详情"
    width="1000px"
    destroy-on-close
    @closed="handleClosed"
  >
  <el-dialog v-model="visible" title="费用详情" width="1000px" destroy-on-close @closed="handleClosed">
    <div class="modal-content">
      <section class="detail-section">
        <h3 class="section-title">应收费用明细</h3>
        <el-descriptions :column="3" border class="margin-top">
          <el-descriptions-item label="系统编号">{{ detailData.systemNo }}</el-descriptions-item>
          <el-descriptions-item label="关联账单编号">{{ detailData.relatedBillNo }}</el-descriptions-item>
          <el-descriptions-item label="来源系统">{{ detailData.sourceSystem }}</el-descriptions-item>
          <el-descriptions-item label="业务板块">{{ detailData.businessSector }}</el-descriptions-item>
          <el-descriptions-item label="单据类型">{{ detailData.documentType }}</el-descriptions-item>
          <el-descriptions-item label="来源系统">{{ dictFormat(sys_system, detailData.sourceSystem) }}</el-descriptions-item>
          <el-descriptions-item label="业务板块">{{ dictFormat(sys_business, detailData.businessSector) }}</el-descriptions-item>
          <el-descriptions-item label="单据类型">{{ dictFormat(sys_receipts, detailData.documentType) }}</el-descriptions-item>
          <el-descriptions-item label="单据编号">{{ detailData.documentNo }}</el-descriptions-item>
          <el-descriptions-item label="客户名称">{{ detailData.customerName }}</el-descriptions-item>
          <el-descriptions-item label="项目名称">{{ detailData.projectName }}</el-descriptions-item>
          <el-descriptions-item label="业务发生时间">{{ detailData.businessTime }}</el-descriptions-item>
          <el-descriptions-item label="应收确认时间">{{ detailData.receivableConfirmTime }}</el-descriptions-item>
          <el-descriptions-item label="应收金额" :span="2">
            <span class="amount-text">{{ detailData.receivableAmount }}</span>
@@ -30,12 +24,40 @@
      </section>
      <section class="table-section">
        <h3 class="section-title" style="margin-top: 10px;" >费用明细</h3>
        <avue-crud
          :option="tableOption"
          :data="detailData.feeList || []"
        <h3 class="section-title" style="margin-top: 20px;">费用明细</h3>
        <el-table
          :data="detailData.feeList || []"
          border
          stripe
          style="width: 100%"
          :header-cell-style="{ backgroundColor: '#f5f7fa', color: '#606266' }"
        >
          </avue-crud>
          <el-table-column label="费用类型" align="center" prop="feeType"/>
            <!-- <template #default="scope">
              {{ dictFormat(fee_type, scope.row.feeType) }}
            </template>
          </el-table-column> -->
          <el-table-column label="费用名称" prop="feeName" align="center" />
          <el-table-column label="计费单位" align="center" prop="billingUnit"/>
            <!-- <template #default="scope">
              {{ dictFormat(sys_unit, scope.row.billingUnit) }}
            </template>
          </el-table-column> -->
          <el-table-column label="计费单价" prop="unitPrice" align="center" />
          <el-table-column label="计费金额" prop="billingAmount" align="center" />
          <el-table-column label="实收金额" prop="actualAmount" align="center" />
          <el-table-column label="币制" align="center"  prop="currency" >
            <template #default="scope">
              {{ dictFormat(sys_currency, scope.row.currency) }}
            </template>
          </el-table-column>
          <el-table-column label="费用登记时间" prop="createTime" width="160" align="center" />
        </el-table>
      </section>
    </div>
@@ -48,43 +70,49 @@
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { ref } from 'vue';
import useCurrentInstance from "@/utils/useCurrentInstance";
const { proxy } = useCurrentInstance();
// 加载所需的字典
const {
  sys_system,
  sys_business,
  sys_receipts,
  sys_currency,
  fee_type, // 对应之前的 dicUrl fee_type
  sys_unit   // 对应之前的 dicUrl sys_unit
} = proxy.useDict(
  'sys_system',
  'sys_business',
  'sys_receipts',
  'sys_currency',
  'fee_type',
  'sys_unit'
);
const dictFormat = (dict: any, value: any) => {
  return proxy.selectDictLabel(dict, value);
};
const visible = ref(false);
const detailData = ref<any>({});
// 表格配置
const tableOption = {
    tip: false,
  header: false, // 隐藏头部按钮
  addBtn: false,
  editBtn: false,
  delBtn: false,
  menu: false,   // 隐藏操作栏
  column: [
    { label: '费用类型', prop: 'feeType' },
    { label: '费用名称', prop: 'feeName' },
    { label: '计费单位', prop: 'unit' },
    { label: '计费单价', prop: 'price' },
    { label: '计费金额', prop: 'totalAmount' },
    { label: '实收金额', prop: 'actualAmount' },
    { label: '币制', prop: 'currency' },
    { label: '费用登记时间', prop: 'createTime', width: 160 },
  ]
};
// 暴露给父组件的方法
const open = (data: any) => {
  detailData.value = data || {};
  // 统一数据来源字段
  if (data && data.receivableFeeDetailList) {
    detailData.value.feeList = data.receivableFeeDetailList;
  } else {
    detailData.value.feeList = [];
  }
  visible.value = true;
};
const handleClosed = () => {
  detailData.value = {};
};
const handleConfirm = () => {
  visible.value = false;
};
defineExpose({ open });
@@ -94,26 +122,29 @@
.modal-content {
  padding: 10px;
}
.section-title {
  font-size: 16px;
  font-weight: bold;
  margin: 20px 0 10px 0;
  margin: 10px 0;
  color: #333;
  padding-left: 10px;
  border-left: 4px solid #409eff; /* 添加了蓝色侧边,与主流财务系统风格统一 */
}
.section-title:first-child {
  margin-top: 0;
}
.amount-text {
  color: #f56c6c;
  font-weight: bold;
}
:deep(.el-descriptions__label) {
  width: 120px;
  background-color: #f5f7fa;
}
/* 统一描述列表单元格样式 */
::v-deep .el-descriptions__body .el-descriptions__table.is-bordered .el-descriptions__cell {
    border: var(--el-descriptions-table-border);
    padding: 8px 11px;
    width: 100px;
  border: var(--el-descriptions-table-border);
  padding: 8px 11px;
}
</style>
ui/admin-ui3/src/components/FeeDetailModal/index.vue
@@ -36,7 +36,24 @@
          </el-form-item>
        </el-col>
        <el-col :span="8">
        <el-col :span="8" v-if="typeText == '应收'" >
          <el-form-item label="客户名称" prop="customerName">
            <!-- <el-select v-model="mainForm.customerName" placeholder="请选择供应商名称" style="width: 100%;" clearable>
              <el-option v-for="dict in sys_supplier" :key="dict.value" :label="dict.label"
                :value="dict.value"></el-option>
            </el-select> -->
            <el-input v-model="mainForm.customerName" placeholder="请选择 客户名称" readonly @click="handleCustonerClick"
              class="clickable-input">
              <template #suffix>
                <el-icon @click="handleCustonerClick" class="search-icon">
                  <Search />
                </el-icon>
              </template>
            </el-input>
          </el-form-item>
        </el-col>
             <el-col :span="8" v-if="typeText == '应付'" >
          <el-form-item label="供应商名称" prop="customerName">
            <!-- <el-select v-model="mainForm.customerName" placeholder="请选择供应商名称" style="width: 100%;" clearable>
              <el-option v-for="dict in sys_supplier" :key="dict.value" :label="dict.label"
@@ -79,7 +96,7 @@
        </el-col>
        <el-col :span="8" v-if="typeText == '应收'">
          <el-form-item label="应收金额" prop="receivableAmount">
            <el-input-number v-model="mainForm.receivableAmount" :min="0" class="w-full" />
            <el-input-number v-model="mainForm.receivableAmount" disabled :min="0" class="w-full" />
          </el-form-item>
        </el-col>
        <el-col :span="8" v-if="typeText == '应付'">
@@ -119,13 +136,13 @@
    <el-table :data="receivableFeeDetailList" border stripe style="width: 100%">
      <el-table-column prop="feeType" label="费用类型" >
        <template #default="scope">
          {{ dictFormat('fee_type', scope.row.feeType) }}
          {{ dictFormat(fee_type, scope.row.feeType) }}
        </template>
      </el-table-column>
      <el-table-column prop="feeName" label="费用名称" />
      <el-table-column prop="billingUnit" label="计费单位">
        <template #default="scope">
          {{ dictFormat('sys_unit', scope.row.billingUnit)}}
          {{ dictFormat(sys_unit, scope.row.billingUnit)}}
        </template>
      </el-table-column>
      <el-table-column prop="unitPrice" label="计费单价" />
@@ -133,7 +150,7 @@
      <el-table-column prop="actualAmount" label="实收金额" />
      <el-table-column prop="currency" label="币制">
        <template #default="scope">
          {{ dictFormat('sys_currency', scope.row.currency)}}
          {{ dictFormat(sys_currency, scope.row.currency)}}
        </template>
      </el-table-column>
      <el-table-column prop="createTime" label="费用登记时间" width="180" />
@@ -228,7 +245,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed } from 'vue';
import { ref, reactive, computed, watch } from 'vue';
import { ElMessage, type FormInstance } from 'element-plus';
import useCurrentInstance from '@/utils/useCurrentInstance'
import EntitySelector from '../EntitySelector/index.vue';
@@ -427,6 +444,29 @@
  mainForm.customerId = selectedCustomer.id; // 现在字段已声明,赋值有效
  isCustomerSelectVisibleIshow.value = false;
};
// 监听费用明细列表的变化,自动计算总额并保留2位小数
watch(
  () => receivableFeeDetailList.value,
  (newList) => {
    const total = newList.reduce((sum, item) => {
      // 确保取到的是数值,如果为空则默认为 0
      const amount = parseFloat(item.actualAmount) || 0;
      return sum + amount;
    }, 0);
    // 计算结果保留2位小数
    // parseFloat(...toFixed(2)) 是为了确保最后存入 mainForm 的是数字类型而非字符串
    const formattedTotal = parseFloat(total.toFixed(2));
    // 根据类型赋值
    if (typeText.value === '应收') {
      mainForm.receivableAmount = formattedTotal;
    } else {
      mainForm.payableAmount = formattedTotal;
    }
  },
  { deep: true, immediate: true } // immediate: true 确保初始加载数据时也能计算一次
);
defineExpose({ open, canceleClick });
</script>
ui/admin-ui3/src/components/GenerateBillDialog/index.vue
@@ -48,28 +48,28 @@
        <h3 class="section-title">账单明细</h3>
      </div>
      <el-table :data="detailList" border stripe height="300px" style="width: 100%">
        <el-table-column prop="systemNo" label="系统编号" width="120" />
        <el-table-column prop="sourceSystem" label="来源系统" width="120">
        <el-table-column prop="systemNo" align="center" label="系统编号" width="140" />
        <el-table-column prop="sourceSystem" align="center" label="来源系统" width="120">
          <template #default="scope">
            {{ dictFormat(sys_system, scope.row.sourceSystem) }}
          </template>
        </el-table-column><!-- sys_system -->
        <el-table-column prop="businessSector" label="业务板块" width="120">
        <el-table-column prop="businessSector" align="center" label="业务板块" width="120">
          <template #default="scope">
            {{ dictFormat(sys_business, scope.row.businessSector) }}
          </template>
        </el-table-column>
        <!-- sys_business -->
        <el-table-column prop="documentType" label="单据类型" width="120">
        <el-table-column prop="documentType" align="center" label="单据类型" width="120">
          <template #default="scope">
            {{ dictFormat(sys_receipts, scope.row.documentType) }}
          </template>
        </el-table-column><!-- sys_receipts -->
        <el-table-column prop="documentNo" label="单据编号" width="150" />
        <el-table-column prop="customerName" label="客户名称" width="150" />
        <el-table-column prop="projectName" label="项目名称" width="150" />
        <el-table-column prop="receivableAmount" label="应收金额" align="right" />
        <el-table-column prop="currency" label="币制" width="100">
        <el-table-column prop="documentNo" align="center" label="单据编号" width="150" />
        <el-table-column prop="customerName" align="center" label="客户名称" width="150" />
        <el-table-column prop="projectName" align="center" label="项目名称" width="150" />
        <el-table-column prop="receivableAmount" align="center" label="应收金额" />
        <el-table-column prop="currency" align="center" label="币制" width="100">
          <template #default="scope">
            {{ dictFormat(sys_currency, scope.row.currency) }}
          </template>
@@ -79,7 +79,7 @@
    <template #footer>
      <el-button @click="cancel">取消</el-button>
      <el-button type="primary" @click="handleConfirm" >确认生成</el-button>
      <el-button type="primary" @click="handleConfirm">确认生成</el-button>
    </template>
  </el-dialog>
</template>
@@ -127,15 +127,49 @@
const open = (data: any, selectionList: any[]) => {
  visible.value = true;
  if (data) {
    if (data) {
      // 假设 data 的结构就是 mainForm 需要的结构
      Object.assign(statistics.value, data);
      // 确保后端返回的明细字段名与此一致
      if (selectionList.length > 0) {
        detailList.value = [...selectionList];
      }
    }
    Object.assign(statistics.value, data);
    if (selectionList && selectionList.length > 0) {
      detailList.value = selectionList.flatMap(item => {
        if (!item.receivableAmountStr) return [item];
        // 1. 拆分多个币种字符串
        const amountParts = item.receivableAmountStr.trim().split(/\s+/);
        return amountParts.map(part => {
          // 2. 正则解析提取数值和币种名称
          // ([\d.]+) 匹配数字和小数点
          // ([\u4e00-\u9fa5]+) 匹配中文字符(币种)
          const match = part.match(/([\d.]+)([\u4e00-\u9fa5]+)/);
          let amount = item.receivableAmount; // 默认值
          let currencyValue = item.currency;   // 默认值
          if (match) {
            amount = parseFloat(match[1]); // 提取的数字
            const currencyName = match[2]; // 提取的币种文字,如 "港币"
            // 3. 根据提取的文字匹配字典中的 Value
            // 假设字典 sys_currency.value: 0 是人民币, 1 是港币 (请根据您实际字典值调整)
            if (currencyName.includes('人民币')) {
              currencyValue = 'RMB'; // 对应字典的人民币value
            } else if (currencyName.includes('港币')) {
              currencyValue = 'HKD'; // 对应字典的港币value
            }
          }
          // 4. 返回新对象,覆盖金额和币制
          return {
            ...item,
            receivableAmount: amount, // 赋值提取的数字
            currency: currencyValue,   // 赋值匹配到的字典ID
            receivableAmountStr: part  // 保持拆分后的文本
          };
        });
      });
    } else {
      detailList.value = [];
    }
  }
};
// 3. 确认生成按钮逻辑
ui/admin-ui3/src/components/NestedDetailDialog/index.vue
New file
@@ -0,0 +1,216 @@
<template>
    <el-dialog v-model="visible" :title="type === 'receivable' ? '应收账单费用明细' : '应付账单费用明细'" width="1300px"
        destroy-on-close>
        <div class="modal-content">
            <section class="info-section">
                <el-descriptions title="账单信息" :column="3" border class="mb-5">
                    <el-descriptions-item label="系统编号">{{ billInfo.systemNo }}</el-descriptions-item>
                    <el-descriptions-item label="账单名称">{{ billInfo.billName }}</el-descriptions-item>
                    <el-descriptions-item :label="type == 'receivable' ? '客户名称' : '供应商名称'">
                        {{ billInfo.customerName }}
                    </el-descriptions-item>
                    <el-descriptions-item label="单据数量">{{ billInfo.documentCount }}</el-descriptions-item>
                    <el-descriptions-item label="应结算金额">
                        <span class="text-bold">{{ billInfo.totalAmount }}</span>
                    </el-descriptions-item>
                    <el-descriptions-item label="币制">{{ billInfo.currency }}</el-descriptions-item>
                    <el-descriptions-item label="减免金额">{{ billInfo.discountAmount }}</el-descriptions-item>
                    <el-descriptions-item :label="type == 'receivable' ? '已收金额' : '已付金额'">
                        {{ billInfo.receivedAmount }}
                    </el-descriptions-item>
                    <el-descriptions-item :label="type == 'receivable' ? '待收金额' : '待付金额'">
                        <span class="text-danger">{{ billInfo.pendingAmount }}</span>
                    </el-descriptions-item>
                    <el-descriptions-item label="周期类型">{{ billInfo.periodType }}</el-descriptions-item>
                    <el-descriptions-item label="业务期间">
                        <span v-if="billInfo.businessStartDate">{{ billInfo.businessStartDate }}</span>
                        <span v-if="billInfo.businessStartDate && billInfo.businessEndDate"> ~ </span>
                        <span v-if="billInfo.businessEndDate">{{ billInfo.businessEndDate }}</span>
                    </el-descriptions-item>
                    <el-descriptions-item label="账单周期">
                        <span v-if="billInfo.billingStartDate">{{ billInfo.billingStartDate }}</span>
                        <span v-if="billInfo.billingStartDate && billInfo.billingEndDate"> ~ </span>
                        <span v-if="billInfo.billingEndDate">{{ billInfo.billingEndDate }}</span>
                    </el-descriptions-item>
                    <el-descriptions-item label="账单生成日期">{{ billInfo.billGenerateDate }}</el-descriptions-item>
                    <el-descriptions-item label="账单发送日期">{{ billInfo.billSendDate }}</el-descriptions-item>
                    <el-descriptions-item label="账单到期日期">{{ billInfo.billDueDate }}</el-descriptions-item>
                </el-descriptions>
            </section>
            <section class="table-section">
                <h3 class="section-title">费用明细</h3>
                <el-table :data="mainTableData" border stripe style="width: 100%" v-loading="loading">
                    <el-table-column prop="systemNo" label="系统编号" width="160" align="center" />
                    <el-table-column prop="sourceSystem" label="来源系统" align="center">
                        <template #default="scope">
                            {{ dictFormat(sys_system, scope.row.sourceSystem) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="businessSector" label="业务板块" align="center">
                        <template #default="scope">
                            {{ dictFormat(sys_business, scope.row.businessSector) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="documentType" label="单据类型" align="center">
                        <template #default="scope">
                            {{ dictFormat(sys_business, scope.row.documentType) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="documentNo" label="单据编号" width="160" align="center" />
                    <el-table-column prop="customerName" :label="type === 'receivable' ? '客户名称' : '供应商名称'"
                        min-width="150" align="center" />
                    <el-table-column prop="projectName" label="项目名称" align="center" />
                    <el-table-column prop="receivableAmount" :label="type === 'receivable' ? '应收金额' : '应付金额'"
                        align="center" />
                    <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
                        <template #default="scope">
                            <el-button type="text" @click="handleExamine(scope.row)">查看
                            </el-button>
                        </template>
                    </el-table-column>
                    <!-- <el-table-column prop="currency" label="币制" align="center" /> -->
                </el-table>
                <pagination v-show="pageF.total > 0" :total="pageF.total" v-model:page="queryParams.pageNum"
                    v-model:limit="queryParams.pageSize" @pagination="getDataList" />
            </section>
        </div>
        <template #footer>
            <el-button @click="visible = false">关 闭</el-button>
        </template>
    </el-dialog>
    <DetailModal ref="detailModalRef" />
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { getReceivableBillManagement } from "@/api/cwgl/receivableBillManagement";
import { listReceivableFeeManagement } from "@/api/cwgl/receivableFeeManagement";
import useCurrentInstance from "@/utils/useCurrentInstance";
import DetailModal from '@/components/DetailModal/index.vue';
import {
    getReceivableFeeManagement,
} from "@/api/cwgl/receivableFeeManagement";
const { proxy } = useCurrentInstance()
const { sys_system, sys_business, sys_receipts, sys_supplier, sys_whether_type, sys_currency } = proxy.useDict(
    'sys_system',
    'sys_business',
    'sys_receipts',
    'sys_supplier',
    'sys_whether_type', 'sys_currency'
)
const dictFormat = (dict: any, value: any) => {
    return proxy.selectDictLabel(dict, value);
}
const props = defineProps<{
    type: 'receivable' | 'payable'
}>();
const visible = ref(false);
const loading = ref(false);
const billInfo = ref<any>({});
const mainTableData = ref([]);
// 分页总数对象
const pageF = reactive({
    total: 0
});
// 查询参数对象(对应 pagination 组件的绑定)
const queryParams = reactive({
    pageNum: 1,
    pageSize: 10,
    relatedBillNo: ''
});
/** 获取表格数据列表 */
const getDataList = () => {
    if (!queryParams.relatedBillNo) return;
    loading.value = true;
    listReceivableFeeManagement(queryParams).then(res => {
        if (res.code === 200) {
            mainTableData.value = res.rows || [];
            pageF.total = res.total || 0;
        }
    }).finally(() => {
        loading.value = false;
    });
};
/** 打开弹窗主入口 */
const open = (data: any) => {
    // 重置分页
    queryParams.pageNum = 1;
    queryParams.relatedBillNo = '';
    mainTableData.value = [];
    pageF.total = 0;
    // 获取账单详情
    fetchBillDetail(data.id);
};
/** 获取账单顶部详情信息 */
const fetchBillDetail = (id: string | number) => {
    getReceivableBillManagement(id).then((response) => {
        if (response.code == 200) {
            billInfo.value = response.data;
            queryParams.relatedBillNo = response.data.systemNo;
            visible.value = true;
            // 详情拿到后,加载表格
            getDataList();
        }
    });
};
const detailModalRef = ref(null);
const handleExamine = (row) => {
    getReceivableFeeManagement(row.id).then((res) => {
        if (res.code === 200) {
            detailModalRef.value.open(res.data);
        }
    });
};
defineExpose({ open });
</script>
<style scoped>
.mb-5 {
    margin-bottom: 20px;
}
.section-title {
    font-size: 16px;
    font-weight: bold;
    margin: 15px 0;
    padding-left: 10px;
    border-left: 4px solid #409eff;
}
.text-bold {
    font-weight: bold;
}
.text-danger {
    color: #f56c6c;
    font-weight: bold;
}
/* 深度适配样式 */
:deep(.el-descriptions__label) {
    width: 140px;
    background-color: #f5f7fa !important;
}
::v-deep .el-descriptions__body .el-descriptions__table.is-bordered .el-descriptions__cell {
    border: var(--el-descriptions-table-border);
    padding: 8px 11px;
    width: 200px;
}
</style>
ui/admin-ui3/src/components/OperationLogModal/index.vue
@@ -1,13 +1,16 @@
<template>
    <el-dialog v-model="visible" title="操作日志" width="1100px" destroy-on-close>
    <el-dialog v-model="visible" title="操作日志" width="1000px" destroy-on-close>
        <div class="log-container">
            <avue-crud ref="crudRef" :data="tableData" :option="tableOption" :table-loading="loading">
                <!-- <template #type="{ row }">
                    <el-tag :type="getTypeTag(row.type)">
                        {{ row.typeDesc || row.type }}
                    </el-tag>
                </template> -->
            </avue-crud>
            <el-table v-if="logModalRef == 'listReceivableFeeManagementLog'" v-loading="loading" :data="tableData" border stripe style="width: 100%" max-height="500px">
                <el-table-column prop="operator" label="操作人" width="120" />
                <el-table-column prop="createTime" label="操作时间" width="180" />
                <el-table-column prop="operationDesc" label="操作描述" show-overflow-tooltip />
            </el-table>
             <el-table v-if="logModalRef == 'listReceivableBillManagementLog'" v-loading="loading" :data="tableData" border stripe style="width: 100%" max-height="500px">
                <el-table-column prop="createBy" label="操作人" width="120" />
                <el-table-column prop="createTime" label="操作时间" width="180" />
                <el-table-column prop="operation" label="操作描述" show-overflow-tooltip />
            </el-table>
        </div>
        <template #footer>
            <el-button @click="visible = false">关 闭</el-button>
@@ -17,70 +20,21 @@
<script setup lang="ts">
import { ref } from 'vue';
  import { listReceivableFeeManagementLog} from "@/api/cwgl/receivableFeeManagementLog";
// 如果需要调用接口获取数据,保留此引入
// import { listReceivableFeeManagementLog } from "@/api/cwgl/receivableFeeManagementLog";
const visible = ref(false);
const loading = ref(false);
const tableData = ref([]);
const tableOption = {
    header: false,
    tip: false,           // 隐藏“当前已选择”提示
    addBtn: false,
    editBtn: false,
    delBtn: false,
    menu: false,          // 隐藏操作列
    border: true,
    stripe: true,
    column: [
        {
            label: '操作人',
            prop: 'operator',
            width: 120
        },
        {
            label: '操作时间',
            prop: 'operationTime',
            width: 180
        },
        // {
        //     label: '操作类型',
        //     prop: 'type',
        //     slot: true,       // 开启自定义插槽用于展示 Tag
        //     width: 120
        // },
        {
            label: '操作描述',
            prop: 'operationDesc',
            overHidden: true  // 内容过长时显示省略号
        },
          {
            label: '记录创建时间',
            prop: 'createTime',
            overHidden: true  // 内容过长时显示省略号
        }
    ]
};
// 根据类型返回不同的 Tag 颜色
const getTypeTag = (type: string) => {
    const map: Record<string, string> = {
        'add': 'success',
        'edit': 'warning',
        'del': 'danger',
        'import': 'info',
        'export': 'primary'
    };
    return map[type] || '';
};
const logModalRef = ref();
// 暴露给外部调用的打开方法
const open = (logs: any[]) => {
const open = (logs: any[],apiString: string) => {
    visible.value = true;
    loading.value = true;
    // 模拟异步加载
    console.log(apiString);
    logModalRef.value = apiString;
    // 模拟加载动画
    setTimeout(() => {
        tableData.value = logs || [];
        loading.value = false;
@@ -94,4 +48,9 @@
.log-container {
    padding: 10px 0;
}
/* 调整表格内边距,使其更美观 */
:deep(.el-table) {
    margin-top: 10px;
}
</style>
ui/admin-ui3/src/components/Pagination/index.vue
New file
@@ -0,0 +1,104 @@
<template>
  <div :class="{ 'hidden': hidden }" class="pagination-container">
    <el-pagination
      :background="background"
      v-model:current-page="currentPage"
      v-model:page-size="pageSize"
      :layout="layout"
      :page-sizes="pageSizes"
      :pager-count="pagerCount"
      :total="total"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  </div>
</template>
<script setup lang="ts">
import { scrollTo } from '@/utils/scroll-to'
import {computed} from "vue";
const props = defineProps({
  total: {
    required: true,
    type: Number
  },
  page: {
    type: Number,
    default: 1
  },
  limit: {
    type: Number,
    default: 10
  },
  pageSizes: {
    type: Array,
    default() {
      return [10, 20, 30, 50]
    }
  },
  // 移动端页码按钮的数量端默认值5
  pagerCount: {
    type: Number,
    default: document.body.clientWidth < 992 ? 5 : 7
  },
  layout: {
    type: String,
    default: 'total, sizes, prev, pager, next, jumper'
  },
  background: {
    type: Boolean,
    default: true
  },
  autoScroll: {
    type: Boolean,
    default: true
  },
  hidden: {
    type: Boolean,
    default: false
  }
})
const emit = defineEmits(['update:page','update:limit','pagination']);
const currentPage = computed({
  get() {
    return props.page
  },
  set(val) {
    emit('update:page', val)
  }
})
const pageSize = computed({
  get() {
    return props.limit
  },
  set(val){
    emit('update:limit', val)
  }
})
function handleSizeChange(val:any) {
  emit('pagination', { page: currentPage.value, limit: val })
  if (props.autoScroll) {
    scrollTo(0, 800)
  }
}
function handleCurrentChange(val:any) {
  emit('pagination', { page: val, limit: pageSize.value })
  if (props.autoScroll) {
    scrollTo(0, 800)
  }
}
</script>
<style scoped>
.pagination-container {
  background: #fff;
  padding: 32px 16px;
  position: relative;
}
.pagination-container.hidden {
  display: none;
}
</style>
ui/admin-ui3/src/components/SettlementDialog/index.vue
New file
@@ -0,0 +1,367 @@
<template>
    <el-dialog v-model="visible" :title="type === 'receivable' ? '应收账单结算' : '应付账单结算'" width="1200px" destroy-on-close
        @closed="handleClosed">
        <el-descriptions title="账单信息" :column="3" border class="mb-5">
            <el-descriptions-item label="系统编号">{{ billInfo.systemNo }}</el-descriptions-item>
            <el-descriptions-item label="账单名称">{{ billInfo.billName }}</el-descriptions-item>
            <el-descriptions-item v-if="type == 'receivable'" label="客户名称">{{ billInfo.customerName
                }}</el-descriptions-item>
            <el-descriptions-item v-if="type == 'payable'" label="供应商名称">{{ billInfo.customerName
                }}</el-descriptions-item>
            <el-descriptions-item label="单据数量">{{ billInfo.documentCount }}</el-descriptions-item>
            <el-descriptions-item label="应结算金额">
                <span class="text-bold">{{ billInfo.totalAmount }}</span>
            </el-descriptions-item>
            <el-descriptions-item label="币制">{{ billInfo.currency }}</el-descriptions-item>
            <el-descriptions-item label="减免金额">{{ billInfo.discountAmount }}</el-descriptions-item>
            <el-descriptions-item v-if="type == 'receivable'" label="已收金额">{{ billInfo.receivedAmount
                }}</el-descriptions-item>
            <el-descriptions-item v-if="type == 'payable'" label="已付金额">{{ billInfo.receivedAmount
                }}</el-descriptions-item>
            <el-descriptions-item v-if="type == 'receivable'" label="待收金额">
                <span class="text-danger">{{ billInfo.pendingAmount }}</span>
            </el-descriptions-item>
            <el-descriptions-item v-if="type == 'payable'" label="待付金额">
                <span class="text-danger">{{ billInfo.pendingAmount }}</span>
            </el-descriptions-item>
            <el-descriptions-item label="周期类型">
                {{ billInfo.periodType }}
            </el-descriptions-item>
            <el-descriptions-item label="业务期间">
                <span v-if="billInfo.businessEndDate !== null">{{ billInfo.businessEndDate + '-' }}</span>
                <span v-if="billInfo.businessStartDate !== null">
                    {{ billInfo.businessStartDate }}
                </span>
            </el-descriptions-item>
            <el-descriptions-item label="账单周期">
                <span v-if="billInfo.billingStartDate !== null">{{ billInfo.billingStartDate + '-' }}</span>
                <span v-if="billInfo.billingEndDate !== null">
                    {{ billInfo.billingEndDate }}
                </span>
            </el-descriptions-item>
            <el-descriptions-item label="账单生成日期">{{ billInfo.billGenerateDate }}</el-descriptions-item>
            <el-descriptions-item label="账单发送日期">{{ billInfo.billSendDate }}</el-descriptions-item>
            <el-descriptions-item label="账单到期日期">{{ billInfo.billDueDate }}</el-descriptions-item>
        </el-descriptions>
        <h3 class="section-title">本次结算信息</h3>
        <el-form ref="formRef" :model="formData" :rules="rules" label-width="110px" label-position="right">
            <el-row :gutter="20">
                <el-col :span="8">
                    <el-form-item label="结算方式" prop="settlementMethod">
                        <el-select v-model="formData.settlementMethod" placeholder="请选结算方式" clearable>
                            <el-option v-for="dict in sys_clearing_form" :key="dict.value" :label="dict.label"
                                :value="dict.value" />
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="8" v-if="type == 'receivable'">
                    <el-form-item label="客户银行账户" prop="customerBankAccount">
                        <el-input v-model="formData.customerBankAccount" @click="openBankDialog('customer')" readonly
                            placeholder="点击选择">
                            <template #append>
                                <el-button icon="Search" @click="openBankDialog('customer')" />
                            </template>
                        </el-input>
                    </el-form-item>
                </el-col>
                <!-- <el-col :span="8" v-if="type == 'payable'">
                    <el-form-item label="付款银行账户" prop="customerAccount">
                        <el-input v-model="formData.customerAccount" placeholder="点击选择">
                            <template #append>
                                <el-button icon="Search" @click="handleSelectAccount('customer')" />
                            </template>
                        </el-input>
                    </el-form-item>
                </el-col> -->
                <el-col :span="8" v-if="type == 'receivable'">
                    <el-form-item label="客户开户行">
                        <el-input v-model="formData.customerBank" disabled />
                    </el-form-item>
                </el-col>
                <!-- <el-col :span="8" v-if="type == 'payable'">
                    <el-form-item label="付款账户开户行">
                        <el-input v-model="formData.customerBank" disabled />
                    </el-form-item>
                </el-col> -->
            </el-row>
            <el-row :gutter="20">
                <el-col :span="8">
                    <el-form-item label="收款银行账户" prop="receivingBankAccount">
                        <el-input v-model="formData.receivingBankAccount" @click="openBankDialog('receiving')" readonly
                            placeholder="请输入收款银行账户">
                            <template #append>
                                <el-button icon="Search" @click="openBankDialog('receiving')" />
                            </template>
                        </el-input>
                    </el-form-item>
                </el-col>
                <el-col :span="8">
                    <el-form-item label="收款账户开户行">
                        <el-input v-model="formData.receivingBank" disabled />
                    </el-form-item>
                </el-col>
                <!-- 少 -->
                <el-col :span="8" v-if="type == 'receivable'">
                    <el-form-item label="收款人">
                        <el-input v-model="formData.operator"  />
                    </el-form-item>
                </el-col>
                <!-- <el-col :span="8" v-if="type == 'payable'">
                    <el-form-item label="收款银行账户">
                        <el-input v-model="formData.operator" disabled />
                    </el-form-item>
                </el-col> -->
            </el-row>
            <el-row :gutter="20">
                <el-col :span="8" v-if="type == 'receivable'">
                    <el-form-item label="收款日期" prop="receiptDate">
                        <el-date-picker v-model="formData.receiptDate" type="date" placeholder="请选择日期"
                            style="width: 100%" value-format="YYYY-MM-DD" />
                    </el-form-item>
                </el-col>
                <!-- <el-col :span="8" v-if="type == 'payable'">
                    <el-form-item label="付款日期" prop="settleDate">
                        <el-date-picker v-model="formData.settleDate" type="date" placeholder="请选择日期"
                            style="width: 100%" value-format="YYYY-MM-DD" />
                    </el-form-item>
                </el-col> -->
                <el-col :span="8" v-if="type == 'receivable'">
                    <el-form-item label="收款金额" prop="receiptAmount">
                        <el-input-number v-model="formData.receiptAmount" :precision="2" :min="0" style="width: 100%"
                            @change="calcRemaining" />
                    </el-form-item>
                </el-col>
                <!-- <el-col :span="8" v-if="type == 'payable'">
                    <el-form-item label="付款金额" prop="settleAmount">
                        <el-input-number v-model="formData.settleAmount" :precision="2" :step="0.1" :min="0"
                            style="width: 100%" @change="calcRemaining" />
                    </el-form-item>
                </el-col> -->
                <el-col :span="8" v-if="type == 'receivable'">
                    <el-form-item label="收款后待收金额">
                        <el-input v-model="formData.remainingPendingAmount" disabled class="remaining-input" />
                    </el-form-item>
                </el-col>
                <!-- <el-col :span="8" v-if="type == 'payable'">
                    <el-form-item label="收款后待付金额">
                        <el-input v-model="formData.remainingAmount" disabled class="remaining-input" />
                    </el-form-item>
                </el-col> -->
            </el-row>
        </el-form>
        <template #footer>
            <el-button @click="openIshpw">取消</el-button>
            <el-button type="primary" :loading="submitting" @click="handleSubmit">确定</el-button>
        </template>
    </el-dialog>
    <bankCardData v-model:visible="bankDialogVisible"
        :default-selected-id="currentSelectType === 'customer' ? formData.bankAccountId : formData.receivingBankAccountId"
        :mode="currentSelectType === 'customer' ? 'config' : 'internal'" @confirm="handleBankConfirm" />
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import useCurrentInstance from "@/utils/useCurrentInstance";
import bankCardData from "../bankCardData/index.vue";
const props = defineProps<{
    type: 'receivable' | 'payable' // 类型:应收或应付
}>()
const { proxy } = useCurrentInstance();
// 获取所需字典数据
const {
    sys_clearing_form
} = proxy.useDict(
    'sys_clearing_form'
);
const emit = defineEmits(['success'])
const visible = ref(false)
const submitting = ref(false)
const formRef = ref()
// 账单详情数据
const billInfo = ref<any>({})
// 表单数据
const formData = reactive({
    settlementMethod: '', // 确保名称与 prop 一致
    customerBankAccount: '',
    customerBank: '',
    receivingBankAccount: '',
    receivingBank: '',
    receivingBankAccountId: '',
    operator: 'admin',
    // 收款
    receiptDate: '',
    receiptAmount: 0,
    remainingPendingAmount: 0,
    // 付款 (备用)
    settleDate: '',
    settleAmount: 0,
    bankAccountId: ''
})
// 校验规则
const rules = {
    // 结算方式
    settlementMethod: [{ required: true, message: '请选择结算方式', trigger: 'change' }],
    // 收款相关校验 (type === 'receivable')
    receiptDate: [{ required: true, message: '请选择收款日期', trigger: 'change' }],
    receiptAmount: [
        { required: true, message: '请输入收款金额', trigger: 'blur' },
        { type: 'number', min: 0.01, message: '金额必须大于0', trigger: 'blur' }
    ],
    // 付款相关校验 (type === 'payable' - 如果你后续取消注释的话)
    settleDate: [{ required: true, message: '请选择付款日期', trigger: 'change' }],
    settleAmount: [
        { required: true, message: '请输入付款金额', trigger: 'blur' },
        { type: 'number', min: 0.01, message: '金额必须大于0', trigger: 'blur' }
    ]
}
// 打开弹窗
const open = (row: any) => {
    visible.value = true
    billInfo.value = { ...row }
   // 初始化本次收款金额:默认填入全部待收金额(用户可改)
    formData.receiptAmount = row.pendingAmount || 0;
    formData.settleAmount = row.pendingAmount || 0
    calcRemaining()
}
// 计算剩余待收/待付
const calcRemaining = () => {
    // 1. 获取原始待收金额 (从 billInfo 中获取)
    const pending = Number(billInfo.value.pendingAmount || 0);
    // 2. 获取当前输入的收款金额 (注意:你 HTML 中绑定的是 receiptAmount)
    const current = Number(formData.receiptAmount || 0);
    // 3. 计算差值并保留 2 位小数
    // 使用 Number().toFixed(2) 确保精度,再转回 Number 以便后续逻辑使用
    formData.remainingPendingAmount = Number((pending - current).toFixed(2));
};
// 弹窗显示状态
const bankDialogVisible = ref(false);
// 定义一个标识,记录当前是谁在选银行
const currentSelectType = ref<'customer' | 'receiving'>('customer');
// 修改打开弹窗的方法,传入标识
const openBankDialog = (type: 'customer' | 'receiving') => {
    currentSelectType.value = type;
    bankDialogVisible.value = true;
};
const openIshpw = () => {
    visible.value = false
}
// 处理确认回调
const handleBankConfirm = (data: any) => {
    if (currentSelectType.value === 'customer') {
        // 填充客户银行信息
        formData.bankAccountId = data.id;
        formData.customerBankAccount = data.accountNo;
        formData.customerBank = data.bankName;
    } else {
        // 填充收款银行信息 (对应你代码里的 receivingBankAccount 等)
        formData.receivingBankAccountId = data.id; // 建议在 formData 增加此 ID 字段用于回显
        formData.receivingBankAccount = data.accountNo;
        formData.receivingBank = data.bankName;
    }
};
// 提交
const handleSubmit = async () => {
    await formRef.value.validate()
    submitting.value = true
    try {
        // 模拟API调用
        // console.log('提交数据:', { ...formData, billId: billInfo.value.id, type: props.type })
        // await new Promise(resolve => setTimeout(resolve, 1000))
        emit('success',formData)
        // visible.value = false
    } catch (error) {
        console.error(error)
    } finally {
        submitting.value = false
    }
}
// 4. 修改重置逻辑
const handleClosed = () => {
    formRef.value?.resetFields()
    Object.assign(formData, {
        settlementMethod: '',
        receiptDate: '',
        receiptAmount: 0,
        customerBankAccount: '',
        customerBank: '',
        receivingBankAccount: '',
        receivingBank: '',
        // ... 其他需要清空的字段
    })
    billInfo.value = {}
}
defineExpose({ open,openIshpw })
</script>
<style scoped>
.mb-5 {
    margin-bottom: 20px;
}
.section-title {
    font-size: 16px;
    font-weight: bold;
    margin: 20px 0;
    padding-left: 10px;
    border-left: 4px solid #409eff;
}
.text-bold {
    font-weight: bold;
    font-size: 15px;
}
.text-danger {
    color: #f56c6c;
    font-weight: bold;
}
.remaining-input :deep(.el-input__inner) {
    color: #e6a23c;
    font-weight: bold;
}
:deep(.el-descriptions__label) {
    width: 120px;
    background-color: #f5f7fa !important;
}
::v-deep .el-descriptions__body .el-descriptions__table.is-bordered .el-descriptions__cell {
    border: var(--el-descriptions-table-border);
    padding: 8px 11px;
    width: 200px;
}
</style>
ui/admin-ui3/src/components/bankCardCate/index.vue
@@ -6,14 +6,37 @@
        <el-form ref="formRef" :model="form" :rules="formRules" label-width="140px" size="default"
            class="form-container">
            <!-- 关联客户(带搜索图标) -->
            <el-form-item label="关联客户" prop="customerName">
                <el-input v-model="form.customerName" placeholder="请选择关联客户" readonly suffix-icon="Search"
                    @click="openCustomerSelectDialog" class="search-input" />
            <el-form-item label="关联客户" v-if="ishowBank" prop="customerName">
                <!-- <el-input v-model="form.customerName" placeholder="请选择关联客户" readonly suffix-icon="Search"
                    @click="openCustomerSelectDialog" class="search-input" /> -->
                   <el-input v-model="form.customerName" placeholder="请选择关联客户" readonly class="search-input"
                    @click="openCustomerSelectDialog">
                    <template #suffix>
                        <el-icon class="el-input__icon" style="cursor: pointer;" @click="openCustomerSelectDialog">
                            <Search />
                        </el-icon>
                    </template>
                </el-input>
            </el-form-item>
            <el-form-item label="关联主体" v-if="!ishowBank" prop="customerName">
                <el-input v-model="form.customerName" placeholder="请选择关联主体" readonly class="search-input"
                    @click="subjectPerationSelectDialog">
                    <template #suffix>
                        <el-icon class="el-input__icon" style="cursor: pointer;" @click="subjectPerationSelectDialog">
                            <Search />
                        </el-icon>
                    </template>
                </el-input>
            </el-form-item>
            <!-- 抬头公司 -->
            <el-form-item label="账号编号" prop="accountNo">
            <el-form-item label="账号编号" v-if="ishowBank" prop="accountNo">
                <el-input v-model="form.accountNo" placeholder="请输入账号编号" />
            </el-form-item>
            <el-form-item label="银行账号" v-if="!ishowBank" prop="accountNo">
                <el-input v-model="form.accountNo" placeholder="请输入银行账号" />
            </el-form-item>
            <!-- 统一社会信用代码 -->
@@ -21,7 +44,7 @@
                <el-input v-model="form.accountName" placeholder="请输入户名" maxlength="18" />
            </el-form-item>
                 <!-- 开户银行名称 -->
            <!-- 开户银行名称 -->
            <el-form-item label="银行名称" prop="bankName">
                <el-input v-model="form.bankName" placeholder="请输入开户银行名称" />
            </el-form-item>
@@ -30,33 +53,39 @@
                <el-input v-model="form.branchName" placeholder="请输入支行名称" />
            </el-form-item>
            <el-form-item label="账号类型" prop="accountType">
            <el-form-item label="账号类型" v-if="ishowBank" prop="accountType">
                <el-select v-model="form.accountType" placeholder="请选账号类型" clearable>
                    <el-option v-for="dict in sys_invoice_type" :key="dict.value" :label="dict.label"
                        :value="dict.value" />
                </el-select>
            </el-form-item>
                  <el-form-item label="币种" prop="currency">
                <el-select v-model="form.currency" placeholder="请选币种" clearable>
                    <el-option v-for="dict in sys_currency" :key="dict.value" :label="dict.label"
              <el-form-item label="账号类型" v-if="!ishowBank" prop="accountType">
                <el-select v-model="form.accountType" placeholder="请选账号类型" clearable>
                    <el-option v-for="dict in sys_internal_type" :key="dict.value" :label="dict.label"
                        :value="dict.value" />
                </el-select>
            </el-form-item>
            <el-form-item label="币种" prop="currency">
                <el-select v-model="form.currency" placeholder="请选币种" clearable>
                    <el-option v-for="dict in sys_currency" :key="dict.value" :label="dict.label" :value="dict.value" />
                </el-select>
            </el-form-item>
                     <el-form-item label="账户状态" prop="status">
            <el-form-item label="账户状态" prop="status">
                <el-select v-model="form.status" placeholder="请选账户状态" clearable>
                    <el-option v-for="dict in sys_bank_type" :key="dict.value" :label="dict.label"
                        :value="dict.value" />
                </el-select>
            </el-form-item>
        </el-form>
        <!-- 底部按钮 -->
@@ -69,12 +98,10 @@
    </el-dialog>
    <!-- 关联客户选择弹窗 -->
    <CustomerSelectDialog
        :visible="isCustomerSelectVisibleIshow"
        :default-selected-id="form.customerId"
        @confirm="handleCustomerSelect"
        @close="isCustomerSelectVisibleIshow = false"
    />
    <CustomerSelectDialog :visible="isCustomerSelectVisibleIshow" :default-selected-id="form.customerId"
        @confirm="handleCustomerSelect" @close="isCustomerSelectVisibleIshow = false" />
    <subjectPeration :visible="subjectPerationShow" :default-selected-id="form.customerId"
        @confirm="subjectPerationSelect" @close="subjectPerationShow = false" />
</template>
<script setup lang="ts">
@@ -83,11 +110,21 @@
import { ElMessage } from 'element-plus';
// 引入客户选择弹窗组件
import CustomerSelectDialog from '../CustomerSelectDialog/index';
import subjectPeration from '../subjectPeration/index';
import useCurrentInstance from "@/utils/useCurrentInstance";
const { proxy } = useCurrentInstance();
const { sys_invoice_type,sys_currency,sys_bank_type } = proxy.useDict('sys_invoice_type','sys_currency','sys_bank_type');
const { sys_invoice_type, sys_currency, sys_bank_type,sys_internal_type } = proxy.useDict('sys_invoice_type', 'sys_currency', 'sys_bank_type',
    'sys_internal_type'
);
const props = defineProps({
    ishowBank: {
        type: Boolean,
        default: true
    },
});
// 定义表单数据类型(新增customerId字段,避免赋值时报错)
interface InvoiceForm {
    customerId?: string | number; // 新增:客户ID(用于回显选中)
@@ -120,12 +157,12 @@
    accountType: '',
    bankName: '',
    branchName: '',
     id:'',
    id: '',
    invoiceOperatingLicenseAddress: '',
    invoiceOperatingLicensePhone: '',
    invoiceOperatingLicenseEmail: '',
    currency:'',
    status:'',
    currency: '',
    status: '',
});
// 表单校验规则
@@ -158,14 +195,14 @@
// 打开弹窗(供父组件调用,修复回显逻辑)
const openDialog = (data?: Partial<InvoiceForm>) => {
    dialogVisible.value = true;
    // 先重置表单,避免旧数据残留
    nextTick(() => {
        formRef.value?.resetFields();
        // 有回显数据时,逐个赋值(核心修复:避免整体赋值form = data)
        if (data && Object.keys(data).length > 0) {
           // 遍历data的所有字段,赋值到form(仅覆盖对应字段)
            // 遍历data的所有字段,赋值到form(仅覆盖对应字段)
            Object.assign(form, data);
            // 清空表单校验状态
            formRef.value?.clearValidate();
@@ -179,12 +216,12 @@
                accountType: '',
                bankName: '',
                branchName: '',
                id:'',
                id: '',
                invoiceOperatingLicenseAddress: '',
                invoiceOperatingLicensePhone: '',
                invoiceOperatingLicenseEmail: '',
                 currency:'',
                 status:''
                currency: '',
                status: ''
            });
        }
    });
@@ -201,7 +238,16 @@
    form.customerId = selectedCustomer.id; // 现在字段已声明,赋值有效
    isCustomerSelectVisibleIshow.value = false;
};
const subjectPerationShow = ref(false);
const subjectPerationSelectDialog = () => {
    subjectPerationShow.value = true;
};
const subjectPerationSelect = (selectedCustomer) => {
    form.customerName = selectedCustomer.customerFullName;
    form.customerId = selectedCustomer.id; // 现在字段已声明,赋值有效
    isCustomerSelectVisibleIshow.value = false;
};
// 提交表单(修复校验逻辑 + 关闭弹窗)
const handleSubmit = async () => {
    if (!formRef.value) return;
@@ -241,13 +287,41 @@
<style scoped lang="scss">
.form-container {
    padding: 10px 0;
    :deep(.el-form-item) { margin-bottom: 18px; }
    :deep(.el-form-item) {
        margin-bottom: 18px;
    }
}
.search-input {
    :deep(.el-input__inner) { cursor: pointer; background-color: #f8f9fa; }
    :deep(.el-icon-search) { color: #409eff; }
    :deep(.el-input__inner) {
        cursor: pointer;
        background-color: #f8f9fa;
    }
    :deep(.el-icon-search) {
        color: #409eff;
    }
}
.dialog-footer { text-align: right; }
.dialog-footer {
    text-align: right;
}
/*  */
/* 使用 :deep() 穿透组件样式 */
:deep(.search-input .el-input__wrapper) {
  background-color: #ffffff !important; /* 强制背景为白色 */
  box-shadow: 0 0 0 1px var(--el-input-border-color, #dcdfe6) inset; /* 保持边框 */
}
/* 针对 readonly 状态下的特定处理(如果需要更精确控制) */
:deep(.search-input .el-input__inner[readonly]) {
  background-color: #ffffff !important;
  cursor: pointer; /* 既然是点击弹出,建议鼠标手势设为 pointer */
}
/* 如果你还想去掉鼠标滑过时的灰色感(如果有的话) */
:deep(.search-input .el-input__wrapper:hover) {
  background-color: #ffffff !important;
}
</style>
ui/admin-ui3/src/components/bankCardData/index.vue
New file
@@ -0,0 +1,220 @@
<template>
    <el-dialog v-model="dialogVisible" :title="mode === 'internal' ? '请选择内部银行' : '请选择关联客户'" width="85%" destroy-on-close
        @close="handleClose" append-to-body>
        <div class="search-bar">
            <el-form inline :model="queryParams" class="search-form" label-width="80px">
                <el-form-item v-if="mode === 'config'" label="客户名称:">
                    <el-input v-model="queryParams.customerName" placeholder="请输入客户名称" clearable style="width: 180px" />
                </el-form-item>
                <el-form-item label="账号编号:">
                    <el-input v-model="queryParams.accountNo" placeholder="请输入账号编号" clearable style="width: 180px" />
                </el-form-item>
                <el-form-item label="户名:">
                    <el-input v-model="queryParams.accountName" placeholder="请输入户名" clearable style="width: 180px" />
                </el-form-item>
                <el-form-item label="账号类型:">
                    <el-select v-model="queryParams.accountType" placeholder="请选择类型" clearable style="width: 150px">
                        <el-option v-for="dict in sys_account_type" :key="dict.value" :label="dict.label"
                            :value="dict.value" />
                    </el-select>
                </el-form-item>
                <el-form-item class="search-btns">
                    <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
                    <el-button plain icon="RefreshLeft" @click="handleReset">清空</el-button>
                </el-form-item>
            </el-form>
        </div>
        <el-table ref="customerTableRef" :data="customerList" border size="small" style="width: 100%"
            highlight-current-row row-key="id" @current-change="handleRowSelect" class="custom-highlight-table">
            <el-table-column v-if="mode === 'config'" prop="customerName" align="center" label="客户名称" min-width="120"
                show-overflow-tooltip />
            <el-table-column prop="accountNo" label="账号编号" align="center" show-overflow-tooltip />
            <el-table-column prop="accountName" label="户名" align="center" />
            <el-table-column prop="bankName" label="银行名称" align="center" show-overflow-tooltip />
            <el-table-column prop="branchName" label="支行名称" align="center" show-overflow-tooltip />
            <el-table-column prop="accountType" label="账号类型" align="center">
                <template #default="scope">
                    {{ dictFormat(sys_account_type, scope.row.accountType) }}
                </template>
            </el-table-column>
            <el-table-column prop="currency" label="币种" align="center">
                <template #default="scope">
                    {{ dictFormat(sys_currency, scope.row.currency) }}
                </template>
            </el-table-column>
            <el-table-column prop="status" label="账户状态" align="center">
                <template #default="scope">
                    {{ dictFormat(sys_bank_type, scope.row.status) }}
                </template>
            </el-table-column>
        </el-table>
        <div class="pagination-container">
            <pagination v-show="pageF.total > 0" :total="pageF.total" v-model:page="queryParams.pageNum"
                v-model:limit="queryParams.pageSize" @pagination="getDataList" />
        </div>
        <template #footer>
            <div class="dialog-footer">
                <el-button @click="handleClose">取消</el-button>
                <el-button type="primary"  @click="handleConfirm">确定</el-button>
            </div>
        </template>
    </el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, watch, nextTick } from 'vue';
import { ElMessage } from 'element-plus';
import useCurrentInstance from "@/utils/useCurrentInstance";
import { listBankAccountConfig } from "@/api/cwgl/bankAccountConfig";
// import { listInternalBank } from "@/api/cwgl/internalBank"; // 假设这是你的内部银
import {  listBankConfig,} from "@/api/cwgl/bankConfig";
const { proxy } = useCurrentInstance();
const { sys_currency, sys_account_type, sys_bank_type } = proxy.useDict('sys_currency', 'sys_account_type', 'sys_bank_type');
const dictFormat = (dict: any, value: any) => {
    return proxy.selectDictLabel(dict, value);
}
const props = defineProps({
    visible: { type: Boolean, default: false },
    defaultSelectedId: { type: [String, Number], default: '' },
    mode: { type: String, default: 'config' }
});
const emit = defineEmits(['confirm', 'close', 'update:visible']);
const queryParams = reactive({
    pageNum: 1,
    pageSize: 10,
    customerName: '',
    accountNo: '',
    accountName: '',
    accountType: '',
});
const pageF = reactive({ total: 0 });
const dialogVisible = ref(false);
const customerList = ref([]);
const selectedRow = ref(null);
const customerTableRef = ref();
// 获取数据逻辑
// 2. 修改获取数据逻辑 getDataList
const getDataList = async () => {
    try {
        // 核心逻辑:根据 mode 切换 API 方法
        const apiMethod = props.mode === 'internal' ? listBankConfig : listBankAccountConfig;
        const res = await apiMethod(queryParams);
        if (res.code === 200) {
            customerList.value = res.rows;
            pageF.total = res.total;
            if (props.defaultSelectedId) {
                syncSelection();
            }
        }
    } catch (err) {
        console.error(err);
    }
};
// 核心选中同步逻辑
const syncSelection = () => {
    nextTick(() => {
        if (!props.defaultSelectedId || customerList.value.length === 0) return;
        const row = customerList.value.find(item => String(item.id) === String(props.defaultSelectedId));
        if (row) {
            selectedRow.value = row;
            // 调用 Element Plus 原生方法设置高亮行
            customerTableRef.value?.setCurrentRow(row);
        }
    });
};
const handleSearch = () => {
    queryParams.pageNum = 1;
    getDataList();
};
const handleReset = () => {
    Object.keys(queryParams).forEach(key => {
        if (key !== 'pageNum' && key !== 'pageSize') queryParams[key] = '';
    });
    queryParams.pageNum = 1;
    handleSearch();
};
const handleRowSelect = (val: any) => {
    selectedRow.value = val;
};
const handleConfirm = () => {
    if (!selectedRow.value) return ElMessage.warning('请选择一行数据');
    emit('confirm', { ...selectedRow.value });
    handleClose();
};
const handleClose = () => {
    emit('update:visible', false);
    emit('close');
};
// 监听弹窗显示,触发数据加载和自动选中
watch(() => props.visible, (newVal) => {
    dialogVisible.value = newVal;
    if (newVal) {
        handleSearch();
    } else {
        selectedRow.value = null;
        customerTableRef.value?.setCurrentRow(null);
    }
});
</script>
<style scoped lang="scss">
.search-bar {
    background: #fdfdfd;
    padding: 15px 10px 5px;
    border-bottom: 1px solid #eee;
    margin-bottom: 15px;
    .search-btns {
        margin-left: 10px;
    }
}
.pagination-container {
    margin-top: 15px;
    display: flex;
    justify-content: flex-end;
}
/* 核心:仿照图片中的淡绿色选中效果 */
.custom-highlight-table {
    :deep(.el-table__body tr.current-row > td) {
        background-color: #e1f3d8 !important;
        /* 图片中的淡绿色 */
        color: #606266;
    }
    /* 悬浮效果调整 */
    :deep(.el-table__body tr:hover > td) {
        background-color: #f5f7fa !important;
    }
}
.dialog-footer {
    padding-top: 10px;
}
</style>
ui/admin-ui3/src/components/subjectPeration/index.vue
New file
@@ -0,0 +1,284 @@
<template>
    <!-- 关联客户选择弹窗 -->
    <el-dialog v-model="dialogVisible" title="请选择 关联客户" width="80%" destroy-on-close @close="handleClose"
        append-to-body>
        <!-- 搜索区域 -->
        <div class="search-bar">
            <el-form inline :model="queryParams" class="search-form">
                <el-form-item label="运营主体简称:">
                    <el-input v-model="queryParams.customerShortName" placeholder="请输入运营主体简称" style="width: 180px" />
                </el-form-item>
                  <el-form-item label="运营主体全称:">
                    <el-input v-model="queryParams.customerFullName" placeholder="请输入运营主体全称" style="width: 180px" />
                </el-form-item>
                <el-form-item label="运营主体编号:">
                    <el-input v-model="queryParams.customerCode" placeholder="请输入运营主体编号" style="width: 180px" />
                </el-form-item>
                  <el-form-item label="经营状态:">
                    <el-select v-model="queryParams.operatingStatus" style="width: 200px;" placeholder="请选择经营状态" clearable>
                        <el-option v-for="dict in customer_type" :key="dict.value" :label="dict.label"
                            :value="parseInt(dict.value)" />
                    </el-select>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
                    <el-button plain icon="RefreshLeft" @click="handleReset">清空</el-button>
                </el-form-item>
            </el-form>
        </div>
        <!-- 客户表格(单选+默认选中) -->
        <el-table ref="customerTableRef" :data="customerList" border size="small" style="width: 100%"
            :highlight-current-row="true" @current-change="handleRowSelect" :current-row-key="selectedRow?.id"
            class="customer-table">
            <!-- <el-table-column prop="customerType" label="客户类型">
                <template #default="scope">
                    {{ dictFormat(customer_type, scope.row.customerType) }}
                </template>
            </el-table-column> -->
            <el-table-column prop="customerShortName" label="运营主体简称" />
            <el-table-column prop="customerFullName" label="运营主体全称" />
            <el-table-column prop="customerCode" label="运营主体编号" />
            <el-table-column prop="contactName" label="联系人姓名" />
            <el-table-column prop="operatingStatus" label="经营状态">
                <template #default="scope">
                    {{ dictFormat(business_status, scope.row.operatingStatus) }}
                </template>
            </el-table-column>
            <el-table-column prop="updateTime" label="更新时间" />
        </el-table>
        <pagination v-show="pageF.total > 0" :total="pageF.total" v-model:page="queryParams.pageNum"
            v-model:limit="queryParams.pageSize" @pagination="getList" />
        <!-- 底部按钮 -->
        <template #footer>
            <div class="dialog-footer">
                <el-button type="primary" @click="handleConfirm">确定</el-button>
            </div>
        </template>
    </el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, watch, nextTick } from 'vue';
import type { Table, TableCurrentRow } from 'element-plus';
import { ElMessage } from 'element-plus';
import useCurrentInstance from "@/utils/useCurrentInstance";
import { PageF } from "@/utils/globalInterface";
import { listTmsSettlementEntity } from "@/api/tms/tmsSettlementEntity";
const dictFormat = (dict: any, value: any) => {
    return proxy.selectDictLabel(dict, value);
}
// 分页参数
const pageF = reactive({
    ...PageF,
});
// 获取全局实例和字典
const { proxy } = useCurrentInstance();
const { customer_type, sys_invoice_type, sys_currency, sys_account_type, sys_bank_type,business_status } =
    proxy.useDict('customer_type', 'sys_invoice_type', 'sys_currency', 'sys_account_type', 'sys_bank_type','business_status');
// 定义客户数据类型
interface Customer {
    id: string | number;
    operatingStatus: string;
    customerShortName: string;
    customerCode: string;
    contactName: string;
    contractCompany: string;
}
// Props
const props = defineProps({
    visible: {
        type: Boolean,
        default: false
    },
    defaultSelectedId: {
        type: [String, Number],
        default: ''
    }
});
// Emits
const emit = defineEmits<{
    (e: 'confirm', selected: Customer): void;
    (e: 'close'): void;
}>();
// 响应式数据
const dialogVisible = ref(false);
const queryParams = reactive({
    operatingStatus: '',
    customerShortName: '',
    customerCode: '',
    pageNum: 1,
    pageSize: 10
});
const customerList = ref<Customer[]>([]);
const selectedRow = ref<Customer>();
const customerTableRef = ref<InstanceType<typeof Table>>();
// 核心修复:监听默认选中ID + 数据加载完成后再选中
const loadAndSelectRow = async (id: string | number) => {
    if (!id) return;
    // 1. 先确保数据加载完成
    await getDataList();
    nextTick(() => {
        // 2. 处理类型不匹配问题(统一转成字符串/数字)
        const targetId = typeof id === 'string' ? id : String(id);
        // 查找对应行(忽略类型,只比较值)
        const targetRow = customerList.value.find(item => String(item.id) === targetId);
        if (targetRow) {
            selectedRow.value = targetRow;
            // 3. 手动设置表格选中行
            if (customerTableRef.value) {
                customerTableRef.value.setCurrentRow(targetRow);
            }
        } else {
            // 可选:如果当前页没有,提示用户或自动分页查找(简单场景可省略)
            ElMessage.info('选中的客户不在当前列表,请调整搜索条件');
        }
    });
};
// 监听弹窗显示 + 默认选中ID变化
watch(
    () => [props.defaultSelectedId, props.visible],
    async ([id, visible]) => {
        if (visible && id) {
            // 弹窗显示且有默认ID时,加载数据并选中
            await loadAndSelectRow(id);
        } else if (!visible) {
            // 弹窗关闭清空选中
            selectedRow.value = undefined;
            if (customerTableRef.value) {
                customerTableRef.value.setCurrentRow(null);
            }
        }
    },
    { immediate: true }
);
// 监听弹窗显示状态(兼容原有逻辑)
watch(
    () => props.visible,
    (val) => {
        dialogVisible.value = val;
        if (val) handleReset();
    },
    { immediate: true }
);
// 加载数据列表(改为async,支持await)
const getDataList = async () => {
    try {
        const res = await listTmsSettlementEntity(queryParams);
        if (res.code === 200) {
            customerList.value = res.rows;
            pageF.total = res.total;
        }
    } catch (err) {
        console.error('加载客户列表失败:', err);
    }
};
// 搜索
const handleSearch = () => {
    queryParams.pageNum = 1;
    getDataList().then(() => {
        // 搜索后重新尝试选中(如果有默认ID)
        if (props.defaultSelectedId) {
            loadAndSelectRow(props.defaultSelectedId);
        }
    });
};
// 重置
const handleReset = () => {
    queryParams.operatingStatus = '';
    queryParams.customerShortName = '';
    queryParams.customerCode = '';
    queryParams.customerFullName = '';
    queryParams.pageNum = 1;
    queryParams.pageSize = 10;
    selectedRow.value = undefined;
    if (customerTableRef.value) {
        customerTableRef.value.setCurrentRow(null);
    }
    getDataList().then(() => {
        // 重置后重新尝试选中(如果有默认ID)
        if (props.defaultSelectedId) {
            loadAndSelectRow(props.defaultSelectedId);
        }
    });
};
// 分页回调
const getList = () => {
    getDataList().then(() => {
        // 分页后重新尝试选中(如果有默认ID)
        if (props.defaultSelectedId) {
            loadAndSelectRow(props.defaultSelectedId);
        }
    });
};
// 选中行
const handleRowSelect = (val: TableCurrentRow<Customer>) => {
    selectedRow.value = val as Customer;
};
// 确认选择
const handleConfirm = () => {
    if (!selectedRow.value) {
        ElMessage.warning('请选择一个客户');
        return;
    }
    emit('confirm', selectedRow.value);
    dialogVisible.value = false;
};
// 关闭弹窗
const handleClose = () => {
    dialogVisible.value = false;
    emit('close');
};
// 初始化加载数据
getDataList();
</script>
<style scoped lang="scss">
.search-bar {
    margin-bottom: 15px;
    padding: 0 5px;
}
.customer-table {
    :deep(.el-table__body tr.current-row > td) {
        background-color: #d4f5d4 !important;
        color: #333;
    }
    :deep(.el-table__header th) {
        background-color: #f5f7fa;
        font-weight: 500;
    }
}
.dialog-footer {
    text-align: right;
    width: 100%;
}
</style>
ui/admin-ui3/src/main.ts
@@ -23,6 +23,7 @@
const app = createApp(App);
app.use(pinia)
import Pagination from '@/components/Pagination/index.vue'
import DictTag from "/src/components/DictTag/index.vue";
import FileUpload from "/src/components/FileUpload/index.vue";
@@ -33,6 +34,7 @@
import SvgIcon from "/src/components/SvgIcon/index.vue";
app.component("DictTag", DictTag);
app.component('Pagination', Pagination);
app.component('FileUpload', FileUpload);
app.component('basicContainer', basicContainer)
app.component('XlsFileImport', XlsFileImport);
ui/admin-ui3/src/views/cwgl/bankAccountConfig/index.vue
@@ -150,6 +150,7 @@
    accountTypeData: {
      label: '账号类型',
      minWidth: 120,
      hide: true,
      addDisplay: false,  // 新增时不显示
      editDisplay: false, // 修改时不显示
      viewDisplay: true,
@@ -168,6 +169,7 @@
    currencyData: {
      label: '币种',
      minWidth: 120,
      hide: true,
      addDisplay: false,  // 新增时不显示
      editDisplay: false, // 修改时不显示
      viewDisplay: true,
@@ -188,6 +190,7 @@
    statusData: {
      label: '账户状态',
      minWidth: 120,
      hide: true,
      addDisplay: false,  // 新增时不显示
      editDisplay: false, // 修改时不显示
      viewDisplay: true,
ui/admin-ui3/src/views/cwgl/bankConfig/index.vue
@@ -1,48 +1,18 @@
<template>
  <basicContainer >
    <avue-crud
        :option="option"
        :table-loading="pageF.loading"
        :data="tableData"
        :page="page"
        :permission="permissionList"
        :before-open="beforeOpen"
        v-model="form"
        ref="crudRef"
        @row-update="rowUpdate"
        @row-save="rowSave"
        @refresh-change="refreshChange"
        @row-del="rowDel"
        @search-change="searchChange"
        @search-reset="searchReset"
        @selection-change="selectionChange"
        @current-change="currentChange"
        @size-change="sizeChange"
        @on-load="onLoad"
    >
  <basicContainer>
    <avue-crud :option="option" :table-loading="pageF.loading" :data="tableData" :page="page"
      :permission="permissionList" :before-open="beforeOpen" v-model="form" ref="crudRef" @row-update="rowUpdate"
      @row-save="rowSave" @refresh-change="refreshChange" @row-del="rowDel" @search-change="searchChange"
      @search-reset="searchReset" @selection-change="selectionChange" @current-change="currentChange"
      @size-change="sizeChange" @on-load="onLoad">
      <template #menu-left>
        <el-button
            type="success"
            icon="Edit"
            :disabled="pageF.single"
            v-hasPermi="['cwgl:bankConfig:edit']"
            @click="handleUpdate">修改
        <el-button type="success" icon="Edit" :disabled="pageF.single" v-hasPermi="['cwgl:bankConfig:edit']"
          @click="handleUpdate">修改
        </el-button>
        <el-button
            type="danger"
            icon="Delete"
            :disabled="pageF.multiple"
            @click="handleDelete"
            v-hasPermi="['cwgl:bankConfig:remove']"
        >删除
        <el-button type="danger" icon="Delete" :disabled="pageF.multiple" @click="handleDelete"
          v-hasPermi="['cwgl:bankConfig:remove']">删除
        </el-button>
        <el-button
            type="warning"
            plain
            icon="Download"
            @click="handleExport"
            v-hasPermi="['cwgl:bankConfig:export']"
        >导出
        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['cwgl:bankConfig:export']">导出
        </el-button>
      </template>
    </avue-crud>
@@ -50,141 +20,151 @@
</template>
<script setup name="bankConfig" lang="ts">
  import {BankConfigI,addBankConfig, delBankConfig, exportBankConfig, getBankConfig, listBankConfig, updateBankConfig} from "@/api/cwgl/bankConfig";
  import useCurrentInstance from "@/utils/useCurrentInstance";
  import {computed,reactive, ref, toRefs} from "vue";
  import {PagesInterface, PageQueryInterface} from "@/utils/globalInterface";
  import {usePagePlus} from "@/hooks/usePagePlus";
  import {hasPermission} from "@/utils/permissionUtils";
import { BankConfigI, addBankConfig, delBankConfig, exportBankConfig, getBankConfig, listBankConfig, updateBankConfig } from "@/api/cwgl/bankConfig";
import useCurrentInstance from "@/utils/useCurrentInstance";
import { computed, reactive, ref, toRefs } from "vue";
import { PagesInterface, PageQueryInterface } from "@/utils/globalInterface";
import { usePagePlus } from "@/hooks/usePagePlus";
import { hasPermission } from "@/utils/permissionUtils";
  const { proxy } = useCurrentInstance();
  const crudRef = ref();
const { proxy } = useCurrentInstance();
const crudRef = ref();
  const permissionList = computed(()=>{
    return {
      addBtn: hasPermission(["cwgl:bankConfig:add"]),
      delBtn: hasPermission(["cwgl:bankConfig:remove"]),
      editBtn: hasPermission(["cwgl:bankConfig:edit"]),
      viewBtn: hasPermission(["cwgl:bankConfig:query"]),
    }
  })
const permissionList = computed(() => {
  return {
    addBtn: hasPermission(["cwgl:bankConfig:add"]),
    delBtn: hasPermission(["cwgl:bankConfig:remove"]),
    editBtn: hasPermission(["cwgl:bankConfig:edit"]),
    viewBtn: hasPermission(["cwgl:bankConfig:query"]),
  }
})
  const data = reactive({
    form:<BankConfigI>{},
    queryParams:<BankConfigI&PageQueryInterface>{},
    page: <PagesInterface>{
      pageSize: 10,
      total: 0,
      currentPage: 1,
const data = reactive({
  form: <BankConfigI>{},
  queryParams: <BankConfigI & PageQueryInterface>{},
  page: <PagesInterface>{
    pageSize: 10,
    total: 0,
    currentPage: 1,
  },
  selectionList: [],
})
const { queryParams, form, page, selectionList } = toRefs(data);
const option = ref({
  pageKey: 'BankConfig',
  rowKey: 'id',
  column: {
    id: {
      label: 'ID',
    },
    selectionList:[],
  })
  const {queryParams,form,page,selectionList} = toRefs(data);
  const option = ref({
    pageKey: 'BankConfig',
    rowKey: 'id',
    column: {
                                id: {
          label: 'ID',
                            },
                                customerId: {
          label: '客户ID',
                                rules: [
              {
                required: true,
                message: "客户ID不能为空", trigger: "blur" }
            ],                  },
                                customerName: {
          label: '客户名称',
                                rules: [
              {
                required: true,
                message: "客户名称不能为空", trigger: "blur" }
            ],                  },
                                accountNo: {
          label: '账号编号',
                                rules: [
              {
                required: true,
                message: "账号编号不能为空", trigger: "blur" }
            ],                  },
                                accountName: {
          label: '户名',
                                rules: [
              {
                required: true,
                message: "户名不能为空", trigger: "blur" }
            ],                  },
                                bankName: {
          label: '银行名称',
                                rules: [
              {
                required: true,
                message: "银行名称不能为空", trigger: "blur" }
            ],                  },
                                branchName: {
          label: '支行名称',
                            },
                                accountType: {
          label: '账号类型(corporate:对公账户;personal:个人账户;collection:收款账户;payment:付款账户)',
                            },
                                currency: {
          label: '币种',
                            },
                                status: {
          label: '状态(normal:正常;frozen:冻结;cancelled:注销;abnormal:异常)',
                            },
                                accountNumber: {
          label: '银行账号',
                            },
                                openingDate: {
          label: '开户日期',
                            },
                                bankCode: {
          label: '银行行号',
                            },
                                remark: {
          label: '备注',
                      type: 'textarea', minRows: 3, maxRows: 5,
                            },
                                isDefault: {
          label: '是否默认账户(0:否;1:是)',
                            },
                                createBy: {
          label: '创建人',
                            },
                                updateBy: {
          label: '更新人',
                            },
                                createTime: {
          label: '创建时间',
                            },
                                updateTime: {
          label: '更新时间',
                            },
                                deleted: {
          label: '删除标记(0:正常;1:删除)',
                            },
          }
  })
    customerId: {
      label: '客户ID',
      rules: [
        {
          required: true,
          message: "客户ID不能为空", trigger: "blur"
        }
      ],
    },
    customerName: {
      label: '客户名称',
      rules: [
        {
          required: true,
          message: "客户名称不能为空", trigger: "blur"
        }
      ],
    },
    accountNo: {
      label: '账号编号',
      rules: [
        {
          required: true,
          message: "账号编号不能为空", trigger: "blur"
        }
      ],
    },
    accountName: {
      label: '户名',
      rules: [
        {
          required: true,
          message: "户名不能为空", trigger: "blur"
        }
      ],
    },
    bankName: {
      label: '银行名称',
      rules: [
        {
          required: true,
          message: "银行名称不能为空", trigger: "blur"
        }
      ],
    },
    branchName: {
      label: '支行名称',
    },
    accountType: {
      label: '账号类型(corporate:对公账户;personal:个人账户;collection:收款账户;payment:付款账户)',
    },
    currency: {
      label: '币种',
    },
    status: {
      label: '状态(normal:正常;frozen:冻结;cancelled:注销;abnormal:异常)',
    },
    accountNumber: {
      label: '银行账号',
    },
    openingDate: {
      label: '开户日期',
    },
    bankCode: {
      label: '银行行号',
    },
    remark: {
      label: '备注',
      type: 'textarea', minRows: 3, maxRows: 5,
    },
    isDefault: {
      label: '是否默认账户(0:否;1:是)',
    },
    createBy: {
      label: '创建人',
    },
    updateBy: {
      label: '更新人',
    },
    createTime: {
      label: '创建时间',
    },
    updateTime: {
      label: '更新时间',
    },
    deleted: {
      label: '删除标记(0:正常;1:删除)',
    },
  }
})
  const { tableData,pageF,rowSave,rowUpdate,rowDel,beforeOpen,searchChange,
    searchReset,selectionChange,onLoad,currentChange,sizeChange,handleDelete,handleExport,handleUpdate,refreshChange} = usePagePlus({
    form:form,
    option:option,
    queryParams:queryParams,
    idKey:'id',
    page:page.value,
    getListApi:listBankConfig,
    getDetailApi:getBankConfig,
    exportApi:exportBankConfig,
    deleteApi:delBankConfig,
    addApi:addBankConfig,
    updateApi:updateBankConfig,
    handleUpdateFunc:()=>{
const { tableData, pageF, rowSave, rowUpdate, rowDel, beforeOpen, searchChange,
  searchReset, selectionChange, onLoad, currentChange, sizeChange, handleDelete, handleExport, handleUpdate, refreshChange } = usePagePlus({
    form: form,
    option: option,
    queryParams: queryParams,
    idKey: 'id',
    page: page.value,
    getListApi: listBankConfig,
    getDetailApi: getBankConfig,
    exportApi: exportBankConfig,
    deleteApi: delBankConfig,
    addApi: addBankConfig,
    updateApi: updateBankConfig,
    handleUpdateFunc: () => {
      crudRef.value.rowEdit(selectionList.value[0]);
    },
    handleSelectionChangeFunc:(selection:any)=>{
    handleSelectionChangeFunc: (selection: any) => {
      selectionList.value = selection;
    }
  })
ui/admin-ui3/src/views/cwgl/interiorBankAccountConfig/index.vue
New file
@@ -0,0 +1,306 @@
<template>
  <basicContainer>
    <avue-crud :option="option" :table-loading="pageF.loading" :data="tableData" :page="page"
      :permission="permissionList" :before-open="beforeOpen" v-model="form" ref="crudRef" @row-update="rowUpdate"
      @row-save="rowSave" @refresh-change="refreshChange" @row-del="rowDel" @search-change="searchChange"
      @search-reset="searchReset" @selection-change="selectionChange" @current-change="currentChange"
      @size-change="sizeChange" @on-load="onLoad">
      <template #menu-left>
        <el-button type="primary" icon="Plus" v-hasPermi="['cwgl:bankConfig:add']" @click="handleAdd">新增
        </el-button>
        <!-- <el-button type="success" icon="Edit" :disabled="pageF.single" v-hasPermi="['cwgl:bankAccountConfig:edit']"
          @click="handleUpdate">修改
        </el-button> -->
        <!-- <el-button type="danger" icon="Delete" :disabled="pageF.multiple" @click="handleDelete"
          v-hasPermi="['cwgl:bankAccountConfig:remove']">删除
        </el-button> -->
        <el-button type="warning" plain icon="Download" @click="handleExport"
          v-hasPermi="['cwgl:bankConfig:export']">导出
        </el-button>
      </template>
      <template #menu="{ size, row, index }">
        <el-link class="link-btn" type="primary" icon="Edit" :underline="false" plain :size="size"
          @click="handleFy(row)" v-hasPermi="['cwgl:bankConfig:edit']"> 编辑
        </el-link>
      </template>
    </avue-crud>
  </basicContainer>
  <bankCardCate ref="invoiceFormRef" :ishowBank="false" @submit="handleFormSubmit" />
</template>
<script setup name="bankAccountConfig" lang="ts">
import { BankAccountConfigI, addBankAccountConfig, delBankAccountConfig, exportBankAccountConfig, getBankAccountConfig, listBankAccountConfig, updateBankAccountConfig } from "@/api/cwgl/twoBankAccountConfig";
import { BankConfigI, addBankConfig, delBankConfig, exportBankConfig, getBankConfig, listBankConfig, updateBankConfig } from "@/api/cwgl/bankConfig";
import useCurrentInstance from "@/utils/useCurrentInstance";
import { computed, reactive, ref, toRefs } from "vue";
import { PagesInterface, PageQueryInterface } from "@/utils/globalInterface";
import { usePagePlus } from "@/hooks/usePagePlus";
import { hasPermission } from "@/utils/permissionUtils";
import bankCardCate from "@/components/bankCardCate/index.vue";
const { proxy } = useCurrentInstance();
const crudRef = ref();
const {
  customer_type, sys_invoice_type, sys_currency, sys_account_type, sys_bank_type
} =
  proxy.useDict(
    'customer_type', 'sys_invoice_type', 'sys_currency', 'sys_account_type', 'sys_bank_type'
  );
const dictFormat = (dict: any, value: any) => {
  return proxy.selectDictLabel(dict, value);
}
const permissionList = computed(() => {
  return {
  addBtn: hasPermission(["cwgl:bankConfig:add"]),
    delBtn: hasPermission(["cwgl:bankConfig:remove"]),
    editBtn: hasPermission(["cwgl:bankConfig:edit"]),
    viewBtn: hasPermission(["cwgl:bankConfig:query"]),
  }
})
const data = reactive({
  form: <BankAccountConfigI>{},
  queryParams: <BankAccountConfigI & PageQueryInterface>{},
  page: <PagesInterface>{
    pageSize: 10,
    total: 0,
    currentPage: 1,
  },
  selectionList: [],
})
const { queryParams, form, page, selectionList } = toRefs(data);
const option = ref({
  pageKey: 'BankAccountConfig',
  rowKey: 'id',
  addBtn: false,
  editBtn: false,
  searchSpan: 5,
  labelWidth: 150,
  searchLabelWidth: 120,
  column: {
    // id: {
    //   label: 'ID',
    // },
    // customerId: {
    //   label: '客户ID',
    //   rules: [
    //     {
    //       required: true,
    //       message: "客户ID不能为空", trigger: "blur"
    //     }
    //   ],
    // },
    customerName: {
      label: '客户名称',
      minWidth: 120,
      search: true,
      rules: [
        {
          required: true,
          message: "客户名称不能为空", trigger: "blur"
        }
      ],
    },
    accountNo: {
      label: '账号编号',
      minWidth: 180,
      search: true,
      rules: [
        {
          required: true,
          message: "账号编号不能为空", trigger: "blur"
        }
      ],
    },
    accountName: {
      label: '户名',
      minWidth: 120,
      search: true,
      rules: [
        {
          required: true,
          message: "户名不能为空", trigger: "blur"
        }
      ],
    },
    bankName: {
      label: '银行名称',
      minWidth: 140,
      rules: [
        {
          required: true,
          message: "银行名称不能为空", trigger: "blur"
        }
      ],
    },
    branchName: {
      label: '支行名称',
      minWidth: 180,
    },
    accountType: {
      label: '账号类型',
      search: true,
      minWidth: 120,
      dataType: 'string',
      type: 'select',
      // addDisplay: false,  // 新增时不显示
      // editDisplay: false, // 修改时不显示
      viewDisplay: false,
      dicUrl: '/system/dict/data/type/sys_account_type',
    },
    accountTypeData: {
      label: '账号类型',
      minWidth: 120,
      hide: true,
      addDisplay: false,  // 新增时不显示
      editDisplay: false, // 修改时不显示
      viewDisplay: true,
    },
    currency: {
      label: '币种',
      search: true,
      minWidth: 120,
      dataType: 'string',
      type: 'select',
      // addDisplay: false,  // 新增时不显示
      // editDisplay: false, // 修改时不显示
      viewDisplay: false,
      dicUrl: '/system/dict/data/type/sys_currency',
    },
    currencyData: {
      label: '币种',
      minWidth: 120,
      hide: true,
      addDisplay: false,  // 新增时不显示
      editDisplay: false, // 修改时不显示
      viewDisplay: true,
    },
    status: {
      label: '账户状态',
      search: true,
      minWidth: 120,
      dataType: 'string',
      type: 'select',
      // addDisplay: false,  // 新增时不显示
      // editDisplay: false, // 修改时不显示
      viewDisplay: false,
      dicUrl: '/system/dict/data/type/sys_bank_type',
    },
    statusData: {
      label: '账户状态',
      minWidth: 120,
      hide: true,
      addDisplay: false,  // 新增时不显示
      editDisplay: false, // 修改时不显示
      viewDisplay: true,
    }
    // accountNumber: {
    //   label: '银行账号',
    // },
    // openingDate: {
    //   label: '开户日期',
    // },
    // bankCode: {
    //   label: '银行行号',
    // },
    // remark: {
    //   label: '备注',
    //   type: 'textarea', minRows: 3, maxRows: 5,
    // },
    // isDefault: {
    //   label: '是否默认账户(0:否;1:是)',
    // },
    // createBy: {
    //   label: '创建人',
    // },
    // updateBy: {
    //   label: '更新人',
    // },
    // createTime: {
    //   label: '创建时间',
    // },
    // updateTime: {
    //   label: '更新时间',
    // },
    // deleted: {
    //   label: '删除标记(0:正常;1:删除)',
    // },
  }
})
const { tableData, pageF, rowSave, rowUpdate, rowDel, beforeOpen, searchChange,
  searchReset, selectionChange, onLoad, currentChange, sizeChange, handleDelete, handleExport, handleUpdate, refreshChange } = usePagePlus({
    form: form,
    option: option,
    queryParams: queryParams,
    idKey: 'id',
    page: page.value,
    getListApi: listBankConfig,
    getDetailApi: getBankConfig,
    exportApi: exportBankConfig,
    deleteApi: delBankConfig,
    addApi: addBankConfig,
    updateApi: updateBankConfig,
    handleUpdateFunc: () => {
      crudRef.value.rowEdit(selectionList.value[0]);
    },
    handleSelectionChangeFunc: (selection: any) => {
      selectionList.value = selection;
    },
    handleEndOpenFunc: (data, obj) => {
      if (data == 'view') {
        nextTick(() => {
          // 强制将 row 的原始数据(包含'pc') 重新灌入表单
          // 这能解决你打印信息中最后出现的 {} 置空问题
          Object.assign(form.value, obj.data);
          form.value.accountTypeData = dictFormat(sys_account_type.value, form.value.accountType);
          form.value.currencyData = dictFormat(sys_currency.value, form.value.currency);
          form.value.statusData = dictFormat(sys_bank_type.value, form.value.status);
        });
      }
    },
  })
const invoiceFormRef = ref();
const handleAdd = () => {
  invoiceFormRef.value.openDialog('');
};
const handleFormSubmit = (data: any) => {
  if (data.id !== '') {
    updateBankConfig(data).then((res) => {
      if (res.code == 200) {
        proxy.$message.success(res.msg);
        invoiceFormRef.value.handleClose();
        onLoad(page.value)
      }
    });
  } else {
    addBankConfig(data).then((res) => {
      if (res.code == 200) {
        proxy.$message.success(res.msg);
        invoiceFormRef.value.handleClose();
        onLoad(page.value)
      }
    });
  }
};
const handleFy = (row: any) => {
  getBankConfig(row.id).then((res) => {
    if (res.code == 200) {
      invoiceFormRef.value.openDialog(res.data);
    }
  });
};
</script>
ui/admin-ui3/src/views/cwgl/receivableBillManagement/index.vue
@@ -1,245 +1,400 @@
<template>
  <basicContainer >
    <avue-crud
        :option="option"
        :table-loading="pageF.loading"
        :data="tableData"
        :page="page"
        :permission="permissionList"
        :before-open="beforeOpen"
        v-model="form"
        ref="crudRef"
        @row-update="rowUpdate"
        @row-save="rowSave"
        @refresh-change="refreshChange"
        @row-del="rowDel"
        @search-change="searchChange"
        @search-reset="searchReset"
        @selection-change="selectionChange"
        @current-change="currentChange"
        @size-change="sizeChange"
        @on-load="onLoad"
    >
  <basicContainer>
    <avue-crud :option="option" :table-loading="pageF.loading" :data="tableData" :page="page"
      :permission="permissionList" :before-open="beforeOpen" v-model="form" ref="crudRef" @row-update="rowUpdate"
      @row-save="rowSave" @refresh-change="refreshChange" @row-del="rowDel" @search-change="searchChange"
      @search-reset="searchReset" @selection-change="selectionChange" @current-change="currentChange"
      @size-change="sizeChange" @on-load="onLoad">
      <template #menu-left>
        <el-button
            type="success"
            icon="Edit"
            :disabled="pageF.single"
            v-hasPermi="['cwgl:receivableBillManagement:edit']"
            @click="handleUpdate">修改
        <!-- <el-button type="success" icon="Edit" :disabled="pageF.single"
          v-hasPermi="['cwgl:receivableBillManagement:edit']" @click="handleUpdate">修改
        </el-button>
        <el-button
            type="danger"
            icon="Delete"
            :disabled="pageF.multiple"
            @click="handleDelete"
            v-hasPermi="['cwgl:receivableBillManagement:remove']"
        >删除
        <el-button type="danger" icon="Delete" :disabled="pageF.multiple" @click="handleDelete"
          v-hasPermi="['cwgl:receivableBillManagement:remove']">删除
        </el-button> -->
        <el-button type="warning" plain icon="Download" @click="handleExport"
          v-hasPermi="['cwgl:receivableBillManagement:export']">导出
        </el-button>
        <el-button
            type="warning"
            plain
            icon="Download"
            @click="handleExport"
            v-hasPermi="['cwgl:receivableBillManagement:export']"
        >导出
        </el-button>
      </template>
      <template #menu="{ size, row, index }">
        <el-link class="link-btn" type="primary" v-if="row.status == 0 || row.status == 1" :underline="false" plain :size="size" @click="handleSettle(row)"
          v-hasPermi="['cwgl:receivableBillManagement:view']"> 结算
        </el-link>
        <el-link class="link-btn" type="primary" v-if="row.status == 0 || row.status == 1|| row.status == 3" :underline="false" plain :size="size" @click="handleViewHistory(row)"
          v-hasPermi="['cwgl:receivableBillManagement:view']"> 结算明细
        </el-link>
        <el-link class="link-btn" type="primary" :underline="false" plain :size="size" @click="handleViewFeeDetail(row)"
          v-hasPermi="['cwgl:receivableBillManagement:view']"> 详情
        </el-link>
        <!-- <el-link class="link-btn" v-if="row.status == 0" type="primary" :underline="false" plain :size="size"
          icon="el-icon-edit" @click="handleEdit(row)" v-hasPermi="['cwgl:receivableFeeManagement:edit']"> 编辑
        </el-link> -->
        <el-link class="link-btn" v-if="row.status == 0" type="primary"
        :underline="false"
          plain @click="handleInvalid(row)" v-hasPermi="['cwgl:receivableBillManagement:invalid']"> 作废
        </el-link>
        <el-button type="text" icon="View" @click="handleFlow(row)"
          v-hasPermi="['cwgl:receivableBillManagement:flow']">日志</el-button>
      </template>
    </avue-crud>
  </basicContainer>
  <SettlementDialog ref="settleDialogRef" :type="currentType" @success="handleRefresh" />
  <BillSettlementHistory ref="historyRef" :type="activeType" />
  <NestedDetailDialog ref="feeDetailRef" :type="activeType" />
  <OperationLogModal ref="logModalRef" />
</template>
<script setup name="receivableBillManagement" lang="ts">
  import {ReceivableBillManagementI,addReceivableBillManagement, delReceivableBillManagement, exportReceivableBillManagement, getReceivableBillManagement, listReceivableBillManagement, updateReceivableBillManagement} from "@/api/cwgl/receivableBillManagement";
  import useCurrentInstance from "@/utils/useCurrentInstance";
  import {computed,reactive, ref, toRefs} from "vue";
  import {PagesInterface, PageQueryInterface} from "@/utils/globalInterface";
  import {usePagePlus} from "@/hooks/usePagePlus";
  import {hasPermission} from "@/utils/permissionUtils";
import { ReceivableBillManagementI, addReceivableBillManagement, delReceivableBillManagement, exportReceivableBillManagement, getReceivableBillManagement, listReceivableBillManagement, updateReceivableBillManagement,receivableBillManagementVoid } from "@/api/cwgl/receivableBillManagement";
import useCurrentInstance from "@/utils/useCurrentInstance";
import { computed, reactive, ref, toRefs } from "vue";
import { PagesInterface, PageQueryInterface } from "@/utils/globalInterface";
import { usePagePlus } from "@/hooks/usePagePlus";
import { hasPermission } from "@/utils/permissionUtils";
import SettlementDialog from '@/components/SettlementDialog/index.vue';
import BillSettlementHistory from '../../../components/BillSettlementHistory/index.vue';
import NestedDetailDialog from '../../../components/NestedDetailDialog/index.vue';
import OperationLogModal from '@/components/OperationLogModal/index.vue';
  import { listReceivableBillManagementLog} from "@/api/cwgl/receivableBillManagementLog";
  const { proxy } = useCurrentInstance();
  const crudRef = ref();
import { addReceivableBillSettlementDetail, } from "@/api/cwgl/receivableBillSettlementDetail";
const { proxy } = useCurrentInstance();
const crudRef = ref();
  const permissionList = computed(()=>{
    return {
      addBtn: hasPermission(["cwgl:receivableBillManagement:add"]),
      delBtn: hasPermission(["cwgl:receivableBillManagement:remove"]),
      editBtn: hasPermission(["cwgl:receivableBillManagement:edit"]),
      viewBtn: hasPermission(["cwgl:receivableBillManagement:query"]),
    }
  })
const permissionList = computed(() => {
  return {
    addBtn: hasPermission(["cwgl:receivableBillManagement:add"]),
    delBtn: hasPermission(["cwgl:receivableBillManagement:remove"]),
    editBtn: hasPermission(["cwgl:receivableBillManagement:edit"]),
    viewBtn: hasPermission(["cwgl:receivableBillManagement:query"]),
  }
})
  const data = reactive({
    form:<ReceivableBillManagementI>{},
    queryParams:<ReceivableBillManagementI&PageQueryInterface>{},
    page: <PagesInterface>{
      pageSize: 10,
      total: 0,
      currentPage: 1,
const data = reactive({
  form: <ReceivableBillManagementI>{},
  queryParams: <ReceivableBillManagementI & PageQueryInterface>{},
  page: <PagesInterface>{
    pageSize: 10,
    total: 0,
    currentPage: 1,
  },
  selectionList: [],
})
const { queryParams, form, page, selectionList } = toRefs(data);
const option = ref({
  pageKey: 'ReceivableBillManagement',
  rowKey: 'id',
  labelWidth: 150,
  delBtn: false,
  addBtn: false,
  viewBtn: false,
  editBtn: false,
  searchLabelWidth: 120,
  column: {
    // id: {
    //   label: 'ID',
    // },
    systemNo: {
      label: '系统编号',
      minWidth: 150,
      search: true,
      rules: [
        {
          required: true,
          message: "系统编号不能为空", trigger: "blur"
        }
      ],
    },
    selectionList:[],
  })
  const {queryParams,form,page,selectionList} = toRefs(data);
  const option = ref({
    pageKey: 'ReceivableBillManagement',
    rowKey: 'id',
    column: {
                                id: {
          label: 'ID',
                            },
                                systemNo: {
          label: '系统编号',
                                rules: [
              {
                required: true,
                message: "系统编号不能为空", trigger: "blur" }
            ],                  },
                                billName: {
          label: '账单名称',
                                rules: [
              {
                required: true,
                message: "账单名称不能为空", trigger: "blur" }
            ],                  },
                                customerName: {
          label: '客户名称',
                                rules: [
              {
                required: true,
                message: "客户名称不能为空", trigger: "blur" }
            ],                  },
                                isInternalSettlement: {
          label: '是否内部结算',
                                rules: [
              {
                required: true,
                message: "是否内部结算不能为空", trigger: "blur" }
            ],                  },
                                internalSettlementUnit: {
          label: '内部结算单位',
                            },
                                documentCount: {
          label: '单据数量',
                            },
                                totalAmount: {
          label: '应结算金额',
                            },
                                currency: {
          label: '币制',
                            },
                                discountAmount: {
          label: '减免金额',
                            },
                                receivedAmount: {
          label: '已收金额',
                            },
                                pendingAmount: {
          label: '待收金额',
                            },
                                exchangeRate: {
          label: '汇率',
                            },
                                cnyAmount: {
          label: '人民币金额',
                            },
                                periodType: {
          label: '周期类型',
                                rules: [
              {
                required: true,
                message: "周期类型不能为空", trigger: "change"
                 }
            ],                  },
                                businessStartDate: {
          label: '业务期间开始日期',
                                rules: [
              {
                required: true,
                message: "业务期间开始日期不能为空", trigger: "blur" }
            ],                  },
                                businessEndDate: {
          label: '业务期间结束日期',
                                rules: [
              {
                required: true,
                message: "业务期间结束日期不能为空", trigger: "blur" }
            ],                  },
                                billingStartDate: {
          label: '账期开始日期',
                                rules: [
              {
                required: true,
                message: "账期开始日期不能为空", trigger: "blur" }
            ],                  },
                                billingEndDate: {
          label: '账期结束日期',
                                rules: [
              {
                required: true,
                message: "账期结束日期不能为空", trigger: "blur" }
            ],                  },
                                billGenerateDate: {
          label: '账单生成日期',
                                rules: [
              {
                required: true,
                message: "账单生成日期不能为空", trigger: "blur" }
            ],                  },
                                billSendDate: {
          label: '账单发送日期',
                            },
                                billDueDate: {
          label: '账单到期日期',
                                rules: [
              {
                required: true,
                message: "账单到期日期不能为空", trigger: "blur" }
            ],                  },
                                status: {
          label: '状态(draft:草稿;generated:已生成;sent:已发送;partial_paid:部分收款;paid:已收款;cancelled:已取消)',
                            },
                                remark: {
          label: '备注',
                      type: 'textarea', minRows: 3, maxRows: 5,
                            },
                                createBy: {
          label: '创建人',
                            },
                                createTime: {
          label: '创建时间',
                            },
                                updateBy: {
          label: '更新人',
                            },
                                updateTime: {
          label: '更新时间',
                            },
                                deleted: {
          label: '删除标记(0:正常;1:删除)',
                            },
          }
  })
    billName: {
      label: '账单名称',
      minWidth: 150,
      search: true,
  const { tableData,pageF,rowSave,rowUpdate,rowDel,beforeOpen,searchChange,
    searchReset,selectionChange,onLoad,currentChange,sizeChange,handleDelete,handleExport,handleUpdate,refreshChange} = usePagePlus({
    form:form,
    option:option,
    queryParams:queryParams,
    idKey:'id',
    page:page.value,
    getListApi:listReceivableBillManagement,
    getDetailApi:getReceivableBillManagement,
    exportApi:exportReceivableBillManagement,
    deleteApi:delReceivableBillManagement,
    addApi:addReceivableBillManagement,
    updateApi:updateReceivableBillManagement,
    handleUpdateFunc:()=>{
      rules: [
        {
          required: true,
          message: "账单名称不能为空", trigger: "blur"
        }
      ],
    },
    customerName: {
      label: '客户名称',
      minWidth: 150,
      search: true,
      rules: [
        {
          required: true,
          message: "客户名称不能为空", trigger: "blur"
        }
      ],
    },
    // isInternalSettlement: {
    //   label: '是否内部结算',
    //   rules: [
    //     {
    //       required: true,
    //       message: "是否内部结算不能为空", trigger: "blur"
    //     }
    //   ],
    // },
    // internalSettlementUnit: {
    //   label: '内部结算单位',
    // },
    documentCount: {
      label: '单据数量',
      minWidth: 100,
    },
    totalAmount: {
      label: '应结算金额',
      minWidth: 100,
    },
    currency: {
      label: '币制',
      minWidth: 100,
    },
    discountAmount: {
      label: '减免金额',
      minWidth: 100,
    },
    receivedAmount: {
      label: '已收金额',
      minWidth: 100,
    },
    pendingAmount: {
      label: '待收金额',
      minWidth: 100,
    },
    // exchangeRate: {
    //   label: '汇率',
    // },
    // cnyAmount: {
    //   label: '人民币金额',
    // },
    // 在 option 的 column 中修改 periodType
    periodType: {
      label: '周期类型',
      minWidth: 200, // 增加宽度以容纳日期范围
    },
    businessStartDateArray: {
      label: '业务期间',
      formatter: (row) => {
        if (row.businessEndDate && row.businessStartDate) {
          return `${row.businessStartDate} 至 ${row.businessEndDate}`;
        }
        return row.periodType || '-';
      }
    },
    businessDateArray: {
      label: '账单周期',
      formatter: (row) => {
        if (row.billingStartDate && row.billingEndDate) {
          return `${row.billingStartDate} 至 ${row.billingEndDate}`;
        }
        return row.periodType || '-';
      }
    },
    // businessEndDate: {
    //   label: '业务期间结束日期',
    //   rules: [
    //     {
    //       required: true,
    //       message: "业务期间结束日期不能为空", trigger: "blur"
    //     }
    //   ],
    // },
    // billingStartDate: {
    //   label: '账期开始日期',
    //   rules: [
    //     {
    //       required: true,
    //       message: "账期开始日期不能为空", trigger: "blur"
    //     }
    //   ],
    // },
    // billingEndDate: {
    //   label: '账期结束日期',
    //   rules: [
    //     {
    //       required: true,
    //       message: "账期结束日期不能为空", trigger: "blur"
    //     }
    //   ],
    // },
    billGenerateDate: {
      label: '账单生成日期',
      minWidth: 150,
      rules: [
        {
          required: true,
          message: "账单生成日期不能为空", trigger: "blur"
        }
      ],
    },
    billSendDate: {
      label: '账单发送日期',
      minWidth: 150,
    },
    billDueDate: {
      label: '账单到期日期',
      minWidth: 150,
      rules: [
        {
          required: true,
          message: "账单到期日期不能为空", trigger: "blur"
        }
      ],
    },
    // remark: {
    //   label: '备注',
    //   type: 'textarea', minRows: 3, maxRows: 5,
    // },
    createBy: {
      label: '创建人',
      minWidth: 150,
    },
    createTime: {
      label: '创建时间',
      minWidth: 200,
    },
    updateBy: {
      label: '更新人',
      minWidth: 150,
    },
    updateTime: {
      label: '更新时间',
      minWidth: 200,
    },
    status: {
      label: '状态',
      minWidth: 120,
      fixed: 'right',
      type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/sys_bill_status',
      search: true,
      rules: [
        {
          required: true,
          message: "状态不能为空", trigger: "blur"
        }
      ],
    },
    // deleted: {
    //   label: '删除标记(0:正常;1:删除)',
    // },
  }
})
const { tableData, pageF, rowSave, rowUpdate, rowDel, beforeOpen, searchChange,
  searchReset, selectionChange, onLoad, currentChange, sizeChange, handleDelete, handleExport, handleUpdate, refreshChange } = usePagePlus({
    form: form,
    option: option,
    queryParams: queryParams,
    idKey: 'id',
    page: page.value,
    getListApi: listReceivableBillManagement,
    getDetailApi: getReceivableBillManagement,
    exportApi: exportReceivableBillManagement,
    deleteApi: delReceivableBillManagement,
    addApi: addReceivableBillManagement,
    updateApi: updateReceivableBillManagement,
    handleUpdateFunc: () => {
      crudRef.value.rowEdit(selectionList.value[0]);
    },
    handleSelectionChangeFunc:(selection:any)=>{
    handleSelectionChangeFunc: (selection: any) => {
      selectionList.value = selection;
    }
  })
const settleDialogRef = ref()
const currentType = ref<'receivable' | 'payable'>('receivable')
const ids = ref('')
const handleSettle = (row) => {
  currentType.value = 'receivable'
  ids.value = row.id
  getReceivableBillManagement(row.id).then((res) => {
    if (res.code === 200) {
      settleDialogRef.value.open(res.data)
    }
  })
}
const handleRefresh = (data) => {
  console.log(data);
  // ids.value
  data.billId = ids.value
  addReceivableBillSettlementDetail(data).then((res) => {
    if (res.code == 200) {
      settleDialogRef.value.openIshpw()
      proxy.$modal.msgSuccess(res.msg);
      onLoad(page.value)
    }
  })
}
// 结算历史弹窗引用
const historyRef = ref();
const activeType = ref('receivable');
/** 查看结算记录 */
const handleViewHistory = (row: any) => {
  // 假设父组件通过某种方式知道当前是应收还是应付逻辑
  // 或者直接从 row 里的某个字段判断
  historyRef.value.open(row);
};
/* 获取结算历史数据 */
// 2. 定义引用和类型
const feeDetailRef = ref();
/** 查看费用明细按钮点击事件 */
const handleViewFeeDetail = (row: any) => {
  // 设置当前业务类型(应收页面传 'receivable',应付页面传 'payable')
  activeType.value = 'receivable';
  feeDetailRef.value.open(row);
};
const handleInvalid = (row: any) => {
  proxy.$modal.confirm(`是否作废该系统编号 :${row.systemNo}?`).then(function () {
    return receivableBillManagementVoid(row.id);
  }).then((res) => {
    onLoad(page.value);
    proxy.$modal.msgSuccess(res.msg);
  })
}
const logModalRef = ref(null);
const handleFlow = (row: any,) => {
  // 这里可以从 row 中直接获取日志,或者调用后端接口查询
  listReceivableBillManagementLog({billId:row.id}).then((res) => {
    if (res.code == 200) {
     logModalRef.value.open(res.rows,'listReceivableBillManagementLog');
    }
  });
}
</script>
ui/admin-ui3/src/views/cwgl/receivableFeeManagement/index.vue
@@ -26,8 +26,8 @@
        </el-button>
      </template>
      <template #menu="{ size, row, index }">
        <el-link class="link-btn"  type="primary" :underline="false" plain
          :size="size" icon="View" @click="handleExamine(row)" v-hasPermi="['cwgl:receivableFeeManagement:view']"> 查看
        <el-link class="link-btn" type="primary" :underline="false" plain :size="size" icon="View"
          @click="handleExamine(row)" v-hasPermi="['cwgl:receivableFeeManagement:view']"> 查看
        </el-link>
        <el-link class="link-btn" v-if="row.status == 0" type="primary" :underline="false" plain :size="size"
          icon="el-icon-edit" @click="handleEdit(row)" v-hasPermi="['cwgl:receivableFeeManagement:edit']"> 编辑
@@ -54,7 +54,7 @@
<script setup name="receivableFeeManagement" lang="ts">
import {
  ReceivableFeeManagementI, addReceivableFeeManagement, delReceivableFeeManagement, exportReceivableFeeManagement, getReceivableFeeManagement, listReceivableFeeManagement, updateReceivableFeeManagement,
  getStatistics, addCreateBill,receivableFeeManagementVoid
  getStatistics, addCreateBill, receivableFeeManagementVoid
} from "@/api/cwgl/receivableFeeManagement";
import useCurrentInstance from "@/utils/useCurrentInstance";
import { computed, reactive, ref, toRefs } from "vue";
@@ -65,7 +65,7 @@
import GenerateBillDialog from '@/components/GenerateBillDialog/index.vue';
import DetailModal from '@/components/DetailModal/index.vue';
import OperationLogModal from '@/components/OperationLogModal/index.vue';
  import { listReceivableFeeManagementLog} from "@/api/cwgl/receivableFeeManagementLog";
import { listReceivableFeeManagementLog } from "@/api/cwgl/receivableFeeManagementLog";
@@ -167,6 +167,21 @@
        }
      ],
    },
    receivableAmountStr: {
      label: '应收金额描述',
      minWidth: 150,
      search: true,
      formatter: (row) => {
        if (!row.receivableAmountStr) return '-';
        // 将空格替换为换行符。如果后端返回的是 "0港币 2420人民币"
        // 我们将其转换为 "0港币\n2420人民币"
        return row.receivableAmountStr.replace(/\s+/g, '\n');
      },
      styles: {
        whiteSpace: 'pre-wrap',
        lineHeight: '1.5'
      },
    },
    documentNo: {
      label: '单据编号',
      minWidth: 150,
@@ -178,7 +193,7 @@
        }
      ],
    },
     isInternalSettlement: {
    isInternalSettlement: {
      label: '是否内部结算',
      search: true,
      minWidth: 120,
@@ -193,7 +208,7 @@
    internalSettlementUnit: {
      label: '内部结算单位',
      minWidth: 150,
       search: true,
      search: true,
    },
    customerName: {
      label: '客户名称',
@@ -319,7 +334,6 @@
      search: true,
      label: '状态',
      fixed: 'right',
      search: true,
      minWidth: 120,
      type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/sys_charge',
    },
@@ -435,6 +449,7 @@
  getStatistics(ids).then((res) => {
    if (res.code === 200) {
      // 打开弹窗并传入数据
      console.log(selectionList.valu);
      billDialogRef.value.open(res.data, selectionList.value);
    }
  });
@@ -446,9 +461,9 @@
    billType: obj.billType,
    billName: obj.billName,
    statisticsData: statisticsData,
     customerName: selectionList.value[0].customerName,
     isInternalSettlement: selectionList.value[0].isInternalSettlement,
     internalSettlementUnit: selectionList.value[0].internalSettlementUnit,
    customerName: selectionList.value[0].customerName,
    isInternalSettlement: selectionList.value[0].isInternalSettlement,
    internalSettlementUnit: selectionList.value[0].internalSettlementUnit,
  };
  addCreateBill(payload).then((res) => {
@@ -487,9 +502,9 @@
const handleFlow = (row: any) => {
  // 这里可以从 row 中直接获取日志,或者调用后端接口查询
  // 示例模拟数据
  listReceivableFeeManagementLog({receivableFeeId:row.id}).then((res) => {
  listReceivableFeeManagementLog({ receivableFeeId: row.id }).then((res) => {
    if (res.code == 200) {
     logModalRef.value.open(res.rows);
      logModalRef.value.open(res.rows,'listReceivableFeeManagementLog');
    }
  });
@@ -504,3 +519,10 @@
};
</script>
<style scoped>
/* 确保 el-table 能够识别换行符 */
:deep(.el-table .cell) {
  white-space: pre-wrap !important;
  word-break: break-all;
}
</style>