拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ThinkPHP5家庭财务系统实战:从部署到多人协作

简介本资源是一套基于ThinkPHP5框架开发的家庭财务收支管理网站完整源码案例面向PHP初学者与Web开发入门者解决个人及家庭日常记账、预算控制与消费分析等实际需求。压缩包共1412个文件涵盖320个HTML页面、277个JavaScript交互脚本、245个PNG图标资源、238个CSS样式文件、173个PHP核心逻辑文件以及SQL数据库脚本、配置文件和前端UI组件如Bootstrap、EasyUI、UEditor、Font Awesome等整体大小为14.77MB结构清晰体现标准MVC分层设计。目前已有189人学习下载适合通过真实项目理解用户认证、多账户管理、收支分类统计、可视化报表生成及安全防护等Web开发关键能力。读者可直接部署运行深入研读application目录下的模型-控制器-视图实现结合public静态资源与config配置体系掌握ThinkPHP5工程化开发全流程。1. 这不是又一个“记账小工具”而是用 ThinkPHP5 搭建可落地的家庭财务收支管理网站的完整实践路径你在网上搜“家庭财务收支管理”大概率会看到一堆 Excel 模板、手机 App 推荐或者几行 PHP 代码拼凑的单页记账页。但真正能部署在自己服务器上、支持多成员协作、有清晰权限分层、数据可导出可统计、界面不简陋还能二次扩展的 Web 系统——极少有开源案例把「ThinkPHP5」这个成熟框架和「家庭财务」这个具体场景深度绑定来呈现。本标题指向的.zip源码包本质是一套经过真实需求反推、结构完整、路由清晰、模型分层合理、且未过度封装的家庭级财务系统参考实现。它不追求企业级复杂度但严格遵循 MVC 分层逻辑收支分类用数据库字典驱动流水记录带时间戳金额账户分类备注附件可选报表页用原生 SQL 聚合而非前端硬算权限控制到「仅查看配偶账目」粒度。适合 PHP 初学者理解 TP5 的 Request/Model/View/Validate 四件套如何协同也适合中小团队快速 fork 出内部费用登记系统——关键在于它把「家庭」这个最小财务单元的业务规则如房贷月供固定、水电费按月结算、红包收入无分类编码进了验证器和控制器逻辑里而不是堆砌功能。2. 用 ThinkPHP5 在本地跑通家庭财务系统的最小命令与目录结构还原2.1 解压后必须确认的三个核心目录与文件作用拿到ThinkPHP5家庭财务收支管理网站源码案例设计.zip后解压得到的根目录结构通常包含application/、public/、think可执行脚本及runtime/可能为空。这并非标准 TP5 官方安装包而是基于 TP5.0.24 或 TP5.1.39 的定制化应用包需特别注意application/下的common.php是全局函数入口其中定义了money_format()等财务专用格式化函数application/index/是默认模块其controller/Index.php中的index()方法返回首页视图而controller/Account.php才是收支核心控制器public/目录下必须存在index.php入口文件且其顶部define(APP_PATH, __DIR__ . /../application/);路径需与实际解压位置匹配。提示若直接双击index.php打开空白页说明未启用 PHP 内置服务器或 Apache/Nginx 配置错误。TP5 5.0 版本要求 PHP 5.6.0且pdo_mysql、mbstring、openssl扩展必须启用。2.2 用 PHP 内置服务器启动并验证基础路由无需配置 Apache 或 Nginx用 PHP 自带的开发服务器即可快速验证。进入public/目录执行php -S localhost:8000 -t . router.php其中router.php是 TP5 官方推荐的路由转发脚本内容如下若缺失请手动创建?php // router.php if (preg_match(/\.(?:png|jpg|jpeg|gif|ico|txt|woff|woff2|css|js|html|htm)$/i, $_SERVER[REQUEST_URI])) { return false; } else { include __DIR__ . /index.php; }执行后访问http://localhost:8000应看到登录页访问http://localhost:8000/index/account/index应跳转至收支列表页需先注册账号。若提示No input file specified.检查php -v输出的 PHP 版本是否低于 5.6若报错Class think\Db not found说明vendor/目录缺失——此源码包未包含 Composer 依赖需手动补全。2.3 补全 Composer 依赖与数据库初始化的两步强制操作该源码包通常不打包vendor/需通过 Composer 安装核心依赖。在项目根目录即含composer.json的目录执行composer install --no-dev --optimize-autoloader--no-dev参数排除测试类库--optimize-autoloader加速类加载符合生产环境习惯。成功后检查vendor/topthink/thinkphp/是否存在确认 TP5 核心已载入。数据库初始化分三步创建 MySQL 数据库如family_finance字符集设为utf8mb4导入application/database.php中指定的 SQL 文件常见路径为data/family_finance.sql该文件包含finance_account账户表、finance_category分类表、finance_record流水表、finance_user用户表四张核心表修改application/database.php中的数据库配置return [ type mysql, hostname 127.0.0.1, database family_finance, // 此处必须与你创建的库名一致 username root, password your_password, hostport 3306, charset utf8mb4, prefix finance_, // 表前缀需与 SQL 文件中建表语句匹配 ];注意prefix参数必须与 SQL 文件中CREATE TABLE finance_account的前缀完全一致否则模型查询将找不到表。若 SQL 文件使用无前缀建表则此处设为空字符串。2.4 验证登录与基础功能的四个关键请求路径启动服务后用浏览器访问以下路径验证各模块连通性路径用途预期响应/index.php?s/index/user/login用户登录页显示用户名/密码输入框提交后跳转至首页/index.php?s/index/account/index收支列表页显示近30天流水含「新增」按钮/index.php?s/index/category/index分类管理页列出「餐饮」「交通」「工资」等预设分类支持增删改/index.php?s/index/report/monthly月度报表页柱状图显示当月收入/支出对比下方表格列明细若任一路径返回 404检查application/route.php中是否定义了对应路由规则。典型配置如下// application/route.php Route::get(index/user/login, index/User/login); Route::get(index/account/index, index/Account/index); Route::get(index/category/index, index/Category/index); Route::get(index/report/monthly, index/Report/monthly);这些路由映射到控制器方法是理解业务流程的起点。例如Account/index方法内调用FinanceRecordModel::where(user_id, $uid)-order(create_time desc)-paginate(15)即按用户 ID 查询并分页体现了典型的家庭多账户隔离逻辑。3. 收支核心模型与验证器的三层校验逻辑拆解3.1FinanceRecord模型中的字段约束与关联定义application/index/model/FinanceRecord.php是收支流水的核心模型其定义直接决定数据写入的合法性。关键代码段如下?php namespace app\index\model; use think\Model; class FinanceRecord extends Model { // 指定数据表不含前缀 protected $name record; // 自动写入时间戳 protected $autoWriteTimestamp true; protected $createTime create_time; protected $updateTime false; // 字段类型转换 protected $type [ amount float, account_id integer, category_id integer, is_income boolean, ]; // 关联账户表 public function account() { return $this-belongsTo(FinanceAccount, account_id, id); } // 关联分类表 public function category() { return $this-belongsTo(FinanceCategory, category_id, id); } }这段代码揭示了三个关键设计点第一$name record表明该模型操作finance_record表前缀finance_ 名称record与数据库实际表名严格对应第二$type数组将amount强制转为浮点型避免整数存储导致小数丢失这是财务数据精度的生命线第三belongsTo关联声明让FinanceRecord::with(account,category)-find(1)可一次性查出流水账户名分类名省去多次查询。3.2FinanceRecordValidate验证器中的业务规则嵌入单纯数据库约束不够家庭财务有独特业务规则。application/index/validate/FinanceRecordValidate.php将规则前置到应用层?php namespace app\index\validate; use think\Validate; class FinanceRecordValidate extends Validate { protected $rule [ amount require|number|between:0.01,9999999.99, account_id require|integer|gt:0, category_id require|integer|gt:0, is_income require|in:0,1, remark max:200, create_time date, ]; protected $message [ amount.require 金额不能为空, amount.number 金额必须为数字, amount.between 金额应在0.01至9999999.99之间, account_id.gt 请选择有效账户, category_id.gt 请选择有效分类, is_income.in 收支类型只能是0支出或1收入, ]; }这里between:0.01,9999999.99限制单笔金额范围防止误输0.001分币单位或10000000千万级异常值in:0,1强制is_income字段二值化确保报表统计时SUM(CASE WHEN is_income1 THEN amount ELSE 0 END)可靠执行。验证失败时控制器中$validate-batch(false)-check($data)返回false并携带getError()消息前端可直接展示。3.3 控制器中对「家庭成员可见性」的权限拦截逻辑application/index/controller/Account.php的add()方法不仅处理新增还注入了家庭维度权限控制public function add() { if ($this-request-isPost()) { $data $this-request-post(); $data[user_id] session(user_id); // 强制绑定当前登录用户 // 若开启家庭共享检查目标账户是否属于同一家庭 $account FinanceAccount::find($data[account_id]); if ($account $account-family_id ! session(family_id)) { $this-error(您无权操作该账户); } $validate validate(FinanceRecord); if (!$validate-check($data)) { $this-error($validate-getError()); } $result FinanceRecord::create($data); if ($result) { $this-success(添加成功, index); } else { $this-error(添加失败); } } }session(family_id)是用户登录时存入的家族标识$account-family_id是账户所属家族 ID。此逻辑确保 A 用户无法向 B 用户的账户记账即使 URL 被篡改。这种「数据归属权」控制比 RBAC 更细粒度是家庭场景的刚需。3.4 报表生成中 SQL 聚合与 PHP 处理的分工边界application/index/controller/Report.php的monthly()方法展示如何平衡数据库计算与 PHP 渲染public function monthly() { $year input(year, date(Y)); $month input(month, date(m)); // 数据库层聚合按分类统计当月收支 $income FinanceRecord::where(user_id, session(user_id)) -where(is_income, 1) -whereYear(create_time, $year) -whereMonth(create_time, $month) -field(category_id, SUM(amount) as total) -group(category_id) -select(); $expense FinanceRecord::where(user_id, session(user_id)) -where(is_income, 0) -whereYear(create_time, $year) -whereMonth(create_time, $month) -field(category_id, SUM(amount) as total) -group(category_id) -select(); // PHP 层合并将收入/支出按分类 ID 对齐生成图表数据 $categories FinanceCategory::all([id, name, type]); // type1收入,2支出 $chartData []; foreach ($categories as $cat) { $inc 0; $exp 0; foreach ($income as $row) { if ($row[category_id] $cat[id]) $inc $row[total]; } foreach ($expense as $row) { if ($row[category_id] $cat[id]) $exp $row[total]; } $chartData[] [ name $cat[name], income $inc, expense $exp, ]; } $this-assign(chartData, json_encode($chartData)); return $this-fetch(); }此处SUM(amount)由 MySQL 完成利用索引加速而「按分类名对齐」逻辑交由 PHP 处理因分类表较小通常 50 条PHP 循环成本远低于复杂 JOIN。json_encode()输出供 ECharts 前端渲染体现前后端职责分离。4. 从源码到可用系统的三类必调参数与两个高频排错点4.1 数据库连接、时区、调试模式的三项基础配置修改application/database.php、application/config.php、thinkphp/base.php是三处必须检查的配置文件配置文件参数名默认值必调原因建议值application/database.phpdebug truetrue生产环境必须关闭否则暴露 SQL 语句falseapplication/config.phpdefault_timezone PRCAsia/ShanghaiPRC 已废弃PHP 7.0 要求标准时区名Asia/Shanghaithinkphp/base.phpini_set(display_errors, Off)On开发时可开上线必须关防止错误信息泄露Off修改后需清空runtime/目录下所有缓存文件rm -rf runtime/*否则配置不生效。特别是runtime/cache/和runtime/log/TP5 会缓存配置文件哈希值。4.2 附件上传路径与权限的本地化适配源码中图片附件功能常位于application/index/controller/Upload.php其uploadImage()方法默认保存到public/uploads/。但 Linux 服务器需确保该目录可写# 进入 public 目录 cd public mkdir -p uploads chmod 755 uploads chown www-data:www-data uploads # Ubuntu/Debian # 或 chown nginx:nginx uploads # CentOS同时检查application/index/validate/UploadValidate.php中的fileSize规则file_size require|fileSize:2097152, // 2MB 限制 file_ext require|fileExt:jpg,png,gif,jpeg,若需上传 PDF 说明书需在file_ext中追加pdf并在php.ini中调整upload_max_filesize 8M和post_max_size 8M。4.3 两个高频排错点URL 重写失效与 Session 丢失问题1访问/index/account/index提示 404但/index.php?s/index/account/index正常这是 Apache/Nginx 未启用 URL 重写导致。Apache 需确认.htaccess文件存在且AllowOverride All已开启Nginx 需在 server 块中添加location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; break; } }问题2登录后刷新页面提示「请先登录」Session 无法保持检查application/config.php中的session配置session [ prefix family_, type , auto_start true, ],若type为空TP5 使用 PHP 默认 session 处理器此时需确认session.save_path指向可写的目录如/var/lib/php/sessions并执行sudo chmod 777 /var/lib/php/sessions sudo chown www-data:www-data /var/lib/php/sessions提示若使用 Redis 存储 Session需安装php-redis扩展并将type设为redis同时配置redis_host、redis_port等参数。5. 将家庭财务系统升级为多人协作模式的三个关键改造点5.1 在用户表中增加 family_id 字段并建立家庭关系链原始源码的finance_user表通常只有id、username、password字段。要支持「夫妻共管」需扩展ALTER TABLE finance_user ADD COLUMN family_id INT UNSIGNED NOT NULL DEFAULT 0 AFTER id, ADD COLUMN role TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT 1-成员,2-管理员 AFTER family_id, ADD INDEX idx_family_id (family_id);role2的用户可管理家庭成员增删改其他用户role1仅能查看和记账。登录后session(family_id)从用户表读取替代硬编码。5.2 账户表增加 shared_flag 字段控制跨成员可见性finance_account表新增字段ALTER TABLE finance_account ADD COLUMN shared_flag TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 0-私有,1-家庭共享 AFTER user_id;在FinanceAccount模型的scopeShared方法中定义public function scopeShared($query) { $query-where(shared_flag, 1) -where(family_id, session(family_id)); }则FinanceAccount::shared()-select()可获取所有家庭共享账户供成员选择。5.3 报表页增加「按成员筛选」的前端交互与后端聚合前端report/monthly.html增加下拉框select nameuser_id iduserFilter option value0全部成员/option {volist nameusers iduser} option value{$user.id}{$user.username}/option {/volist} /select后端Report/monthly方法接收user_id参数并动态构建查询条件$user_id input(user_id, 0); $where [user_id session(user_id)]; if ($user_id 0) { // 管理员可查指定成员 $where [user_id $user_id, family_id session(family_id)]; } $income FinanceRecord::where($where)-where(is_income, 1)-...-select();此改造使系统从「单人记账」跃升为「家庭财务中枢」无需重写核心逻辑仅通过字段扩展与查询条件组合即可实现。5.4 使用 TP5 的事件系统解耦「记账成功」后的通知动作在FinanceRecord模型的afterInsert钩子中触发事件避免控制器逻辑臃肿// application/index/model/FinanceRecord.php protected function afterInsert($data) { // 记账成功后触发事件 \think\Event::trigger(FinanceRecordAdd, $this); } // application/event.php 中绑定监听器 return [ FinanceRecordAdd [ app\\index\\event\\SendSms, app\\index\\event\\UpdateBalance, ], ];UpdateBalance监听器可实时更新账户余额?php namespace app\index\event; use app\index\model\FinanceAccount; class UpdateBalance { public function handle($record) { $account FinanceAccount::find($record-account_id); if ($record-is_income) { $account-balance $record-amount; } else { $account-balance - $record-amount; } $account-save(); } }这种事件驱动设计让「记账」与「余额更新」、「短信通知」解耦后续增加邮件提醒只需新增监听器不改动原有代码。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门