From 8c650e7ef2b4e9232c98f2c34bcc691632972673 Mon Sep 17 00:00:00 2001 From: luojiaquan <1583622118@qq.com> Date: Mon, 21 Sep 2026 17:35:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=99=E9=A2=9D=E9=A2=9D=E5=BA=A6=E6=B5=81?= =?UTF-8?q?=E6=B0=B4=E5=8A=A0=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomerMoneyController.java | 60 +++++++++ .../vo/CustomerBalanceFlowExportVO.java | 91 ++++++++++++++ .../vo/CustomerCreditFlowExportVO.java | 117 ++++++++++++++++++ .../vo/CustomerReceiptExportVO.java | 116 +++++++++++++++++ .../src/components/ColumnSettings/index.vue | 70 +++++++++++ bms-front/src/directive/index.js | 2 + .../src/directive/resizableColumn/index.js | 93 ++++++++++++++ bms-front/src/main.js | 3 + bms-front/src/utils/columnSettings.js | 50 ++++++++ .../customerinfo/customermoney/index.vue | 39 ++++++ .../customerinfo/index.vue | 70 +++++++---- .../supplierinfo/index.vue | 79 ++++++++---- 12 files changed, 743 insertions(+), 47 deletions(-) create mode 100644 bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerBalanceFlowExportVO.java create mode 100644 bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerCreditFlowExportVO.java create mode 100644 bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerReceiptExportVO.java create mode 100644 bms-front/src/components/ColumnSettings/index.vue create mode 100644 bms-front/src/directive/resizableColumn/index.js create mode 100644 bms-front/src/utils/columnSettings.js diff --git a/bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/customer/customermoney/CustomerMoneyController.java b/bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/customer/customermoney/CustomerMoneyController.java index 9fee4e76..3f8d17bc 100644 --- a/bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/customer/customermoney/CustomerMoneyController.java +++ b/bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/customer/customermoney/CustomerMoneyController.java @@ -2,6 +2,8 @@ package com.ruoyi.web.controller.customer.customermoney; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -17,6 +19,7 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.customer.customermoney.api.ICustomerAccountApi; import com.ruoyi.customer.customermoney.domain.CustomerBalanceFlow; import com.ruoyi.customer.customermoney.domain.CustomerCreditApply; @@ -25,6 +28,9 @@ import com.ruoyi.customer.customermoney.domain.CustomerReceipt; import com.ruoyi.customer.customermoney.service.ICreditQuotaService; import com.ruoyi.customer.customermoney.service.ICustomerMoneyService; import com.ruoyi.customer.customermoney.vo.CustomerAccountStatusVO; +import com.ruoyi.customer.customermoney.vo.CustomerBalanceFlowExportVO; +import com.ruoyi.customer.customermoney.vo.CustomerCreditFlowExportVO; +import com.ruoyi.customer.customermoney.vo.CustomerReceiptExportVO; import com.ruoyi.common.utils.SecurityUtils; /** @@ -89,6 +95,24 @@ public class CustomerMoneyController extends BaseController List list = customerMoneyService.selectReceiptList(query); return getDataTable(list); } + + /** + * 导出收款记录(按当前筛选条件,全量导出不分页) + */ + @PreAuthorize("@ss.hasPermi('customersupplier:customerinfo:export')") + @Log(title = "客户收款记录", businessType = BusinessType.EXPORT) + @PostMapping("/receipt/export") + public void receiptExport(HttpServletResponse response, CustomerReceipt query) + { + List list = Collections.emptyList(); + if (query != null && query.getCustomerId() != null && query.getCustomerId() != 0L) + { + list = customerMoneyService.selectReceiptList(query).stream() + .map(CustomerReceiptExportVO::from).collect(Collectors.toList()); + } + ExcelUtil util = new ExcelUtil<>(CustomerReceiptExportVO.class); + util.exportExcel(response, list, "收款记录"); + } /** * 获取收款单详情(含收款附件) */ @@ -149,6 +173,24 @@ public class CustomerMoneyController extends BaseController return getDataTable(list); } + /** + * 导出余额流水(按当前筛选条件,全量导出不分页) + */ + @PreAuthorize("@ss.hasPermi('customersupplier:customerinfo:export')") + @Log(title = "客户余额流水", businessType = BusinessType.EXPORT) + @PostMapping("/flow/export") + public void flowExport(HttpServletResponse response, CustomerBalanceFlow query) + { + List list = Collections.emptyList(); + if (query != null && query.getCustomerId() != null && query.getCustomerId() != 0L) + { + list = customerMoneyService.selectFlowList(query).stream() + .map(CustomerBalanceFlowExportVO::from).collect(Collectors.toList()); + } + ExcelUtil util = new ExcelUtil<>(CustomerBalanceFlowExportVO.class); + util.exportExcel(response, list, "余额流水"); + } + /** * 查询额度流水列表 */ @@ -164,6 +206,24 @@ public class CustomerMoneyController extends BaseController return getDataTable(list); } + /** + * 导出额度流水(按当前筛选条件,全量导出不分页) + */ + @PreAuthorize("@ss.hasPermi('customersupplier:customerinfo:export')") + @Log(title = "客户额度流水", businessType = BusinessType.EXPORT) + @PostMapping("/credit/flow/export") + public void creditFlowExport(HttpServletResponse response, CustomerCreditFlow query) + { + List list = Collections.emptyList(); + if (query != null && query.getCustomerId() != null && query.getCustomerId() != 0L) + { + list = customerMoneyService.selectCreditFlowList(query).stream() + .map(CustomerCreditFlowExportVO::from).collect(Collectors.toList()); + } + ExcelUtil util = new ExcelUtil<>(CustomerCreditFlowExportVO.class); + util.exportExcel(response, list, "额度流水"); + } + /** * 提交额度调整申请(信用额度/临时额度),申请待审批通过后才真正调整额度 */ diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerBalanceFlowExportVO.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerBalanceFlowExportVO.java new file mode 100644 index 00000000..c30e7ab3 --- /dev/null +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerBalanceFlowExportVO.java @@ -0,0 +1,91 @@ +package com.ruoyi.customer.customermoney.vo; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.customer.customermoney.domain.CustomerBalanceFlow; +import lombok.Data; + +/** + * 客户余额流水导出 VO(列与页面余额流水 tab 对齐,枚举导出为中文文案) + * + * @author ruoyi + * @date 2026-09-21 + */ +@Data +public class CustomerBalanceFlowExportVO implements Serializable +{ + private static final long serialVersionUID = 1L; + + @Excel(name = "流水号", width = 22) + private String flowNo; + + @Excel(name = "时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Excel(name = "业务类型", width = 12) + private String bizTypeLabel; + + @Excel(name = "收支", width = 8) + private String directionLabel; + + @Excel(name = "原币金额", width = 16) + private String amountText; + + @Excel(name = "汇率", width = 12) + private String exchangeRate; + + @Excel(name = "本位币变动(CNY)", width = 18) + private BigDecimal baseChangeAmount; + + @Excel(name = "变动前余额", width = 14) + private BigDecimal beforeBalance; + + @Excel(name = "变动后余额", width = 14) + private BigDecimal afterBalance; + + @Excel(name = "关联单号", width = 22) + private String bizNo; + + @Excel(name = "操作人", width = 12) + private String createBy; + + @Excel(name = "备注", width = 30) + private String remark; + + public static CustomerBalanceFlowExportVO from(CustomerBalanceFlow f) + { + CustomerBalanceFlowExportVO vo = new CustomerBalanceFlowExportVO(); + vo.setFlowNo(f.getFlowNo()); + vo.setCreateTime(f.getCreateTime()); + vo.setBizTypeLabel(bizTypeLabel(f.getBizType())); + boolean income = f.getDirection() != null && f.getDirection() == 1; + vo.setDirectionLabel(income ? "收入" : "支出"); + String amt = f.getAmount() == null ? "" : f.getAmount().stripTrailingZeros().toPlainString(); + vo.setAmountText((f.getCurrency() == null ? "" : f.getCurrency() + " ") + amt); + vo.setExchangeRate(f.getExchangeRate() == null ? null : f.getExchangeRate().stripTrailingZeros().toPlainString()); + BigDecimal base = f.getBaseAmount() != null ? f.getBaseAmount() : f.getAmount(); + // 支出导出为负数(配合“收支”列阅读,同时保持 Excel 数值类型) + vo.setBaseChangeAmount(base == null ? null : (income ? base : base.negate())); + vo.setBeforeBalance(f.getBeforeBalance()); + vo.setAfterBalance(f.getAfterBalance()); + vo.setBizNo(f.getBizNo()); + vo.setCreateBy(f.getCreateBy()); + vo.setRemark(f.getRemark()); + return vo; + } + + private static String bizTypeLabel(String v) + { + if ("RECEIPT".equals(v)) return "收款"; + if ("AR_BILL".equals(v)) return "应收账单"; + if ("BILL_PAY".equals(v)) return "账单核销"; + if ("ORDER".equals(v)) return "计费订单"; + if ("REFUND".equals(v)) return "退款"; + if ("ADJUST".equals(v)) return "手工调整"; + if ("FREEZE".equals(v)) return "冻结"; + if ("UNFREEZE".equals(v)) return "解冻"; + return v; + } +} diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerCreditFlowExportVO.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerCreditFlowExportVO.java new file mode 100644 index 00000000..630787e8 --- /dev/null +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerCreditFlowExportVO.java @@ -0,0 +1,117 @@ +package com.ruoyi.customer.customermoney.vo; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.customer.customermoney.domain.CustomerCreditFlow; +import lombok.Data; + +/** + * 客户额度流水导出 VO(列与页面额度流水 tab 对齐,枚举导出为中文文案) + * + * @author ruoyi + * @date 2026-09-21 + */ +@Data +public class CustomerCreditFlowExportVO implements Serializable +{ + private static final long serialVersionUID = 1L; + + @Excel(name = "流水号", width = 22) + private String flowNo; + + @Excel(name = "时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Excel(name = "业务单号", width = 22) + private String bizNo; + + @Excel(name = "变动类型", width = 12) + private String changeTypeLabel; + + @Excel(name = "变动维度", width = 18) + private String dimensionLabel; + + @Excel(name = "调整方式", width = 10) + private String adjustModeLabel; + + @Excel(name = "方向", width = 8) + private String directionLabel; + + @Excel(name = "变动前", width = 12) + private BigDecimal beforeAmount; + + @Excel(name = "变动额", width = 12) + private BigDecimal changeAmount; + + @Excel(name = "变动后", width = 12) + private BigDecimal afterAmount; + + @Excel(name = "已用额度快照", width = 14) + private BigDecimal usedCredit; + + @Excel(name = "生效日期", width = 12, dateFormat = "yyyy-MM-dd") + private Date effectiveDate; + + @Excel(name = "失效日期", width = 12) + private String expireDateText; + + @Excel(name = "调整原因", width = 30) + private String reason; + + @Excel(name = "操作人", width = 12) + private String createBy; + + @Excel(name = "备注", width = 30) + private String remark; + + public static CustomerCreditFlowExportVO from(CustomerCreditFlow f) + { + CustomerCreditFlowExportVO vo = new CustomerCreditFlowExportVO(); + vo.setFlowNo(f.getFlowNo()); + vo.setCreateTime(f.getCreateTime()); + vo.setBizNo(f.getBizNo()); + vo.setChangeTypeLabel(changeTypeLabel(f.getChangeType())); + boolean usageFlow = "OCCUPY".equals(f.getChangeType()) || "RELEASE".equals(f.getChangeType()); + vo.setDimensionLabel(usageFlow ? "授信占用(已用额度)" : "授信额度"); + vo.setAdjustModeLabel(adjustModeLabel(f.getAdjustMode())); + Integer dir = f.getDirection(); + vo.setDirectionLabel(dir == null ? "-" : (dir == 1 ? "增加" : "减少")); + vo.setBeforeAmount(f.getBeforeAmount()); + // 减少导出为负数(配合“方向”列阅读,同时保持 Excel 数值类型) + BigDecimal change = f.getChangeAmount(); + if (change != null && dir != null && dir == -1) + { + change = change.negate(); + } + vo.setChangeAmount(change); + vo.setAfterAmount(f.getAfterAmount()); + // 占用/释放流水的已用额度快照在页面上不展示 + vo.setUsedCredit(usageFlow ? null : f.getUsedCredit()); + vo.setEffectiveDate(f.getEffectiveDate()); + vo.setExpireDateText(f.getExpireDate() == null ? "长期" : new java.text.SimpleDateFormat("yyyy-MM-dd").format(f.getExpireDate())); + vo.setReason(f.getReason()); + vo.setCreateBy(f.getCreateBy()); + vo.setRemark(f.getRemark()); + return vo; + } + + private static String changeTypeLabel(String v) + { + if ("INIT".equals(v)) return "初始化"; + if ("ADJUST".equals(v)) return "手工调整"; + if ("EXPIRE".equals(v)) return "到期失效"; + if ("OCCUPY".equals(v)) return "授信占用"; + if ("RELEASE".equals(v)) return "授信释放"; + return v; + } + + private static String adjustModeLabel(String v) + { + if ("SET".equals(v)) return "设置为"; + if ("ADD".equals(v)) return "增加"; + if ("SUB".equals(v)) return "减少"; + return v; + } +} diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerReceiptExportVO.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerReceiptExportVO.java new file mode 100644 index 00000000..47c19f27 --- /dev/null +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customermoney/vo/CustomerReceiptExportVO.java @@ -0,0 +1,116 @@ +package com.ruoyi.customer.customermoney.vo; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.customer.customermoney.domain.CustomerReceipt; +import lombok.Data; + +/** + * 客户收款记录导出 VO(列与页面收款记录 tab 对齐,枚举导出为中文文案) + * + * @author ruoyi + * @date 2026-09-21 + */ +@Data +public class CustomerReceiptExportVO implements Serializable +{ + private static final long serialVersionUID = 1L; + + @Excel(name = "收款单号", width = 22) + private String receiptNo; + + @Excel(name = "收款日期", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date receivedAt; + + @Excel(name = "收款类型", width = 12) + private String receiptTypeLabel; + + @Excel(name = "币种", width = 8) + private String currency; + + @Excel(name = "原币金额", width = 14) + private BigDecimal amount; + + @Excel(name = "汇率", width = 12) + private String exchangeRate; + + @Excel(name = "汇率来源", width = 10) + private String rateSourceLabel; + + @Excel(name = "本位币金额(CNY)", width = 16) + private BigDecimal baseAmount; + + @Excel(name = "收款方式", width = 12) + private String payMethodLabel; + + @Excel(name = "客户银行账号", width = 24) + private String bankAccountNo; + + @Excel(name = "银行/平台流水号", width = 22) + private String bankTransactionNo; + + @Excel(name = "状态", width = 10) + private String statusLabel; + + @Excel(name = "登记人", width = 12) + private String createBy; + + @Excel(name = "备注", width = 30) + private String remark; + + public static CustomerReceiptExportVO from(CustomerReceipt r) + { + CustomerReceiptExportVO vo = new CustomerReceiptExportVO(); + vo.setReceiptNo(r.getReceiptNo()); + vo.setReceivedAt(r.getReceivedAt()); + vo.setReceiptTypeLabel(receiptTypeLabel(r.getReceiptType())); + vo.setCurrency(r.getCurrency()); + vo.setAmount(r.getAmount()); + vo.setExchangeRate(r.getExchangeRate() == null ? null : r.getExchangeRate().stripTrailingZeros().toPlainString()); + vo.setRateSourceLabel(rateSourceLabel(r.getRateSource())); + vo.setBaseAmount(r.getBaseAmount()); + vo.setPayMethodLabel(payMethodLabel(r.getPayMethod())); + vo.setBankAccountNo(r.getBankAccountNo()); + vo.setBankTransactionNo(r.getBankTransactionNo()); + vo.setStatusLabel(statusLabel(r.getStatus())); + vo.setCreateBy(r.getCreateBy()); + vo.setRemark(r.getRemark()); + return vo; + } + + private static String receiptTypeLabel(String v) + { + if ("PREPAY".equals(v)) return "预充值"; + if ("REPAY".equals(v)) return "还款核销"; + if ("MIXED".equals(v)) return "混合"; + return v; + } + + private static String statusLabel(String v) + { + if ("PENDING".equals(v)) return "待确认"; + if ("CONFIRMED".equals(v)) return "已确认"; + if ("CANCELLED".equals(v)) return "已取消"; + return v; + } + + private static String payMethodLabel(String v) + { + if ("BANK_TRANSFER".equals(v)) return "银行转账"; + if ("ALIPAY".equals(v)) return "支付宝"; + if ("WECHAT".equals(v)) return "微信"; + if ("CASH".equals(v)) return "现金"; + if ("OTHER".equals(v)) return "其他"; + return v; + } + + private static String rateSourceLabel(String v) + { + if ("RATE_TABLE".equals(v)) return "汇率表"; + if ("MANUAL".equals(v)) return "手工修改"; + if ("SYSTEM".equals(v)) return "系统默认"; + return v; + } +} diff --git a/bms-front/src/components/ColumnSettings/index.vue b/bms-front/src/components/ColumnSettings/index.vue new file mode 100644 index 00000000..eaae6aa8 --- /dev/null +++ b/bms-front/src/components/ColumnSettings/index.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/bms-front/src/directive/index.js b/bms-front/src/directive/index.js index 86b8f88a..09a5e7e1 100644 --- a/bms-front/src/directive/index.js +++ b/bms-front/src/directive/index.js @@ -1,9 +1,11 @@ import hasRole from './permission/hasRole' import hasPermi from './permission/hasPermi' import copyText from './common/copyText' +import resizableColumn from './resizableColumn' export default function directive(app){ app.directive('hasRole', hasRole) app.directive('hasPermi', hasPermi) app.directive('copyText', copyText) + app.directive('resizable', resizableColumn) } \ No newline at end of file diff --git a/bms-front/src/directive/resizableColumn/index.js b/bms-front/src/directive/resizableColumn/index.js new file mode 100644 index 00000000..1090e9a0 --- /dev/null +++ b/bms-front/src/directive/resizableColumn/index.js @@ -0,0 +1,93 @@ +/** + * v-resizable —— 让 el-table 表头右边界可拖拽调整列宽。 + * + * 原理:在表格根元素上做事件委托。当鼠标点按落在表头某个 th 右边界(约 8px 内)时,进入拖拽; + * 拖拽过程中动态改写该列对应 与 th 的 width,从而整列变宽/变窄(跨表头与数据区)。 + * 不依赖 el-table 原生的 .el-table__column-resizer(当前运行环境未渲染,故自实现)。 + * + * 用法: ... + */ +const EDGE = 8 // 判定"右边界"的像素容差 + +function colIndex(th) { + const row = th.parentNode + return Array.prototype.indexOf.call(row.children, th) +} + +/** + * 同时改写表头与表体的列宽。 + * el-table 将表头和表体渲染为两张独立的 (各自带 colgroup), + * 仅改一张会导致表头与数据行错位,因此须对主结构(.el-table__inner-wrapper)里的所有 table 一并更新。 + */ +function applyWidth(scopeEl, idx, w) { + scopeEl.querySelectorAll('table').forEach(tbl => { + // 跳过固定附表(fixed 列独立渲染,索引语义不同,避免误改) + if (tbl.closest('.el-table__fixed, .el-table-fixed-column')) return + const col = tbl.querySelector('colgroup') && tbl.querySelector('colgroup').children[idx] + if (col) col.style.width = w + 'px' + tbl.querySelectorAll('tr').forEach(tr => { + const cell = tr.children[idx] + if (!cell) return + cell.style.width = w + 'px' + if (cell.tagName === 'TH') { + cell.style.minWidth = '' + cell.style.maxWidth = '' + } + }) + }) +} + +function bindDrag(tableEl) { + let dragging = null + + function onMouseMove(e) { + if (!dragging) return + const dx = e.clientX - dragging.startX + const w = Math.max(dragging.minWidth || 60, dragging.startWidth + dx) + applyWidth(tableEl, dragging.idx, w) + dragging.lastWidth = w + e.preventDefault() + } + + function onMouseUp() { + if (dragging) { + document.removeEventListener('mousemove', onMouseMove) + document.removeEventListener('mouseup', onMouseUp) + document.body.style.cursor = '' + document.body.style.userSelect = '' + dragging = null + } + } + + tableEl.addEventListener('mousedown', (e) => { + const target = e.target + const th = target.closest('th') + if (!th || !tableEl.contains(th)) return + // 固定列(fixed left/right)不参与拖拽 + if (th.classList.contains('el-table-fixed-column') || th.className.indexOf('fixed') > -1) return + + const rect = th.getBoundingClientRect() + if (e.clientX < rect.right - EDGE) return // 只有贴近右边界才触发 + + const idx = colIndex(th) + + dragging = { + startX: e.clientX, + startWidth: rect.width, + minWidth: Number(th.dataset.resizableMin) || 40, + idx, + th + } + document.body.style.cursor = 'col-resize' + document.body.style.userSelect = 'none' + document.addEventListener('mousemove', onMouseMove) + document.addEventListener('mouseup', onMouseUp) + e.preventDefault() + }) +} + +export default { + mounted(el) { + bindDrag(el) + } +} \ No newline at end of file diff --git a/bms-front/src/main.js b/bms-front/src/main.js index 6713d88d..7ddb64bc 100644 --- a/bms-front/src/main.js +++ b/bms-front/src/main.js @@ -57,6 +57,8 @@ import UserName from '@/components/UserName' import ProductSelect from '@/components/ProductSelect' // 多值输入组件(一个字段搜索多个值,如订单号批量搜索) import MultiValueInput from '@/components/MultiValueInput' +// 表格列设置组件(自定义列显隐) +import ColumnSettings from '@/components/ColumnSettings' const app = createApp(App) @@ -87,6 +89,7 @@ app.component('UserSelect', UserSelect) app.component('UserName', UserName) app.component('ProductSelect', ProductSelect) app.component('MultiValueInput', MultiValueInput) +app.component('ColumnSettings', ColumnSettings) app.use(router) app.use(store) diff --git a/bms-front/src/utils/columnSettings.js b/bms-front/src/utils/columnSettings.js new file mode 100644 index 00000000..8e80aebd --- /dev/null +++ b/bms-front/src/utils/columnSettings.js @@ -0,0 +1,50 @@ +/** + * 表格列显隐偏好(localStorage 持久化)。 + * + * @param {string} storageKey 存储键(页面级唯一,如 'customer-list') + * @param {Array<{key:string,label:string,fixed?:boolean,defaultVisible?:boolean}>} columns 列定义 + * @returns {{colVisible: object, isColVisible: Function, resetColumns: Function}} + * colVisible 响应式显隐映射,模板中 v-if="isColVisible('xxx')" + * resetColumns 恢复默认(供列设置弹窗调用) + */ +const PREFIX = 'bms:columnSettings:' + +export function useColumnSettings(storageKey, columns) { + const defaults = {} + columns.forEach(c => { + defaults[c.key] = c.defaultVisible !== false + }) + + let saved = {} + try { + saved = JSON.parse(localStorage.getItem(PREFIX + storageKey) || '{}') || {} + } catch (e) { + saved = {} + } + + // 仅接受当前列定义中存在的 key(兼容历史存储与列增减) + const colVisible = reactive({ ...defaults }) + columns.forEach(c => { + if (Object.prototype.hasOwnProperty.call(saved, c.key)) { + colVisible[c.key] = !!saved[c.key] + } + // 固定列强制可见 + if (c.fixed) colVisible[c.key] = true + }) + + watch(colVisible, val => { + localStorage.setItem(PREFIX + storageKey, JSON.stringify(val)) + }, { deep: true }) + + function isColVisible(key) { + return colVisible[key] !== false + } + + function resetColumns() { + columns.forEach(c => { + colVisible[c.key] = c.fixed ? true : c.defaultVisible !== false + }) + } + + return { colVisible, isColVisible, resetColumns } +} diff --git a/bms-front/src/views/customersuppliermanagement/customerinfo/customermoney/index.vue b/bms-front/src/views/customersuppliermanagement/customerinfo/customermoney/index.vue index 1cd49360..05cdfb64 100644 --- a/bms-front/src/views/customersuppliermanagement/customerinfo/customermoney/index.vue +++ b/bms-front/src/views/customersuppliermanagement/customerinfo/customermoney/index.vue @@ -110,6 +110,8 @@ 重置登记收款 + 导出 @@ -220,6 +222,8 @@ 搜索 重置 + 导出 @@ -296,6 +300,8 @@ 搜索 重置 + 导出 @@ -1356,6 +1362,39 @@ function resetReceiptQuery() { getReceiptList() } +/** 导出收款记录(按当前筛选,全量导出) */ +function handleExportReceipt() { + const cid = route.query.customerId + if (!cid) return + const params = proxy.addDateRange({ ...receiptQuery }, receiptDateRange.value) + delete params.pageNum + delete params.pageSize + proxy.download('customersupplier/customermoney/receipt/export', params, + `收款记录_${new Date().getTime()}.xlsx`) +} + +/** 导出余额流水(按当前筛选,全量导出) */ +function handleExportFlow() { + const cid = route.query.customerId + if (!cid) return + const params = proxy.addDateRange({ ...flowQuery }, flowDateRange.value) + delete params.pageNum + delete params.pageSize + proxy.download('customersupplier/customermoney/flow/export', params, + `余额流水_${new Date().getTime()}.xlsx`) +} + +/** 导出额度流水(按当前筛选,全量导出) */ +function handleExportCreditFlow() { + const cid = route.query.customerId + if (!cid) return + const params = proxy.addDateRange({ ...creditFlowQuery }, creditFlowDateRange.value) + delete params.pageNum + delete params.pageSize + proxy.download('customersupplier/customermoney/credit/flow/export', params, + `额度流水_${new Date().getTime()}.xlsx`) +} + /** 审核通过 */ function handleConfirmReceipt(row) { proxy.$modal.confirm(`是否确认审核通过收款单「${row.receiptNo}」?审核通过后金额将计入客户余额。`).then(() => { diff --git a/bms-front/src/views/customersuppliermanagement/customerinfo/index.vue b/bms-front/src/views/customersuppliermanagement/customerinfo/index.vue index 4d09bb7d..ef2fd6a0 100644 --- a/bms-front/src/views/customersuppliermanagement/customerinfo/index.vue +++ b/bms-front/src/views/customersuppliermanagement/customerinfo/index.vue @@ -115,49 +115,50 @@ + - - + + - - - - - + + + + + - + - + - - - + + + - + - + - - + + - - - + + + - + - - + +