| ui/admin-ui3/src/api/cwgl/fundFlow.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ui/admin-ui3/src/components/AccountsPayableManagementDialog/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ui/admin-ui3/src/components/ClaimBillDialog/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ui/admin-ui3/src/components/receivableBillManagementDialog/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ui/admin-ui3/src/views/cwgl/fundFlow/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ui/admin-ui3/src/views/cwgl/fundFlowClaimDetail/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
ui/admin-ui3/src/api/cwgl/fundFlow.ts
@@ -56,6 +56,15 @@ }) } /** * 确认资金流水 */ export const confirmFundFlow:requestType = (id) => { return request({ url: '/cwgl/fundFlow/confirm/' + id, method: 'put' }) } /** * 导出资金流水 @@ -65,3 +74,11 @@ download('/cwgl/fundFlow/export',query); }) } /* 账单认领 */ export const addFundFlowClaimDetailClaim:requestType = (data,id) => { return request({ url: '/cwgl/fundFlowClaimDetail/claim/'+id, method: 'post', data }) } ui/admin-ui3/src/components/AccountsPayableManagementDialog/index.vue
New file @@ -0,0 +1,222 @@ <template> <el-dialog v-model="dialogVisible" title="请选择 关联应付账单" width="85%" destroy-on-close @close="handleClose" append-to-body> <div class="search-bar"> <el-form inline :model="queryParams" class="search-form" size="default"> <el-form-item label="系统编号:"> <el-input v-model="queryParams.systemNo" placeholder="请输入系统编号" style="width: 180px" clearable /> </el-form-item> <el-form-item label="账单名称:"> <el-input v-model="queryParams.billName" placeholder="请输入账单名称" style="width: 180px" clearable /> </el-form-item> <el-form-item label="供应商名称:"> <el-input v-model="queryParams.supplierName" placeholder="请输入供应商名称" style="width: 180px" clearable /> </el-form-item> <!-- <el-form-item label="状态:"> <el-select v-model="queryParams.status" style="width: 150px;" placeholder="请选择状态" clearable> <el-option v-for="dict in sys_bill_status" :key="dict.value" :label="dict.label" :value="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" row-key="id" @current-change="handleRowSelect" class="customer-table"> <el-table-column prop="systemNo" label="系统编号" min-width="150" show-overflow-tooltip /> <el-table-column prop="billName" label="账单名称" min-width="150" show-overflow-tooltip /> <el-table-column prop="supplierName" label="供应商名称" min-width="150" show-overflow-tooltip /> <el-table-column prop="isInternalSettlement" label="是否内部结算" min-width="120"> <template #default="scope"> {{ dictFormat(sys_whether_type, scope.row.isInternalSettlement) }} </template> </el-table-column> <el-table-column prop="internalSettlementUnit" label="内部结算单位" min-width="120" show-overflow-tooltip /> <el-table-column prop="documentCount" label="单据数量" min-width="100" /> <el-table-column prop="totalAmount" label="应结算金额" min-width="120" /> <el-table-column prop="currency" label="币制" min-width="100"> <template #default="scope"> {{ dictFormat(sys_currency, scope.row.currency) }} </template> </el-table-column> <el-table-column prop="discountAmount" label="减免金额" min-width="100" /> <el-table-column prop="paidAmount" label="已付金额" min-width="100" /> <el-table-column prop="pendingAmount" label="待付金额" min-width="100" /> <el-table-column prop="status" label="状态" width="100"> <template #default="scope"> {{ dictFormat(sys_bill_status, scope.row.status) }} </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> <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 type { Table } from 'element-plus'; import { ElMessage } from 'element-plus'; import useCurrentInstance from "@/utils/useCurrentInstance"; import { listPayableBillManagement } from "@/api/cwgl/payableBillManagement"; interface Customer { id: string | number; systemNo: string; billName: string; supplierName: string; isInternalSettlement: string; internalSettlementUnit: string; documentCount: number; totalAmount: number; currency: string; discountAmount: number; paidAmount: number; pendingAmount: number; status: string | number; } const props = defineProps({ visible: { type: Boolean, default: false }, defaultSelectedId: { type: [String, Number], default: '' }, // 新增:接收默认状态 defaultStatus: { type: [String, Number], default: '' } }); const emit = defineEmits(['confirm', 'close', 'update:visible']); const { proxy } = useCurrentInstance(); // 获取所需的字典 const { sys_bill_status, sys_currency, sys_whether_type } = proxy.useDict( 'sys_bill_status', 'sys_currency', 'sys_whether_type' ); const dictFormat = (dict: any, value: any) => { return proxy.selectDictLabel(dict, value); }; const dialogVisible = ref(false); const customerList = ref<Customer[]>([]); const total = ref(0); const selectedRow = ref<Customer | null>(null); const customerTableRef = ref<InstanceType<typeof Table>>(); const queryParams = reactive({ systemNo: '', billName: '', supplierName: '', status: '', pageNum: 1, pageSize: 10 }); const getDataList = async () => { try { const res = await listPayableBillManagement(queryParams); if (res.code === 200) { customerList.value = res.rows; total.value = res.total; return res.rows; } } catch (err) { console.error('加载列表失败:', err); } return []; }; const autoSelectRow = (list: Customer[]) => { if (!props.defaultSelectedId || list.length === 0) return; nextTick(() => { const target = list.find(item => String(item.id) === String(props.defaultSelectedId)); if (target && customerTableRef.value) { customerTableRef.value.setCurrentRow(target); selectedRow.value = target; } }); }; const handleSearch = () => { queryParams.pageNum = 1; getList(); }; const handleReset = () => { // 重置其他搜索字段 queryParams.systemNo = ''; queryParams.billName = ''; queryParams.customerName = ''; // 核心处理:如果有默认状态值就恢复默认值,没有才设为空 if (props.defaultStatus !== undefined && props.defaultStatus !== null && props.defaultStatus !== '') { queryParams.status = props.defaultStatus; } else { queryParams.status = ''; } handleSearch(); }; const getList = () => { getDataList().then((list) => { autoSelectRow(list); }); }; const handleRowSelect = (val: Customer | null) => { selectedRow.value = val; }; const handleConfirm = () => { if (!selectedRow.value) { ElMessage.warning('请先点击表格选择一行数据'); return; } emit('confirm', selectedRow.value); handleClose(); }; const handleClose = () => { emit('update:visible', false); emit('close'); }; watch(() => props.visible, (newVal) => { dialogVisible.value = newVal; if (newVal) { // 关键逻辑:如果 props 传了默认状态就用它,否则设置为空字符串 // 使用 queryParams.status = props.defaultStatus || ''; // 但考虑到 '0' 可能是有效值,建议判断是否为 undefined 或 null if (props.defaultStatus !== undefined && props.defaultStatus !== null) { queryParams.status = props.defaultStatus; } else { queryParams.status = ''; } // 重置页码为第一页并加载数据 queryParams.pageNum = 1; getList(); } }); </script> ui/admin-ui3/src/components/ClaimBillDialog/index.vue
New file @@ -0,0 +1,543 @@ <template> <el-dialog v-model="visible" title="账单认领" width="1150px" destroy-on-close :close-on-click-modal="false"> <div style="text-align: right;margin-bottom: 10px;"> <el-button type="warning" v-if="isViewMode" plain icon="Download" @click="handleExport" v-hasPermi="['cwgl:fundFlowClaimDetail:export']">导出 </el-button> <!-- <el-button type="primary" @click="handleFinalSubmit">确 定</el-button> --> </div> <div class="claim-wrapper"> <!-- <div class="section-header">流水详细信息</div> --> <el-descriptions :column="3" border class="mb-20"> <el-descriptions-item label="id">{{ detail.id }}</el-descriptions-item> <el-descriptions-item label="银行流水号">{{ detail.bankFlowNo }}</el-descriptions-item> <el-descriptions-item label="单位">{{ detail.company }}</el-descriptions-item> <el-descriptions-item label="本方账号">{{ detail.ourAccount }}</el-descriptions-item> <el-descriptions-item label="本方账户开户行">{{ detail.ourBankName }}</el-descriptions-item> <el-descriptions-item label="收支标识"> {{ dictFormat(sys_income_expenses, detail.incomeExpenseFlag) }} </el-descriptions-item> <el-descriptions-item label="交易金额"> <span class="amount-text">{{ detail.transactionAmount }}</span> </el-descriptions-item> <el-descriptions-item label="交易币种">{{ detail.currency }}</el-descriptions-item> <el-descriptions-item label="对方账号">{{ detail.counterpartyAccount }}</el-descriptions-item> <el-descriptions-item label="对方户名">{{ detail.counterpartyName }}</el-descriptions-item> <el-descriptions-item label="交易日期">{{ detail.transactionDate }}</el-descriptions-item> <el-descriptions-item label="用途">{{ detail.purpose }}</el-descriptions-item> <el-descriptions-item label="摘要" :span="1">{{ detail.summary }}</el-descriptions-item> <el-descriptions-item label="附言" :span="1">{{ detail.remarks }}</el-descriptions-item> <el-descriptions-item label="已认领金额">{{ detail.claimedAmount || 0 }}</el-descriptions-item> <el-descriptions-item label="待认领金额"> <span class="text-danger font-bold">{{ remainingAmountDr }}</span> </el-descriptions-item v-if="isViewMode"> <el-descriptions-item label="关联账单类型"> <span v-if="detail.incomeExpenseFlag == 0"> 供应商 </span> <span v-if="detail.incomeExpenseFlag == 1"> 客户 </span> </el-descriptions-item> <el-descriptions-item label="" :span="1"></el-descriptions-item> </el-descriptions> <div class="section-header">{{ isViewMode ? '账单认领明细' : '账单认领' }}</div> <div v-if="!isViewMode" class="type-selection-bar mb-20"> <span class="required-label">关联账单类型</span> <el-radio-group v-model="detail.incomeExpenseFlag" disabled @change="handleTypeChange"> <el-radio :label="0">应收账单</el-radio> <el-radio :label="1">应付账单</el-radio> </el-radio-group> </div> <div v-if="!isViewMode" class="mb-10"> <el-button type="primary" icon="Plus" @click="handleAddRow">新增</el-button> </div> <el-table :data="detail.claimDetails" border stripe> <el-table-column label="账单编号" min-width="220"> <template #default="{ row, $index }"> <el-input v-model="row.billNo" @click="openReceivableDialog($index)" :disabled="!row.$edit" readonly placeholder="点击选择账单"> <template v-if="row.$edit" #append> <el-button icon="Search" @click="openReceivableDialog($index)" :disabled="!row.$edit" /> </template> </el-input> </template> </el-table-column> <el-table-column label="关联企业类型" width="120"> <template #default="{ row }"> <span>{{ row.relatedCompanyType }}</span> </template> </el-table-column> <el-table-column label="关联企业名称" width="150"> <template #default="{ row }"> <span>{{ row.relatedCompanyName }}</span> </template> </el-table-column> <el-table-column label="账单金额" width="120"> <template #default="{ row }"> <span>{{ row.billAmount || 0 }}</span> </template> </el-table-column> <el-table-column label="账单待结算金额" width="130"> <template #default="{ row }"> <span>{{ row.billPendingAmount || 0 }}</span> </template> </el-table-column> <el-table-column label="认领金额" width="150"> <template #default="{ row }"> <el-input-number v-model="row.claimAmount" :precision="2" :controls="false" :disabled="!row.$edit" :min="0" style="width: 100%" placeholder="输入金额" @change="(val) => handleAmountChange(val, row)" /> </template> </el-table-column> <el-table-column label="认领日期" width="200"> <template #default="{ row }"> <el-date-picker v-model="row.claimDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" :disabled="!row.$edit" style="width: 100%" placeholder="选择日期时间" /> </template> </el-table-column> <el-table-column label="备注"> <template #default="{ row }"> <el-input v-model="row.remark" :disabled="!row.$edit" placeholder="备注信息" /> </template> </el-table-column> <el-table-column label="操作" v-if="!isViewMode" width="120" fixed="right" align="center"> <template #default="{ row, $index }"> <template v-if="row.$edit"> <el-button type="primary" link @click="handleSaveRow(row)">确定</el-button> </template> <template v-else> <!-- <el-button type="primary" link @click="row.$edit = true">修改</el-button> --> <el-button type="danger" link @click="handleDeleteRow(row)">删除</el-button> </template> </template> </el-table-column> </el-table> <pagination v-show="total > 10" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> </div> <template #footer> <div style="text-align: center;"> <el-button @click="handleCancel">关 闭</el-button> <!-- <el-button type="primary" @click="handleFinalSubmit">确 定</el-button> --> </div> </template> </el-dialog> <receivableBillManagementDialog :default-status="-1" v-model:visible="receivablIshow" :default-selected-id="detail.invoiceManageId" @confirm="receivablForm" /> <AccountsPayableManagementDialog :default-status="-1" v-model:visible="accountsIshow" :default-selected-id="detail.invoiceManageId" @confirm="accountsForm" /> </template> <script setup lang="ts"> import { ref, computed } from 'vue'; import { ElMessage, ElMessageBox } from 'element-plus'; import useCurrentInstance from "@/utils/useCurrentInstance"; import receivableBillManagementDialog from "../receivableBillManagementDialog/index.vue"; import AccountsPayableManagementDialog from "../AccountsPayableManagementDialog/index.vue"; import { addFundFlowClaimDetailClaim } from "@/api/cwgl/fundFlow"; import { delFundFlowClaimDetail, } from "@/api/cwgl/fundFlowClaimDetail"; import { listFundFlowClaimDetail } from "@/api/cwgl/fundFlowClaimDetail"; const { proxy } = useCurrentInstance(); const { sys_income_expenses } = proxy.useDict('sys_income_expenses'); const dictFormat = (dict: any, value: any) => proxy.selectDictLabel(dict, value); const emit = defineEmits(['submit']); const visible = ref(false); const detail = ref<any>({ claimDetails: [] }); const billType = ref(''); // 1. 【待认领金额计算】: 交易金额 - 已认领金额 ) const remainingAmountDr = computed(() => { const total = parseFloat(detail.value.transactionAmount) || 0; const alreadyClaimed = parseFloat(detail.value.claimedAmount) || 0; const res = total - alreadyClaimed; return res.toFixed(2); }); // 1. 实时计算待认领池子(剩余总额) const remainingAmount = computed(() => { const total = parseFloat(detail.value.transactionAmount) || 0; // 流水总额 const historicClaimed = parseFloat(detail.value.claimedAmount) || 0; // 历史已认领 // 累加当前表格中所有行填写的金额 const currentTableTotal = (detail.value.claimDetails || []).reduce((sum, item) => { return sum + (parseFloat(item.claimAmount) || 0); }, 0); const res = total - historicClaimed - currentTableTotal; return res.toFixed(2); }); // 修正后的函数 const handleAmountChange = (val: number | null, row: any) => { if (val === null) return; // 1. 获取池子剩余(需要加回当前行金额) const currentRemaining = parseFloat(remainingAmount.value) || 0; const currentLineAmount = val || 0; // 计算此时如果没填这一行,池子有多少钱 // 注意:这里因为 val 已经改变了,remainingAmount 已经减去了新的 val // 所以池子可用总量 = remainingAmount + val const totalAvailablePool = currentRemaining + currentLineAmount; // 2. 确定两个上限 const limitByBill = row.billAmount || 0; // 账单上限 const limitByPool = totalAvailablePool; // 流水上限 // 3. 校验并修正 if (val > limitByBill) { ElMessage.warning(`认领金额不能超过账单金额 (${limitByBill})`); row.claimAmount = limitByBill; } else if (val > limitByPool) { ElMessage.warning(`认领金额不能超过流水待认领金额 (${limitByPool.toFixed(2)})`); // row.claimAmount = parseFloat(limitByPool.toFixed(2)); } }; // 建议保留 getMaxClaimAmount 作为一个保险上限,或者直接删除它 const getMaxClaimAmount = (row: any) => { // 为了不干扰输入过程,这里返回一个极大的安全值,或者流水总金额 return parseFloat(detail.value.transactionAmount) || 99999999; }; // 重置表单和数据 const resetForm = () => { // 1. 清空明细表格 detail.value = { claimDetails: [], // 如果有其他需要清空的流水基础信息,也可以在这里初始化 transactionAmount: 0, claimedAmount: 0 }; // 2. 清空选择的账单类型 billType.value = ''; // 3. 重置索引和弹窗控制变量 currentRowIndex.value = null; receivablIshow.value = false; accountsIshow.value = false; }; // 取消按钮点击事件 const handleCancel = () => { visible.value = false; resetForm(); }; const isViewMode = ref(false); // 新增:模式控制 // --- 新增:分页与搜索相关的响应式变量 --- const total = ref(0); const loading = ref(false); const queryParams = ref({ pageNum: 1, pageSize: 10, fundFlowId: null as any // 关联的流水ID }); // --- 新增:获取列表数据的方法 --- const getList = async () => { if (!detail.value.id) return; loading.value = true; try { const res = await listFundFlowClaimDetail({ ...queryParams.value, fundFlowId: detail.value.id }); if (res.code === 200) { detail.value.claimDetails = res.rows; detail.value.claimDetails.forEach((item: any) => { if (item.$edit === undefined) { item.$edit = false; } }); total.value = res.total; } } catch (error) { console.error("获取明细列表失败", error); } finally { loading.value = false; } }; const handleExport =()=>{ proxy.download("/cwgl/fundFlowClaimDetail/export",{...queryParams.value}) } // 打开弹窗 const open = (rowData: any, mode: 'view' | 'edit' = 'edit') => { // 1. 先重置一次,防止上次残留 resetForm(); isViewMode.value = mode === 'view'; // 设置模式 // 2. 浅拷贝基础数据 detail.value = { ...rowData, }; // 3. 处理 billType 的自动回显逻辑 if (detail.value.claimDetails && detail.value.claimDetails.length > 0) { // 取出第一条明细的关联企业类型 const firstCompanyType = detail.value.claimDetails[0].relatedCompanyType; if (firstCompanyType === '客户') { billType.value = 'RECEIVABLE'; } else if (firstCompanyType === '供应商') { billType.value = 'PAYABLE'; } // 如果有ID,则请求后端明细数据 // 确保已有的数据行不会变成编辑模式 getList() } visible.value = true; }; // 关联账单类型切换逻辑 const handleTypeChange = (val: string) => { if (detail.value.claimDetails && detail.value.claimDetails.length > 0) { ElMessageBox.confirm('切换账单类型将清空当前已添加的认领明细,是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { detail.value.claimDetails = []; ElMessage.success('已清空明细'); }).catch(() => { billType.value = val === 'RECEIVABLE' ? 'PAYABLE' : 'RECEIVABLE'; }); } }; // 新增行 // 修改新增行逻辑 const handleAddRow = () => { const defaultCompanyType = detail.value.incomeExpenseFlag == '0' ? '客户' : '供应商'; // 获取当前时间的 YYYY-MM-DD HH:mm:ss 格式 const now = new Date(); const formatTime = (date: Date) => { const pad = (num: number) => String(num).padStart(2, '0'); return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` + `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`; }; detail.value.claimDetails.push({ billNo: '', claimAmount: 0, claimDate: formatTime(now), // 使用带时分秒的默认值 remark: '', relatedCompanyType: defaultCompanyType, relatedCompanyName: '', billAmount: 0, billPendingAmount: 0, $edit: true }); }; // 保存行 const handleSaveRow = (row: any) => { if (!row.billNo) return ElMessage.warning('请选择账单编号'); // 转换数值,确保计算准确 const currentClaim = parseFloat(row.claimAmount) || 0; if (currentClaim <= 0) return ElMessage.warning('认领金额必须大于0'); // 1. 获取当前计算属性中的剩余额度(此时已经扣除了所有行的 claimAmount) const currentRemaining = parseFloat(remainingAmount.value) || 0; // 2. 【关键】计算该行实际可用的“剩余池子上限” // 公式:池子真实余量 = 当前显示的余额 + 该行刚才占用的额度 const poolLimit = currentRemaining + currentClaim; // 3. 获取账单本身的上限 const billLimit = row.billPendingAmount || row.billAmount || 0; // --- 开始拦截判定 --- // 判定 A:超过账单欠款 if (currentClaim > billLimit) { return ElMessage.error(`保存失败:认领金额不能超过账单待结算金额 (${billLimit})`); } // 判定 B:超过流水总余量 // 使用 0.01 容差防止 JS 浮点数计算误差 if (currentClaim > (poolLimit + 0.01)) { return ElMessage.error(`保存失败:认领总额超过流水待认领金额,该行当前最大可填 ${poolLimit.toFixed(2)}`); } addFundFlowClaimDetailClaim(row, detail.value.id).then((response) => { if (response.code == 200) { proxy.$modal.msgSuccess("保存成功"); getList(); // 使用统一的 getList 方法 } }) }; const handleDeleteRow = (row: any) => { proxy.$modal.confirm('是否确认删除账单编号为"' + row.billNo + '"?').then(function () { return delFundFlowClaimDetail(row.id); }).then((res) => { if (res.code == 200) { proxy.$modal.msgSuccess("删除成功"); getList(); // 使用统一的 getList 方法 } }).catch(() => { }); }; const receivablIshow = ref(false); const currentRowIndex = ref<number | null>(null); const accountsIshow = ref(false); const openReceivableDialog = (index: number) => { currentRowIndex.value = index; if (detail.value.incomeExpenseFlag == '0') { receivablIshow.value = true; } else if (detail.value.incomeExpenseFlag == '1') { accountsIshow.value = true; } }; // 回填弹窗选中的数据 const receivablForm = (data: any) => { const defaultCompanyType = billType.value === 'RECEIVABLE' ? '客户' : '供应商'; if (currentRowIndex.value !== null && data) { const row = detail.value.claimDetails[currentRowIndex.value]; row.billNo = data.systemNo row.relatedCompanyType = defaultCompanyType; row.relatedCompanyName = data.customerName row.billAmount = data.totalAmount || 0; row.billPendingAmount = data.pendingAmount || 0; currentRowIndex.value = null; receivablIshow.value = false; } }; const accountsForm = (data: any) => { const defaultCompanyType = billType.value === 'RECEIVABLE' ? '客户' : '供应商'; if (currentRowIndex.value !== null && data) { const row = detail.value.claimDetails[currentRowIndex.value]; row.billNo = data.systemNo row.relatedCompanyType = defaultCompanyType; row.relatedCompanyName = data.supplierName row.billAmount = data.totalAmount || 0; row.billPendingAmount = data.pendingAmount || 0; currentRowIndex.value = null; accountsIshow.value = false; } }; // 确定提交 const handleFinalSubmit = () => { if (!billType.value) return ElMessage.warning('请选择关联账单类型'); if (detail.value.claimDetails.length === 0) return ElMessage.warning('请添加至少一条认领明细'); const hasEditing = detail.value.claimDetails.some((row: any) => row.$edit); if (hasEditing) return ElMessage.warning('请先保存正在编辑的明细行'); if (parseFloat(remainingAmount.value) < 0) { return ElMessage.error('最终认领总额不能超过流水待认领金额'); } emit('submit', detail.value); // console.log("提交数据:", detail.value); // ElMessage.success('操作成功'); // visible.value = false; }; defineExpose({ open, handleCancel }); </script> <style scoped> .claim-wrapper { padding: 0 10px; } .section-header { font-size: 16px; font-weight: bold; margin: 15px 0 10px; border-left: 4px solid #409eff; padding-left: 10px; color: #303133; } .type-selection-bar { display: flex; align-items: center; gap: 20px; background: #f8f9fb; padding: 10px 15px; border-radius: 4px; } .required-label { font-size: 14px; font-weight: bold; color: #606266; } .required-label::before { content: '*'; color: #f56c6c; margin-right: 4px; } .amount-text { color: #409eff; font-weight: bold; } .text-danger { color: #f56c6c; } .font-bold { font-weight: bold; } .mb-20 { margin-bottom: 20px; } .mb-10 { margin-bottom: 10px; } :deep(.el-input.is-disabled .el-input__wrapper) { background-color: transparent; box-shadow: none; } :deep(.el-descriptions__body .el-descriptions__table.is-bordered .el-descriptions__cell) { width: 16%; } </style> ui/admin-ui3/src/components/receivableBillManagementDialog/index.vue
@@ -15,11 +15,11 @@ <el-input v-model="queryParams.customerName" placeholder="请输入客户名称" style="width: 180px" clearable /> </el-form-item> <el-form-item label="状态:"> <!-- <el-form-item label="状态:"> <el-select v-model="queryParams.status" style="width: 150px;" placeholder="请选择状态" clearable> <el-option v-for="dict in sys_bill_status" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select> </el-form-item> </el-form-item> --> <el-form-item> <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button> @@ -79,7 +79,9 @@ const props = defineProps({ visible: { type: Boolean, default: false }, defaultSelectedId: { type: [String, Number], default: '' } defaultSelectedId: { type: [String, Number], default: '' }, // 新增:接收默认状态 defaultStatus: { type: [String, Number], default: '' } }); const emit = defineEmits(['confirm', 'close', 'update:visible']); @@ -138,11 +140,18 @@ }; const handleReset = () => { // 重置字段必须与 queryParams 定义的一致 // 重置其他搜索字段 queryParams.systemNo = ''; queryParams.billName = ''; queryParams.customerName = ''; // 核心处理:如果有默认状态值就恢复默认值,没有才设为空 if (props.defaultStatus !== undefined && props.defaultStatus !== null && props.defaultStatus !== '') { queryParams.status = props.defaultStatus; } else { queryParams.status = ''; } handleSearch(); }; @@ -173,6 +182,17 @@ watch(() => props.visible, (newVal) => { dialogVisible.value = newVal; if (newVal) { // 关键逻辑:如果 props 传了默认状态就用它,否则设置为空字符串 // 使用 queryParams.status = props.defaultStatus || ''; // 但考虑到 '0' 可能是有效值,建议判断是否为 undefined 或 null if (props.defaultStatus !== undefined && props.defaultStatus !== null) { queryParams.status = props.defaultStatus; } else { queryParams.status = ''; } // 重置页码为第一页并加载数据 queryParams.pageNum = 1; getList(); } }); ui/admin-ui3/src/views/cwgl/fundFlow/index.vue
@@ -1,61 +1,65 @@ <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" > <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:fundFlow:edit']" <!-- <el-button type="success" icon="Edit" :disabled="pageF.single" v-hasPermi="['cwgl:fundFlow:edit']" @click="handleUpdate">修改 </el-button> <el-button type="danger" icon="Delete" :disabled="pageF.multiple" @click="handleDelete" v-hasPermi="['cwgl:fundFlow:remove']" >删除 <el-button type="danger" icon="Delete" :disabled="pageF.multiple" @click="handleDelete" v-hasPermi="['cwgl:fundFlow:remove']">删除 </el-button> --> <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['cwgl:fundFlow:export']">导出 </el-button> <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['cwgl:fundFlow:export']" >导出 </el-button> </template> <template #menu="{ size, row, index }"> <el-link v-if="row.status == '0'" class="link-btn" type="primary" icon="Edit" :underline="false" :size="size" @click="crudRef.rowEdit(row, index)"> 修改 </el-link> <el-link v-if="row.status == '0'" class="link-btn" type="primary" icon="Position" :underline="false" :size="size" @click="makeInvoice(row)" v-hasPermi="['cwgl:fundFlow:confirm']"> 确认 </el-link> <el-link v-if="row.status == '0'" class="link-btn" type="primary" icon="Delete" :underline="false" :size="size" @click="crudRef.rowDel(row, index)"> 删除 </el-link> <el-link v-if="['1', '2'].includes(String(row.status))" class="link-btn" type="primary" icon="Position" :underline="false" :size="size" @click="handleClaim(row)" v-hasPermi="['cwgl:fundFlow:claim']"> 账单认领 </el-link> <el-link v-if="['1', '2','3'].includes(String(row.status))" class="link-btn" type="primary" icon="Position" :underline="false" :size="size" @click="handleDetails(row)" v-hasPermi="['cwgl:fundFlow:edit']"> 认领明细 </el-link> <el-button type="text" icon="View" @click="handleFlow(row)" v-hasPermi="['cwgl:fundFlow:flow']">日志</el-button> <!-- <el-button type="text" icon="View" @click="handleFlow(row)" v-hasPermi="['cwgl:invoiceManage:flow']">日志</el-button> --> </template> </avue-crud> </basicContainer> <OperationLogModal ref="logModalRef" /> <ClaimBillDialog ref="claimDialogRef" @submit="handleClaimSubmit" /> </template> <script setup name="fundFlow" lang="ts"> import {FundFlowI,addFundFlow, delFundFlow, exportFundFlow, getFundFlow, listFundFlow, updateFundFlow} from "@/api/cwgl/fundFlow"; import { FundFlowI, addFundFlow, delFundFlow, addFundFlowClaimDetailClaim, exportFundFlow, confirmFundFlow, getFundFlow, listFundFlow, updateFundFlow } from "@/api/cwgl/fundFlow"; import useCurrentInstance from "@/utils/useCurrentInstance"; import { listFundFlowLog} from "@/api/cwgl/fundFlowLog"; import {computed,reactive, ref, toRefs} from "vue"; import {PagesInterface, PageQueryInterface} from "@/utils/globalInterface"; import {usePagePlus} from "@/hooks/usePagePlus"; import {hasPermission} from "@/utils/permissionUtils"; import { listFundFlowClaimDetail } from "@/api/cwgl/fundFlowClaimDetail"; import OperationLogModal from '@/components/OperationLogModal/index.vue'; import ClaimBillDialog from "../../../components/ClaimBillDialog/index.vue"; const { proxy } = useCurrentInstance(); const crudRef = ref(); @@ -83,70 +87,132 @@ const option = ref({ pageKey: 'FundFlow', rowKey: 'id', searchSpan: 5, labelWidth: 180, searchLabelWidth: 150, delBtn: false, editBtn: false, column: { id: { label: 'ID', }, // id: { // label: 'ID', // }, bankFlowNo: { label: '银行流水号', minWidth: 120, search: true, rules: [ { required: true, message: "银行流水号不能为空", trigger: "blur" } ], }, message: "银行流水号不能为空", trigger: "blur" } ], }, company: { label: '单位', minWidth: 120, }, ourAccount: { label: '本方账号', search: true, minWidth: 120, }, ourBankName: { label: '本方账户开户行', minWidth: 120, }, incomeExpenseFlag: { label: '收支标识借贷标志 0-收 1-支', label: '收支标识', type: 'radio', // 设置为单选按钮 search: true, // 如果需要在搜索栏也显示 dicUrl: '/system/dict/data/type/sys_income_expenses', rules: [ { required: true, message: "请选择收支标识", trigger: "blur" } ], }, transactionAmount: { label: '交易金额', }, currency: { label: '交易币种', search: true, minWidth: 120, dataType: 'string', type: 'select', // addDisplay: false, // 新增时不显示 // editDisplay: false, // 修改时不显示 viewDisplay: false, dicUrl: '/system/dict/data/type/sys_currency', }, counterpartyAccount: { minWidth: 150, label: '对方账号', search: true, }, counterpartyName: { minWidth: 150, label: '对方户名', search: true, }, transactionDate: { minWidth: 200, // search: true, label: '交易日期', type: 'datetime', // 类型改为 datetime format: 'YYYY-MM-DD HH:mm:ss', // 界面显示的格式 valueFormat: 'YYYY-MM-DD HH:mm:ss', // 提交给后台的数据格式 // search: true, // 如果开启搜索 rules: [ { required: true, message: "请选择交易日期", trigger: "change" } ], }, purpose: { label: '用途', minWidth: 150, }, summary: { label: '摘要', type: 'textarea', minRows: 3, maxRows: 5, hide: true, }, remarks: { label: '附言', hide: true, type: 'textarea', minRows: 3, maxRows: 5, }, createBy: { label: '创建者', status: { minWidth: 120, label: '状态', fixed: 'right', value: '0', addDisplay: false, // 表单不显示 editDisplay: false, viewDisplay: true, dicUrl: '/system/dict/data/type/sys_capital_status', }, createTime: { label: '创建时间', }, updateBy: { label: '更新者', }, updateTime: { label: '更新时间', }, delFlag: { label: '删除标志', }, // createBy: { // label: '创建者', // }, // createTime: { // label: '创建时间', // }, // updateBy: { // label: '更新者', // }, // updateTime: { // label: '更新时间', // }, // delFlag: { // label: '删除标志', // }, } }) @@ -172,4 +238,68 @@ }) const makeInvoice = (row: any) => { proxy.$modal.confirm('是否确认银行流水号为"' + row.bankFlowNo + '"?').then(function () { return confirmFundFlow(row.id); }).then(() => { onLoad(page.value); proxy.$modal.msgSuccess("确认成功"); }).catch(() => { }); } const claimDialogRef = ref(); // fundFlowId const handleClaim = (row: any) => { getFundFlow(row.id).then((response) => { if (response.code == 200) { listFundFlowClaimDetail({ fundFlowId: row.id }).then((res) => { if (res.code == 200) { response.data.claimDetails = res.rows; claimDialogRef.value.open(response.data); claimDialogRef.value.open(response.data, 'edit'); } }) } }) }; const handleClaimSubmit = (payload) => { addFundFlowClaimDetailClaim(payload.claimDetails, payload.id).then((response) => { if (response.code == 200) { onLoad(page.value); proxy.$modal.msgSuccess("认领成功"); claimDialogRef.value.handleCancel(); } }) // console.log("最终提交给后端的数据包:", payload); }; const handleDetails = (row: any) => { getFundFlow(row.id).then((response) => { if (response.code == 200) { listFundFlowClaimDetail({ fundFlowId: row.id }).then((res) => { if (res.code == 200) { response.data.claimDetails = res.rows; claimDialogRef.value.open(response.data, 'view'); } }) } }) }; const logModalRef = ref(null); const handleFlow = (row: any,) => { // 这里可以从 row 中直接获取日志,或者调用后端接口查询 listFundFlowLog({flowId:row.id}).then((res) => { if (res.code == 200) { logModalRef.value.open(res.rows,'payable'); } }); } /* listFundFlowClaimDetail */ </script> ui/admin-ui3/src/views/cwgl/fundFlowClaimDetail/index.vue
@@ -1,48 +1,19 @@ <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" > <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:fundFlowClaimDetail:edit']" <el-button type="success" icon="Edit" :disabled="pageF.single" v-hasPermi="['cwgl:fundFlowClaimDetail:edit']" @click="handleUpdate">修改 </el-button> <el-button type="danger" icon="Delete" :disabled="pageF.multiple" @click="handleDelete" v-hasPermi="['cwgl:fundFlowClaimDetail:remove']" >删除 <el-button type="danger" icon="Delete" :disabled="pageF.multiple" @click="handleDelete" v-hasPermi="['cwgl:fundFlowClaimDetail:remove']">删除 </el-button> <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['cwgl:fundFlowClaimDetail:export']" >导出 <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['cwgl:fundFlowClaimDetail:export']">导出 </el-button> </template> </avue-crud> @@ -92,15 +63,19 @@ rules: [ { required: true, message: "资金流水ID不能为空", trigger: "blur" } ], }, message: "资金流水ID不能为空", trigger: "blur" } ], }, billNo: { label: '账单编号', rules: [ { required: true, message: "账单编号不能为空", trigger: "blur" } ], }, message: "账单编号不能为空", trigger: "blur" } ], }, relatedCompanyType: { label: '关联企业类型', },