简介:点可云进销存系统是一套面向中小企业的轻量级ERP管理解决方案,基于ThinkPHP框架与Layui前端库开发,聚焦采购、销售、零售、多仓库协同、财务核算及全维度经营报表等核心业务场景,助力企业实现进销存一体化管控与数据驱动决策。资源包共1736个文件,含623个PHP后端逻辑文件、198个JS交互脚本、124个HTML页面模板、92个PNG图标及37个CSS样式文件,辅以数据库配置(.sql/.db)、安装脚本(.bat/.sh)和完整文档(README、CHANGELOG、LICENSE),整体压缩包仅19.78MB,结构清晰、开箱即用。目前已有109人学习下载,适合PHP中级开发者快速掌握企业级应用的MVC分层设计、Layui组件集成与多模块业务联动实现。读者可直接部署运行,深入理解采购单流转、销售订单闭环、多仓库存同步、资金流水对账及10+类动态报表生成等真实业务逻辑。
1. 点可云进销存系统:为什么一个基于 ThinkPHP + Layui 的老派技术栈,反而在中小商贸企业里跑得比 SaaS 还稳?
你可能刚点开这个标题时心里一咯噔:ThinkPHP 6 都出三年了,Layui 官网更新停在 2021 年,现在还拿这套组合做进销存?是不是过时了?但现实是——我去年在珠三角跑了 7 家做五金、建材、农产品批发的客户,他们用的正是「点可云」这类系统,不是钉钉宜搭,也不是简道云,更不是某SaaS厂商的云端订阅版。他们不关心 Vue3 或微前端,只问三件事:能不能离线开单?财务报表导出 Excel 能不能带公式?多仓库调拨时,扫码枪扫完 50 行商品,3 秒内必须回显库存差额并锁库。
点可云这类系统恰恰卡在「够用、可控、可改」的黄金缝里:ThinkPHP 提供稳定的 MVC 分层和数据库抽象层,让采购单、销售单、零售小票这些强事务场景能靠事务+锁表兜底;Layui 虽无响应式,但它的 table 组件原生支持服务端分页、列宽拖拽、Excel 导出(含合并单元格),比手写 Vue 表格快 3 倍——尤其当客户要求「把未清采购订单按供应商+物料+单位(件/袋/吨)三维度汇总到一张表里」时,Layui 的toolbar+export+done回调链,配合 ThinkPHP 的Db::query()原生 SQL,反而比 ORM 更直给、更可控。它不是为炫技而生,而是为「老板下午三点要看到昨天所有门店的毛利对比柱状图」而活。适合年营收 500 万~5000 万、IT 人员≤1 名、ERP 预算 ≤3 万元的实体商贸企业。
2. 搭建最小可运行环境:用 ThinkPHP 6.1 + Layui 2.8 快速拉起采购单模块
点可云系统不是从零造轮子,而是基于 ThinkPHP 6.1 LTS 版本(非 7.x)和 Layui 2.8(非 layui-vue)构建。这两个版本组合经过 3 年以上生产验证,兼容 PHP 7.4–8.1,且避免了 TP7 的中间件重构和 Layui-vue 的生态断层风险。下面带你从零拉起「采购单新增」功能,这是整个系统最核心的事务入口。
2.1 初始化 ThinkPHP 6.1 项目并配置多数据库连接
点可云需同时操作主业务库(db_main)和报表缓存库(db_report),尤其在「采购收货汇总表单位件和袋怎么汇总在一个表上」这类需求中,需跨库 JOIN。TP6.1 的多连接配置比 TP5.1 更清晰:
# 使用 Composer 创建项目(注意指定 6.1.x 版本) composer create-project topthink/think=6.1.* pointcloud-inventory cd pointcloud-inventory编辑config/database.php,关键配置如下:
// config/database.php return [ // 主库:业务写入 'default' => 'mysql_main', 'connections' => [ 'mysql_main' => [ 'type' => 'mysql', 'hostname' => '127.0.0.1', 'database' => 'pointcloud_main', 'username' => 'root', 'password' => 'your_pass', 'hostport' => '3306', 'charset' => 'utf8mb4', 'prefix' => 'pc_', // 所有表前缀统一为 pc_ 'debug' => true, 'deploy' => 0, 'rw_separate' => false, ], // 报表库:只读,用于复杂汇总查询 'mysql_report' => [ 'type' => 'mysql', 'hostname' => '127.0.0.1', 'database' => 'pointcloud_report', 'username' => 'report_user', 'password' => 'readonly_pass', 'hostport' => '3306', 'charset' => 'utf8mb4', 'prefix' => '', 'debug' => false, 'deploy' => 0, 'rw_separate' => false, ], ], ];提示:
prefix设为pc_是点可云约定,后续所有数据表名如pc_purchase_order、pc_warehouse均由此生成。不要用空字符串,否则迁移时易与旧系统冲突。
2.2 引入 Layui 2.8 并初始化采购单页面骨架
Layui 不走 npm,直接下载layui-v2.8.18.zip(官网最后稳定版),解压后将layui文件夹放入public/static/下。在app/view/index/purchase/add.html中写基础结构:
<!-- app/view/index/purchase/add.html --> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>新增采购单</title> <link rel="stylesheet" href="/static/layui/css/layui.css"> </head> <body class="layui-layout-body"> <div class="layui-layout layui-layout-admin"> <div class="layui-header"> <div class="layui-logo">点可云·采购管理</div> </div> <div class="layui-body"> <div style="padding: 20px;"> <form class="layui-form" action="{:url('purchase/save')}" method="post"> <div class="layui-form-item"> <label class="layui-form-label">供应商</label> <div class="layui-input-block"> <select name="supplier_id" lay-filter="supplier" required> <option value="">请选择</option> {volist name="suppliers" id="sup"} <option value="{$sup.id}">{$sup.name}({$sup.code})</option> {/volist} </select> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">仓库</label> <div class="layui-input-block"> <select name="warehouse_id" required> <option value="">请选择</option> {volist name="warehouses" id="wh"} <option value="{$wh.id}">{$wh.name}({$wh.code})</option> {/volist} </select> </div> </div> <!-- 商品明细表格占位 --> <div id="goods-table-container"></div> <div class="layui-form-item"> <div class="layui-input-block"> <button class="layui-btn" lay-submit lay-filter="add-purchase">立即提交</button> <button type="reset" class="layui-btn layui-btn-primary">重置</button> </div> </div> </form> </div> </div> </div> <script src="/static/layui/layui.js"></script> <script> layui.use(['form', 'table', 'layer'], function(){ var form = layui.form; var table = layui.table; var layer = layui.layer; // 动态渲染商品明细表格(关键!) table.render({ elem: '#goods-table', height: 400, url: '{:url("purchase/goodsList")}', // 后台返回 JSON:[{id:1,name:"螺丝",unit:"件",price:2.5}] cols: [[ {type:'checkbox'}, {field:'id', title:'ID', width:80, unresize: true}, {field:'name', title:'商品名称', edit: 'text'}, {field:'unit', title:'单位', width:100, templet: '#unitTpl'}, {field:'qty', title:'数量', edit: 'number', width:120}, {field:'price', title:'单价(元)', edit: 'number', width:120}, {field:'amount', title:'金额(元)', width:120, templet: '<div>{{d.qty * d.price}}</div>'}, {fixed: 'right', title:'操作', toolbar: '#barDemo', width:120} ]], page: true, limit: 20, done: function(res, curr, count){ // 表格渲染完成后,触发金额自动计算 calcTotalAmount(); } }); // 监听工具条事件(删除行) table.on('tool(goodsTable)', function(obj){ if(obj.event === 'del'){ layer.confirm('确定删除该商品?', function(index){ obj.del(); calcTotalAmount(); layer.close(index); }); } }); // 金额合计函数(放在全局,供编辑、删除、新增时调用) function calcTotalAmount(){ var total = 0; var data = table.cache['goodsTable']; for(var i in data){ total += (data[i].qty || 0) * (data[i].price || 0); } $('#total-amount').text(total.toFixed(2)); } // 提交前校验(防止空明细) form.on('submit(add-purchase)', function(data){ var goodsData = table.cache['goodsTable']; if(goodsData.length === 0){ layer.msg('请至少添加一行商品明细!', {icon:2}); return false; } return true; // 允许提交 }); }); </script> <script type="text/html" id="unitTpl"> {{# if(d.unit == "件"){ }}件{{# } else if(d.unit == "袋"){ }}袋{{# } else { }}{{d.unit}}{{# } }} </script> <script type="text/html" id="barDemo"> <a class="layui-btn layui-btn-xs" lay-event="del">删除</a> </script> </body> </html>这段代码的关键不在“能显示”,而在三个落地细节:
templet: '#unitTpl'实现「件/袋」单位动态渲染,避免后端拼 HTML 字符串;done回调中调用calcTotalAmount(),确保分页后金额仍准确(Layui table 默认只渲染当前页,但 cache 存全量);form.on('submit')中校验table.cache长度,而非 DOM 行数——因为 Layui 表格支持编辑但不自动同步到 DOM,必须读 cache。
3. 核心数据模型设计:采购单、商品明细、多仓库与单位换算的 MySQL 表结构
点可云的「采购收货汇总表单位件和袋怎么汇总在一个表上」需求,本质是同一物料在不同采购场景下存在多种计量单位(件/袋/箱/吨),且需按实际收货单位归集统计。这要求数据库设计必须支持「单位换算因子」和「收货单位快照」,而非简单用unit VARCHAR(10)硬编码。
3.1 五张核心表及其字段逻辑说明
| 表名 | 字段(关键) | 类型 | 说明 | 索引建议 |
|---|---|---|---|---|
pc_purchase_order | id,order_no,supplier_id,warehouse_id,status,created_at,updated_at | BIGINT / VARCHAR / INT / DATETIME | 主单头表;status用 tinyint(1):0草稿、1已提交、2已收货、3已入库、4已关闭 | UNIQUE(order_no),INDEX(supplier_id, status) |
pc_purchase_item | id,order_id,goods_id,unit_id,qty,price,amount,received_qty,received_unit_id | BIGINT / BIGINT / BIGINT / DECIMAL / DECIMAL / DECIMAL / DECIMAL / BIGINT | 明细表;unit_id是采购单位(如“袋”),received_unit_id是收货单位(如“件”),二者可不同;received_qty为实际收货数量 | INDEX(order_id),INDEX(goods_id) |
pc_goods | id,code,name,base_unit_id,is_multi_unit | BIGINT / VARCHAR / VARCHAR / BIGINT / TINYINT | 商品主数据;base_unit_id是基准单位(如“件”),所有换算以此为基准 | UNIQUE(code),INDEX(name) |
pc_unit | id,code,name,factor_to_base | BIGINT / VARCHAR / VARCHAR / DECIMAL(10,4) | 单位表;factor_to_base表示该单位换算成基准单位的系数,如“袋→件=20”,则factor_to_base=20 | UNIQUE(code) |
pc_warehouse | id,code,name,type,is_enabled | BIGINT / VARCHAR / VARCHAR / TINYINT / TINYINT | 仓库表;type:1总部仓、2区域仓、3门店仓、4虚拟仓(用于调拨中转) | INDEX(type, is_enabled) |
注意:
pc_purchase_item.received_unit_id不是外键指向pc_unit.id,而是冗余存储——因为收货时单位可能临时新增(如某次采购特批用“托盘”),且历史单据单位不可变。这是点可云的务实设计:宁可冗余,不建外键约束导致插入失败。
3.2 实现「件和袋汇总到一张表」的 SQL 查询逻辑
当客户要求「按供应商+物料+单位(件/袋)三维度汇总采购收货」时,不能简单GROUP BY unit_id,因为unit_id是采购单位,而收货单位在received_unit_id。正确做法是:以received_unit_id为主维度,关联pc_unit获取单位名称,并用factor_to_base将所有收货量统一折算为基准单位(件)再汇总:
-- 采购收货汇总视图(含件/袋/箱等多单位统一折算) CREATE VIEW v_purchase_received_summary AS SELECT s.name AS supplier_name, g.name AS goods_name, u.name AS received_unit, SUM(pi.received_qty) AS raw_qty, SUM(pi.received_qty * u.factor_to_base) AS qty_in_base_unit, COUNT(DISTINCT po.id) AS order_count FROM pc_purchase_item pi JOIN pc_purchase_order po ON pi.order_id = po.id JOIN pc_supplier s ON po.supplier_id = s.id JOIN pc_goods g ON pi.goods_id = g.id JOIN pc_unit u ON pi.received_unit_id = u.id WHERE po.status IN (2,3) -- 已收货或已入库 GROUP BY s.id, g.id, u.id, u.name;此视图输出结果示例:
| supplier_name | goods_name | received_unit | raw_qty | qty_in_base_unit | order_count |
|---|---|---|---|---|---|
| 东莞XX五金厂 | M8螺栓 | 件 | 1200 | 1200.0000 | 3 |
| 东莞XX五金厂 | M8螺栓 | 袋 | 50 | 1000.0000 | 2 |
这样,前端报表只需查v_purchase_received_summary,就能天然支持「件和袋汇总在一个表」,无需应用层做单位转换——这是数据库设计阶段就埋下的确定性。
4. 多仓库调拨与库存锁定:用事务+行锁解决并发超卖问题
点可云的「多仓库管理」不是简单增删改查,核心痛点是:A 仓向 B 仓调拨 100 件螺丝,同时 C 仓也在销售这 100 件螺丝,如何保证不超卖?ThinkPHP 的事务封装 + MySQL 行锁是唯一可靠解法,Layui 前端只负责触发,不参与锁逻辑。
4.1 库存扣减的原子操作:pc_stock表结构与 SQL 锁定语句
库存表pc_stock必须按「仓库+商品」粒度建行,且qty字段为DECIMAL(12,2)(支持小数库存,如液体、散装料):
CREATE TABLE `pc_stock` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT, `warehouse_id` bigint unsigned NOT NULL, `goods_id` bigint unsigned NOT NULL, `qty` decimal(12,2) NOT NULL DEFAULT '0.00', `frozen_qty` decimal(12,2) NOT NULL DEFAULT '0.00', -- 冻结量(已分配未出库) `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_warehouse_goods` (`warehouse_id`,`goods_id`), KEY `idx_goods` (`goods_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;关键字段frozen_qty:表示该仓库该商品已被采购单、销售单、调拨单预占的数量。真正扣减时,必须同时更新qty和frozen_qty,且用SELECT ... FOR UPDATE锁住目标行:
// app/controller/Purchase.php public function save() { $data = input('post.'); $this->validate($data, 'PurchaseValidate'); Db::startTrans(); // 开启事务 try { // 1. 插入采购单头 $orderId = Db::name('purchase_order')->insertGetId([ 'order_no' => 'PO' . date('ymd') . str_pad(rand(1000,9999), 4, '0', STR_PAD_LEFT), 'supplier_id' => $data['supplier_id'], 'warehouse_id' => $data['warehouse_id'], 'status' => 1, 'created_at' => date('Y-m-d H:i:s') ]); // 2. 插入明细,并锁定库存行(关键!) foreach ($data['items'] as $item) { // 锁定该仓库+商品的库存行(阻塞其他事务) $stock = Db::name('stock')->where([ 'warehouse_id' => $data['warehouse_id'], 'goods_id' => $item['goods_id'] ])->lock(true)->find(); if (!$stock || $stock['qty'] < $item['qty']) { throw new \Exception("库存不足:商品 {$item['goods_id']} 在仓库 {$data['warehouse_id']} 剩余 {$stock['qty']},需 {$item['qty']}"); } // 3. 更新库存:扣减可用量,增加冻结量 Db::name('stock')->where('id', $stock['id'])->update([ 'qty' => $stock['qty'] - $item['qty'], 'frozen_qty' => $stock['frozen_qty'] + $item['qty'], 'updated_at' => date('Y-m-d H:i:s') ]); // 4. 插入采购明细(此时已锁库,安全) Db::name('purchase_item')->insert([ 'order_id' => $orderId, 'goods_id' => $item['goods_id'], 'unit_id' => $item['unit_id'], 'qty' => $item['qty'], 'price' => $item['price'], 'amount' => $item['qty'] * $item['price'], 'received_qty' => 0, 'received_unit_id' => $item['unit_id'] // 默认收货单位=采购单位 ]); } Db::commit(); return json(['code'=>1, 'msg'=>'采购单创建成功']); } catch (\Exception $e) { Db::rollback(); return json(['code'=>0, 'msg'=>$e->getMessage()]); } }血泪经验:
lock(true)是 ThinkPHP 6.1 的写法,等价于SELECT ... FOR UPDATE。若用lock(false)(即LOCK IN SHARE MODE),则无法阻止其他事务修改qty,会导致超卖。务必用true。
4.2 Layui 前端如何感知库存锁定状态?
用户点击「提交采购单」后,按钮应禁用并显示「库存校验中…」,避免重复提交。Layui 表单提交拦截需加 loading 状态:
form.on('submit(add-purchase)', function(data){ // 1. 禁用按钮 var btn = $(this).find('button[lay-filter="add-purchase"]'); btn.addClass('layui-btn-disabled').html('<i class="layui-icon layui-icon-loading"></i> 库存校验中…'); // 2. 提交 AJAX $.post('{:url("purchase/save")}', data.field, function(res){ if(res.code === 1){ layer.msg('成功!', {icon:1}); setTimeout(function(){ location.href = '{:url("purchase/index")}'; }, 1500); } else { layer.msg(res.msg, {icon:2}); btn.removeClass('layui-btn-disabled').html('立即提交'); } }).fail(function(){ layer.msg('网络错误,请重试', {icon:2}); btn.removeClass('layui-btn-disabled').html('立即提交'); }); return false; // 阻止默认提交 });此处「禁用按钮」不是防 JS 重复执行,而是防用户狂点——因为后端事务锁住库存行后,第二个请求会阻塞数秒甚至超时,前端必须明确反馈「正在处理」,否则用户会以为卡死而刷新页面,造成脏数据。
5. 报表功能避坑指南:Layui table 导出 Excel 的 4 个致命陷阱
点可云的「超详细的报表功能」是客户付费核心点,但 Layui 的table.exportFile()在真实生产中极易翻车。我踩过 4 个必须写死在 checklist 里的坑,每个都导致客户投诉「导出的 Excel 乱码/缺列/公式失效/超时」。
5.1 现象:导出 Excel 中文列头显示为方框或乱码
原因:Layui 导出使用SheetJS(xlsx.full.min.js),其默认编码为 ANSI,中文需显式指定bookType: 'xlsx'和type: 'array',且后端返回必须是 UTF-8 BOM 头。
解决:
- 前端
table.exportFile()必须加参数:table.exportFile('goodsTable', data, 'xlsx', { bookType: 'xlsx', type: 'array' }); - 后端 PHP 导出接口(如
app/controller/Report.php)必须输出 BOM 头:header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment;filename="report.xlsx"'); header('Cache-Control: max-age=0'); // 关键:输出 UTF-8 BOM echo "\xEF\xBB\xBF"; // 后续输出 xlsx 二进制流...
5.2 现象:导出的 Excel 列宽为 0,内容挤成一条线
原因:Layui 默认不设置列宽,Excel 打开时自动适应,但某些版本(尤其是 WPS)会忽略自适应,显示为 0 宽。
解决:在table.render()的cols中为每列加minWidth:
{field:'name', title:'商品名称', minWidth:150}, // 至少 150px {field:'unit', title:'单位', width:100, minWidth:80},5.3 现象:导出的 Excel 中「金额」列无千分位,且无法用 SUM 函数求和
原因:Layui 导出时把数字当字符串处理(因templet返回的是 HTML 字符串<div>1234.56</div>)。
解决:对数值列,templet必须返回纯数字,由 Layui 自动识别类型:
{field:'amount', title:'金额(元)', width:120, templet: function(d){ return d.qty * d.price; }}, // ❌ 错误写法:templet: '<div>{{d.qty * d.price}}</div>'5.4 现象:大数据量(>5000 行)导出时浏览器卡死或超时
原因:LayuiexportFile()在前端生成 Excel,内存爆炸。
解决:超过 2000 行强制走后端导出。前端判断:
var total = table.cache['goodsTable'].length; if(total > 2000){ layer.confirm('数据量过大,将启用后台导出(约30秒)', function(){ window.location.href = '{:url("report/exportLarge")}?table=goodsTable¶ms=' + JSON.stringify(params); }); } else { table.exportFile('goodsTable', table.cache['goodsTable'], 'xlsx'); }后端exportLarge方法用PhpSpreadsheet流式写入,内存占用 <2MB。
避坑总结:报表不是功能堆砌,而是「导出即交付」。Layui 的便捷性在小数据时成立,一旦客户说「我要导出去年全年销售明细」,就必须切后端导出——这不是妥协,是职业底线。
6. 财务报表联动技巧:用「科目余额表」驱动利润表与现金流量表自动计算
点可云的「财务管理功能」常被低估,其实它才是系统粘性最强的部分。客户不要总账凭证,只要「今天毛利多少」「本月经营性现金流净额」——而这依赖一个核心设计:所有业务单据(采购、销售、零售)在保存时,必须实时写入pc_accounting_entry科目余额表,且按「会计期间+科目+方向」聚合。这样,利润表和现金流量表才能脱离 SQL 复杂 JOIN,靠简单SUM()实时生成。
6.1 科目余额表(pc_accounting_entry)结构与写入规则
CREATE TABLE `pc_accounting_entry` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT, `period` char(6) NOT NULL COMMENT '会计期间,格式:202401', `subject_code` varchar(20) NOT NULL COMMENT '科目编码,如:112201(应收账款-XX客户)', `subject_name` varchar(100) NOT NULL, `direction` tinyint NOT NULL COMMENT '1借方,-1贷方', `amount` decimal(14,2) NOT NULL DEFAULT '0.00', `created_at` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_period_subject` (`period`,`subject_code`), KEY `idx_subject` (`subject_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;写入规则(以销售单为例):
- 销售单保存时,生成 3 条分录:
1122(应收账款)借方:+销售总额6001(主营业务收入)贷方:+销售总额6401(主营业务成本)贷方:+销售成本(需关联商品成本价)
- 所有分录
period为date('Ym'),subject_code严格按科目体系编码,direction用1或-1,不用dr/cr字符串——为后续SUM(direction * amount)做准备。
6.2 利润表(v_profit_statement)视图实现
-- 利润表视图:按月聚合,实时计算 CREATE VIEW v_profit_statement AS SELECT period, SUM(CASE WHEN subject_code LIKE '6%' THEN direction * amount ELSE 0 END) AS revenue, SUM(CASE WHEN subject_code LIKE '64%' THEN direction * amount ELSE 0 END) AS cost_of_sales, SUM(CASE WHEN subject_code LIKE '66%' THEN direction * amount ELSE 0 END) AS operating_expense, SUM(CASE WHEN subject_code LIKE '6%' OR subject_code LIKE '64%' OR subject_code LIKE '66%' THEN direction * amount ELSE 0 END) AS net_profit FROM pc_accounting_entry GROUP BY period;关键技巧:
CASE WHEN subject_code LIKE '6%'比IN ('6001','6002',...)更可持续——当客户新增科目(如6003其他业务收入),视图自动包含,无需改 SQL。
6.3 现金流量表(间接法)的 Layui 表格联动
现金流量表难点在于「将净利润调节为经营活动现金流」。点可云用「科目映射表」解耦:建表pc_cashflow_mapping,定义哪些科目变动影响现金流:
| subject_code | cashflow_type | description |
|---|---|---|
| 1122 | 1 | 经营活动-销售商品收到现金 |
| 2202 | -1 | 经营活动-购买商品支付现金 |
| 1002 | 0 | 现金及现金等价物(期末余额) |
然后前端 Layui 表格用url加载动态数据:
table.render({ elem: '#cashflow-table', url: '{:url("report/cashflowData")}?period={:input("period")}', cols: [[ {field:'type_name', title:'项目', width:200}, {field:'amount', title:'金额(元)', width:150, templet: function(d){ return d.amount > 0 ? '+'+d.amount : d.amount; }}, {field:'note', title:'说明', width:250} ]], page: false, done: function(res){ // 渲染完成后,手动计算「现金及现金等价物净增加额」 var total = 0; res.data.forEach(function(row){ if(row.cashflow_type === 0){ total = row.amount; } }); $('#cash-end-balance').text(total.toFixed(2)); } });后端cashflowData方法根据pc_cashflow_mapping查出当期各科目发生额,再按cashflow_type归类。
我坚持在每个新客户上线前,花半天时间陪财务人员核对「科目余额表」的首笔分录是否正确——因为一旦源头写错,利润表就是黑匣子,后面所有报表都是后悔药。点可云的价值,不在界面有多炫,而在每一笔钱的来龙去脉,都能在pc_accounting_entry里找到原始凭证。这才是中小企业的「财务安全感」。
希望帮到你。
本文还有配套的精品资源,点击获取