feat: 完善会员资金明细与退款转账逻辑,新增支付密码组件与资金流水界面
这个提交包含在:
@@ -80,6 +80,9 @@ class FcInstall extends Command
|
||||
$output->writeln('==> 发布模式与发布套餐升级');
|
||||
$this->upgradePublish($output);
|
||||
|
||||
$output->writeln('==> 系统配置分组整理');
|
||||
$this->upgradeConfigGroups($output);
|
||||
|
||||
$output->writeln('==> LBS / 店铺装修 / 支付 / 优惠券 / 举报升级(v1.7.0)');
|
||||
$this->upgradeV170($output);
|
||||
|
||||
@@ -151,16 +154,16 @@ class FcInstall extends Command
|
||||
/**
|
||||
* 发布模式与发布套餐升级(幂等,可重复执行)
|
||||
*
|
||||
* 背景:v1.0.7 新增「免费发布 / 付费发布」开关与付费发布的三档定价
|
||||
* 背景:v1.0.7 新增「免费发布 / 付费发布」开关与付费发布定价
|
||||
* · 单条价格 post.singlePrice
|
||||
* · 免费发布条数 post.freeQuota / post.freeQuotaCycle(v1.0.10:达到条数后按单条价格计费)
|
||||
* · 按月(价格 + 含条数)post.monthPrice / post.monthQuota
|
||||
* · 按年(价格 + 含条数)post.yearPrice / post.yearQuota
|
||||
* 套餐价格与含发布条数唯一真源 = fc_plan(后台「运营推广 → 会员套餐」维护),
|
||||
* 不再使用 post.monthPrice / post.yearPrice 等配置键(历史键在本步骤清理)。
|
||||
* 老库缺列/缺配置时补齐,**不覆盖运营已改过的值**:
|
||||
* ① fc_user_ext 补 post_quota_left / post_quota_expire(剩余发布条数 + 有效期)
|
||||
* ② fc_plan 补 post_quota(套餐含发布条数,月/年卡赠送额度)
|
||||
* ③ fc_config 补 post.* 八项(已存在则跳过)
|
||||
* ④ 月卡/年卡的价格与条数以配置为准做一次同步(配置缺失时反向用套餐值填配置)
|
||||
* ③ fc_config 补 post.* 四项(已存在则跳过)
|
||||
* ④ 清理历史遗留的套餐定价配置键(post.month* / post.year* / fee.*)
|
||||
*/
|
||||
private function upgradePublish(Output $output)
|
||||
{
|
||||
@@ -197,10 +200,6 @@ class FcInstall extends Command
|
||||
['post.singlePrice', '5', 'post', '单条发布价格(元)=付费发布标准价'],
|
||||
['post.freeQuota', '0', 'post', '免费发布条数(0 = 不限制/免费到底;达到条数后按单条发布价格计费)'],
|
||||
['post.freeQuotaCycle', 'day', 'post', '免费条数统计周期:day 每日 / month 每月 / total 累计'],
|
||||
['post.monthPrice', '19.9', 'post', '按月发布价格(元)'],
|
||||
['post.monthQuota', '30', 'post', '按月含发布条数'],
|
||||
['post.yearPrice', '168', 'post', '按年发布价格(元)'],
|
||||
['post.yearQuota', '500', 'post', '按年含发布条数'],
|
||||
];
|
||||
$now = time();
|
||||
$added = [];
|
||||
@@ -219,27 +218,14 @@ class FcInstall extends Command
|
||||
$changed++;
|
||||
}
|
||||
|
||||
// ④ 月/年卡「价格 + 含发布条数」与配置对齐
|
||||
$map = ['M1' => ['post.monthPrice', 'post.monthQuota'], 'M12' => ['post.yearPrice', 'post.yearQuota']];
|
||||
$synced = 0;
|
||||
foreach ($map as $code => $keys) {
|
||||
$plan = Db::name('fc_plan')->where('plan_code', $code)->find();
|
||||
if (!$plan) {
|
||||
continue;
|
||||
}
|
||||
$price = round((float)$this->cfgValue($keys[0], $plan['price']), 2);
|
||||
$quota = (int)$this->cfgValue($keys[1], $plan['post_quota']);
|
||||
if (round((float)$plan['price'], 2) !== $price || (int)$plan['post_quota'] !== $quota) {
|
||||
Db::name('fc_plan')->where('id', $plan['id'])->update([
|
||||
'price' => $price,
|
||||
'post_quota' => $quota,
|
||||
'updatetime' => time(),
|
||||
]);
|
||||
$synced++;
|
||||
}
|
||||
}
|
||||
if ($synced) {
|
||||
$output->writeln(' - 会员套餐已与发布配置对齐 ' . $synced . ' 条(月/年卡价格与含条数)');
|
||||
// ④ 清理历史遗留配置键:套餐定价已统一到 fc_plan,发布免费条数只认 post.freeQuota
|
||||
$deprecated = [
|
||||
'post.monthPrice', 'post.monthQuota', 'post.yearPrice', 'post.yearQuota',
|
||||
'fee.singlePost', 'fee.freePostPerDay', 'fee.memberMonth', 'fee.memberQuarter', 'fee.memberYear',
|
||||
];
|
||||
$removedKeys = Db::name('fc_config')->where('key', 'in', $deprecated)->delete();
|
||||
if ($removedKeys) {
|
||||
$output->writeln(' - 清理废弃配置 ' . $removedKeys . ' 项(套餐定价真源已统一为 fc_plan)');
|
||||
$changed++;
|
||||
}
|
||||
|
||||
@@ -248,6 +234,43 @@ class FcInstall extends Command
|
||||
: ' - 发布模式与套餐配置已是最新,无需处理');
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统配置分组整理(幂等)
|
||||
*
|
||||
* 背景:fa_config 的 configgroup 字典保留了 FastAdmin 演示分组 user(会员配置)与
|
||||
* example(示例分组),两者没有任何配置项,却会在「系统配置」页渲染出空白 tab,
|
||||
* 且 user 与业务分组「会员配置」重名易混淆;这里从字典中移除。
|
||||
*/
|
||||
private function upgradeConfigGroups(Output $output)
|
||||
{
|
||||
$row = Db::name('config')->where('name', 'configgroup')->find();
|
||||
if (!$row) {
|
||||
$output->writeln(' - 未找到 configgroup 字典,跳过');
|
||||
return;
|
||||
}
|
||||
$decoded = json_decode((string)$row['value'], true);
|
||||
if (!is_array($decoded)) {
|
||||
$output->writeln(' - configgroup 字典格式异常,跳过');
|
||||
return;
|
||||
}
|
||||
$target = ['basic', 'email', 'dictionary'];
|
||||
$kept = [];
|
||||
foreach ($decoded as $k => $v) {
|
||||
if (in_array($k, $target, true) || strpos((string)$k, 'fc_') === 0) {
|
||||
$kept[$k] = $v;
|
||||
}
|
||||
}
|
||||
if ($kept === $decoded) {
|
||||
$output->writeln(' - 系统配置分组已是最新,无需处理');
|
||||
return;
|
||||
}
|
||||
Db::name('config')->where('name', 'configgroup')->update([
|
||||
'value' => json_encode($kept, JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
$removed = array_diff(array_keys($decoded), array_keys($kept));
|
||||
$output->writeln(' - 已移除空分组:' . implode(' / ', $removed));
|
||||
}
|
||||
|
||||
/**
|
||||
* v1.7.0 升级:LBS 经纬度 / 店铺装修字段 / 收藏关注 / 支付与举报配置(幂等,可重复执行)
|
||||
*
|
||||
@@ -642,6 +665,21 @@ class FcInstall extends Command
|
||||
protected function tables()
|
||||
{
|
||||
return [
|
||||
'wallet_flow' => "CREATE TABLE IF NOT EXISTS `#P#wallet_flow` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
|
||||
`flow_no` varchar(32) NOT NULL DEFAULT '' COMMENT '流水号',
|
||||
`type` varchar(10) NOT NULL DEFAULT '' COMMENT 'income=入账 expense=支出(用户钱包口径)',
|
||||
`scene` varchar(32) NOT NULL DEFAULT '' COMMENT '场景:余额充值/后台充值/会员开通/发布付费/付费查看/订单退款(余额)/佣金提现',
|
||||
`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变动金额',
|
||||
`balance` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变动后钱包余额(fa_user.money)',
|
||||
`related_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '关联单据ID(订单/信息/提现单)',
|
||||
`remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
|
||||
`createtime` int(10) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `flow_no` (`flow_no`),
|
||||
KEY `user_id` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='同城-用户钱包流水';",
|
||||
'config' => "CREATE TABLE IF NOT EXISTS `#P#config` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`key` varchar(64) NOT NULL DEFAULT '' COMMENT '配置键',
|
||||
@@ -860,6 +898,7 @@ class FcInstall extends Command
|
||||
`free_view_used` int(10) NOT NULL DEFAULT '0',
|
||||
`post_quota_left` int(10) NOT NULL DEFAULT '0' COMMENT '剩余发布条数(月/年套餐赠送)',
|
||||
`post_quota_expire` int(10) DEFAULT NULL COMMENT '发布额度有效期(=会员到期时间)',
|
||||
`pay_password` varchar(255) NOT NULL DEFAULT '' COMMENT '支付密码(password_hash,空=未设置)',
|
||||
`createtime` int(10) DEFAULT NULL,
|
||||
`updatetime` int(10) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
@@ -921,6 +960,7 @@ class FcInstall extends Command
|
||||
|
||||
'finance_flow' => "CREATE TABLE IF NOT EXISTS `#P#finance_flow` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '归属用户,0=平台/历史数据',
|
||||
`flow_no` varchar(32) NOT NULL DEFAULT '',
|
||||
`type` varchar(16) NOT NULL DEFAULT 'income' COMMENT 'income/expense',
|
||||
`scene` varchar(32) NOT NULL DEFAULT '' COMMENT '业务场景',
|
||||
@@ -930,7 +970,8 @@ class FcInstall extends Command
|
||||
`remark` varchar(255) NOT NULL DEFAULT '',
|
||||
`createtime` int(10) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `flow_no` (`flow_no`)
|
||||
UNIQUE KEY `flow_no` (`flow_no`),
|
||||
KEY `user_id` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='同城-资金流水';",
|
||||
|
||||
'message' => "CREATE TABLE IF NOT EXISTS `#P#message` (
|
||||
@@ -1035,20 +1076,12 @@ class FcInstall extends Command
|
||||
['wx.secret', 'b023726713eebe3dad3876f5cea8ee6a', 'wx', '小程序AppSecret(仅服务端持有,不下发前端)'],
|
||||
['pay.mchId', '', 'pay', '微信支付商户号'],
|
||||
['pay.apiKey', '', 'pay', '微信支付密钥'],
|
||||
['fee.singlePost', '5', 'fee', '单条发布价格(元)'],
|
||||
['fee.freePostPerDay', '2', 'fee', '每日免费发布条数'],
|
||||
['fee.memberMonth', '19.9', 'fee', '月卡价格'],
|
||||
['fee.memberQuarter', '49.9', 'fee', '季卡价格'],
|
||||
['fee.memberYear', '168', 'fee', '年卡价格'],
|
||||
// 发布模式与发布套餐(后台「发布与费用配置」页维护;真源=配置,保存时同步 fc_plan)
|
||||
// 发布模式与发布价格(后台「系统配置 → 发布配置」维护)
|
||||
// 套餐价格与含发布条数在 fc_plan(后台「运营推广 → 会员套餐」维护),不走配置键
|
||||
['post.mode', 'free', 'post', '发布模式:free 免费发布 / paid 付费发布(默认免费,避免上线即撞付费墙)'],
|
||||
['post.singlePrice', '5', 'post', '单条发布价格(元)=付费发布标准价'],
|
||||
['post.freeQuota', '0', 'post', '免费发布条数(0 = 不限制/免费到底;达到条数后按单条发布价格计费)'],
|
||||
['post.freeQuotaCycle', 'day', 'post', '免费条数统计周期:day 每日 / month 每月 / total 累计'],
|
||||
['post.monthPrice', '19.9', 'post', '按月发布价格(元)'],
|
||||
['post.monthQuota', '30', 'post', '按月含发布条数'],
|
||||
['post.yearPrice', '168', 'post', '按年发布价格(元)'],
|
||||
['post.yearQuota', '500', 'post', '按年含发布条数'],
|
||||
['dist.enabled', '1', 'dist', '是否开启分销'],
|
||||
['dist.level', '2', 'dist', '分佣层级'],
|
||||
['dist.level1Rate', '20', 'dist', '一级分佣比例%'],
|
||||
|
||||
在新工单中引用
屏蔽一个用户