feat: 新增地址选择插件及订阅消息等多项功能优化
- 新增地址选择插件,支持地图位置选择并返回地址和经纬度 - 新增微信订阅消息发送功能,支持审核结果、提现通知等场景 - 新增订单支付状态查询、提现收款人姓名保存等接口 - 新增服务区域管理,支持按省市区划分并同步到信息发布 - 新增资金流水和营收报表导出功能 - 新增可用优惠券查询、订单退款拆分处理等功能 - 优化后台角标显示、首页数据统计、UI配置下发等 - 修复订单支付并发问题、地区管理逻辑等
这个提交包含在:
@@ -83,6 +83,15 @@ class FcInstall extends Command
|
||||
$output->writeln('==> LBS / 店铺装修 / 支付 / 优惠券 / 举报升级(v1.7.0)');
|
||||
$this->upgradeV170($output);
|
||||
|
||||
$output->writeln('==> 提现商家转账字段升级(v1.2.1)');
|
||||
$this->upgradeV121($output);
|
||||
|
||||
$output->writeln('==> 优惠券抵扣 / 佣金结算字段升级(v1.2.2)');
|
||||
$this->upgradeV122($output);
|
||||
|
||||
$output->writeln('==> 服务区域平铺升级(省 / 市 / 区县)');
|
||||
$this->upgradeArea($output);
|
||||
|
||||
$output->writeln('==> 初始化后台菜单');
|
||||
$this->menu($output);
|
||||
|
||||
@@ -329,6 +338,226 @@ class FcInstall extends Command
|
||||
: ' - LBS / 店铺装修 / 支付 / 优惠券 / 举报配置已是最新,无需处理');
|
||||
}
|
||||
|
||||
/**
|
||||
* v1.2.1:提现「商家转账」字段
|
||||
* - fa_fc_withdraw:out_bill_no / transfer_status / transfer_id / package_info / fail_reason / transfer_time
|
||||
* - fa_fc_user_ext:realname(收款人真实姓名)
|
||||
* 幂等:已存在则跳过
|
||||
*/
|
||||
private function upgradeV121(Output $output)
|
||||
{
|
||||
$prefix = \think\Config::get('database.prefix');
|
||||
$w = $prefix . 'fc_withdraw';
|
||||
$e = $prefix . 'fc_user_ext';
|
||||
|
||||
$cols = [
|
||||
'out_bill_no' => "ALTER TABLE `{$w}` ADD COLUMN `out_bill_no` varchar(32) NOT NULL DEFAULT '' COMMENT '微信商家转账商户单号'",
|
||||
'transfer_status' => "ALTER TABLE `{$w}` ADD COLUMN `transfer_status` varchar(16) NOT NULL DEFAULT '' COMMENT 'WAIT_USER_CONFIRM/PROCESSING/SUCCESS/FAIL/CANCELLED'",
|
||||
'transfer_id' => "ALTER TABLE `{$w}` ADD COLUMN `transfer_id` varchar(64) NOT NULL DEFAULT '' COMMENT '微信转账单号'",
|
||||
'package_info' => "ALTER TABLE `{$w}` ADD COLUMN `package_info` varchar(512) NOT NULL DEFAULT '' COMMENT '拉起确认收款页的package'",
|
||||
'fail_reason' => "ALTER TABLE `{$w}` ADD COLUMN `fail_reason` varchar(255) NOT NULL DEFAULT ''",
|
||||
'transfer_time' => "ALTER TABLE `{$w}` ADD COLUMN `transfer_time` int(10) DEFAULT NULL",
|
||||
];
|
||||
|
||||
$changed = 0;
|
||||
foreach ($cols as $col => $sql) {
|
||||
if ($this->hasColumn($w, $col)) {
|
||||
continue;
|
||||
}
|
||||
Db::execute($sql);
|
||||
$changed++;
|
||||
}
|
||||
|
||||
try {
|
||||
Db::execute("ALTER TABLE `{$w}` ADD KEY `out_bill_no` (`out_bill_no`)");
|
||||
$changed++;
|
||||
} catch (\Exception $e2) {
|
||||
// 索引已存在则忽略
|
||||
}
|
||||
|
||||
if (!$this->hasColumn($e, 'realname')) {
|
||||
Db::execute("ALTER TABLE `{$e}` ADD COLUMN `realname` varchar(32) NOT NULL DEFAULT '' COMMENT '收款人真实姓名(提现用)'");
|
||||
$changed++;
|
||||
}
|
||||
|
||||
// 退款单号(微信退款结果回调按此匹配订单)
|
||||
$o = $prefix . 'fc_order';
|
||||
if (!$this->hasColumn($o, 'out_refund_no')) {
|
||||
Db::execute("ALTER TABLE `{$o}` ADD COLUMN `out_refund_no` varchar(64) NOT NULL DEFAULT '' COMMENT '微信退款单号(商户侧)'");
|
||||
$changed++;
|
||||
}
|
||||
|
||||
$output->writeln($changed
|
||||
? ' - 完成(新增结构 ' . $changed . ' 处)'
|
||||
: ' - 提现转账字段已是最新,无需处理');
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务区域平铺升级(省 / 市 / 区县三列,不再使用层级)
|
||||
*
|
||||
* 目标结构:fc_area(id, province, city, district, lat, lng, sort, enabled)
|
||||
* 每条记录 = 一个服务区域(区县);省 / 市只是该行的归属字段,供前端级联。
|
||||
* 历史层级数据会自动压平:每个区县保留原 ID,省 / 市节点删除。
|
||||
* 幂等:可重复执行。
|
||||
*/
|
||||
private function upgradeArea(Output $output)
|
||||
{
|
||||
$prefix = \think\Config::get('database.prefix');
|
||||
$areaTable = $prefix . 'fc_area';
|
||||
$postTable = $prefix . 'fc_post';
|
||||
$draftTable = $prefix . 'fc_draft';
|
||||
$now = time();
|
||||
$changed = 0;
|
||||
|
||||
// ① fc_area 平铺字段
|
||||
$areaCols = [
|
||||
'province' => "ALTER TABLE `{$areaTable}` ADD COLUMN `province` varchar(32) NOT NULL DEFAULT '' COMMENT '省份' AFTER `id`",
|
||||
'city' => "ALTER TABLE `{$areaTable}` ADD COLUMN `city` varchar(32) NOT NULL DEFAULT '' COMMENT '城市' AFTER `province`",
|
||||
'district' => "ALTER TABLE `{$areaTable}` ADD COLUMN `district` varchar(32) NOT NULL DEFAULT '' COMMENT '区县(最终服务区域)' AFTER `city`",
|
||||
'lat' => "ALTER TABLE `{$areaTable}` ADD COLUMN `lat` decimal(10,6) DEFAULT NULL COMMENT '中心纬度(gcj02)' AFTER `district`",
|
||||
'lng' => "ALTER TABLE `{$areaTable}` ADD COLUMN `lng` decimal(10,6) DEFAULT NULL COMMENT '中心经度(gcj02)' AFTER `lat`",
|
||||
];
|
||||
foreach ($areaCols as $col => $sql) {
|
||||
if ($this->hasColumn($areaTable, $col)) {
|
||||
continue;
|
||||
}
|
||||
Db::execute($sql);
|
||||
$changed++;
|
||||
}
|
||||
if (!$this->hasIndex($areaTable, 'province_city')) {
|
||||
Db::execute("ALTER TABLE `{$areaTable}` ADD KEY `province_city` (`province`,`city`)");
|
||||
}
|
||||
|
||||
// ② 旧层级数据压平:区县保留原 ID,省 / 市节点删除
|
||||
$hasLevel = $this->hasColumn($areaTable, 'level');
|
||||
$hasParent = $this->hasColumn($areaTable, 'parent_id');
|
||||
$hasName = $this->hasColumn($areaTable, 'name');
|
||||
|
||||
if ($hasLevel || $hasParent || $hasName) {
|
||||
$rows = Db::name('fc_area')->select();
|
||||
$byId = [];
|
||||
foreach ($rows as $row) {
|
||||
$byId[(int)$row['id']] = $row;
|
||||
}
|
||||
|
||||
$flat = 0;
|
||||
foreach ($rows as $row) {
|
||||
$level = $hasLevel ? (int)$row['level'] : 0;
|
||||
// 只保留区县(level=3);真实省份/城市节点稍后删除
|
||||
if ($hasLevel && $level > 0 && $level < 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$provinceName = '';
|
||||
$cityName = '';
|
||||
$districtName = $hasName ? (string)$row['name'] : (string)$row['district'];
|
||||
|
||||
if ($hasParent && (int)$row['parent_id'] > 0 && isset($byId[(int)$row['parent_id']])) {
|
||||
$cityRow = $byId[(int)$row['parent_id']];
|
||||
$cityName = $hasName ? (string)$cityRow['name'] : (string)$cityRow['city'];
|
||||
if ((int)$cityRow['parent_id'] > 0 && isset($byId[(int)$cityRow['parent_id']])) {
|
||||
$provinceRow = $byId[(int)$cityRow['parent_id']];
|
||||
$provinceName = $hasName ? (string)$provinceRow['name'] : (string)$provinceRow['province'];
|
||||
}
|
||||
}
|
||||
|
||||
Db::name('fc_area')->where('id', $row['id'])->update([
|
||||
'province' => $provinceName,
|
||||
'city' => $cityName,
|
||||
'district' => $districtName,
|
||||
'updatetime' => $now,
|
||||
]);
|
||||
$flat++;
|
||||
}
|
||||
|
||||
// 删除省 / 市节点(它们不是服务区域)
|
||||
if ($hasLevel) {
|
||||
$deleted = Db::name('fc_area')->where('level', 'in', [1, 2])->delete();
|
||||
}
|
||||
// 删除旧字段,彻底去掉层级概念
|
||||
foreach (['parent_id', 'level', 'name'] as $col) {
|
||||
if ($this->hasColumn($areaTable, $col)) {
|
||||
Db::execute("ALTER TABLE `{$areaTable}` DROP COLUMN `{$col}`");
|
||||
}
|
||||
}
|
||||
$output->writeln(' - 已将 ' . $flat . ' 条区域压平为「省 / 市 / 区县」三列');
|
||||
}
|
||||
|
||||
// ③ 已知区县中心坐标(仅补空值)
|
||||
$coords = [
|
||||
'云岩区' => [26.605, 106.710],
|
||||
'南明区' => [26.568, 106.716],
|
||||
'观山湖区' => [26.625, 106.625],
|
||||
'花溪区' => [26.430, 106.670],
|
||||
'白云区' => [26.678, 106.623],
|
||||
];
|
||||
foreach ($coords as $name => $ll) {
|
||||
Db::name('fc_area')->where('district', $name)->whereNull('lat')->update([
|
||||
'lat' => $ll[0], 'lng' => $ll[1], 'updatetime' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
// ④ fc_post:保留 district_id 作为服务区域ID,移除省/市 ID 列
|
||||
if (!$this->hasColumn($postTable, 'district_id')) {
|
||||
Db::execute("ALTER TABLE `{$postTable}` ADD COLUMN `district_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '服务区域ID(fc_area.id)' AFTER `area`");
|
||||
$changed++;
|
||||
}
|
||||
foreach (['province_id', 'city_id'] as $col) {
|
||||
if ($this->hasColumn($postTable, $col)) {
|
||||
Db::execute("ALTER TABLE `{$postTable}` DROP COLUMN `{$col}`");
|
||||
}
|
||||
}
|
||||
if (!$this->hasIndex($postTable, 'district_id')) {
|
||||
Db::execute("ALTER TABLE `{$postTable}` ADD KEY `district_id` (`district_id`)");
|
||||
}
|
||||
|
||||
// ⑤ fc_draft:同样只保留 area + district_id
|
||||
foreach (['area', 'district_id'] as $col) {
|
||||
if ($this->hasColumn($draftTable, $col)) {
|
||||
continue;
|
||||
}
|
||||
$sql = $col === 'area'
|
||||
? "ALTER TABLE `{$draftTable}` ADD COLUMN `area` varchar(32) NOT NULL DEFAULT '' COMMENT '区县名称' AFTER `address`"
|
||||
: "ALTER TABLE `{$draftTable}` ADD COLUMN `district_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '服务区域ID(fc_area.id)' AFTER `area`";
|
||||
Db::execute($sql);
|
||||
$changed++;
|
||||
}
|
||||
foreach (['province_id', 'city_id'] as $col) {
|
||||
if ($this->hasColumn($draftTable, $col)) {
|
||||
Db::execute("ALTER TABLE `{$draftTable}` DROP COLUMN `{$col}`");
|
||||
}
|
||||
}
|
||||
|
||||
// ⑥ 按区县名称回填 district_id(信息 / 草稿)
|
||||
$byName = [];
|
||||
foreach (Db::name('fc_area')->select() as $area) {
|
||||
$byName[(string)$area['district']] = (int)$area['id'];
|
||||
}
|
||||
$backfilled = 0;
|
||||
foreach ([['fc_post', 'updatetime'], ['fc_draft', null]] as $t) {
|
||||
$rows = Db::name($t[0])->where('district_id', 0)->where('area', '<>', '')->field('id,area')->select();
|
||||
foreach ($rows as $row) {
|
||||
if (!isset($byName[$row['area']])) {
|
||||
continue;
|
||||
}
|
||||
$data = ['district_id' => $byName[$row['area']]];
|
||||
if ($t[1]) {
|
||||
$data[$t[1]] = $now;
|
||||
}
|
||||
Db::name($t[0])->where('id', $row['id'])->update($data);
|
||||
$backfilled++;
|
||||
}
|
||||
}
|
||||
if ($backfilled) {
|
||||
$output->writeln(' - 已回填 ' . $backfilled . ' 条信息/草稿的服务区域ID');
|
||||
}
|
||||
|
||||
$output->writeln($changed || $backfilled
|
||||
? ' - 完成(结构变更 ' . $changed . ' 处,回填 ' . $backfilled . ' 条)'
|
||||
: ' - 服务区域已是平铺结构,无需处理');
|
||||
}
|
||||
|
||||
|
||||
/** 表是否存在某列 */
|
||||
private function hasColumn($table, $column)
|
||||
{
|
||||
@@ -336,6 +565,48 @@ class FcInstall extends Command
|
||||
return !empty($cols);
|
||||
}
|
||||
|
||||
/**
|
||||
* v1.2.2:优惠券抵扣 + 佣金结算周期
|
||||
* - fa_fc_order:origin_amount / coupon_amount / coupon_id
|
||||
* - fa_fc_commission:settle_due(预计结算时间)
|
||||
*/
|
||||
private function upgradeV122(Output $output)
|
||||
{
|
||||
$prefix = \think\Config::get('database.prefix');
|
||||
$o = $prefix . 'fc_order';
|
||||
$c = $prefix . 'fc_commission';
|
||||
|
||||
$changed = 0;
|
||||
|
||||
$orderCols = [
|
||||
'origin_amount' => "ALTER TABLE `{$o}` ADD COLUMN `origin_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠前金额'",
|
||||
'coupon_amount' => "ALTER TABLE `{$o}` ADD COLUMN `coupon_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠券抵扣金额'",
|
||||
'coupon_id' => "ALTER TABLE `{$o}` ADD COLUMN `coupon_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用的用户优惠券ID'",
|
||||
];
|
||||
foreach ($orderCols as $col => $sql) {
|
||||
if (!$this->hasColumn($o, $col)) {
|
||||
Db::execute($sql);
|
||||
$changed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->hasColumn($c, 'settle_due')) {
|
||||
Db::execute("ALTER TABLE `{$c}` ADD COLUMN `settle_due` int(10) DEFAULT NULL COMMENT '预计结算时间'");
|
||||
$changed++;
|
||||
}
|
||||
|
||||
$output->writeln($changed
|
||||
? ' - 完成(新增结构 ' . $changed . ' 处)'
|
||||
: ' - 优惠券/结算字段已是最新,无需处理');
|
||||
}
|
||||
|
||||
/** 表是否存在某个索引 */
|
||||
private function hasIndex($table, $index)
|
||||
{
|
||||
$rows = Db::query("SHOW INDEX FROM `{$table}` WHERE Key_name = '" . addslashes($index) . "'");
|
||||
return !empty($rows);
|
||||
}
|
||||
|
||||
/** 读配置默认值(不依赖 api 基类的 cfg 缓存) */
|
||||
private function cfgValue($key, $default = null)
|
||||
{
|
||||
@@ -350,184 +621,15 @@ class FcInstall extends Command
|
||||
/**
|
||||
* 初始化 FastAdmin 后台菜单(幂等)
|
||||
*
|
||||
* 结构:
|
||||
* 同城业务 (fc)
|
||||
* ├─ 内容管理 分类管理 / 轮播管理 / 信息管理 / 评价管理 / 举报处理
|
||||
* ├─ 用户与商家 商家管理 / 会员管理 / 消息管理
|
||||
* ├─ 交易管理 订单管理 / 会员套餐 / 优惠券管理 / 资金流水 / 佣金明细 / 付费查看记录
|
||||
* ├─ 分销管理 分销关系 / 提现审核
|
||||
* └─ 基础数据 服务区域 / 草稿箱
|
||||
* v1.7.0 追加(幂等):数据总览 fc/dashboard(置首)、系统设置 fc/setting(置末),
|
||||
* 以及上述「交易管理」下的优惠券管理 fc/coupon 与它们的节点权限。
|
||||
* 菜单结构统一定义在 FcMenu::GROUPS / FcMenu::ITEMS,
|
||||
* 保证 fc:install 与 fc:menu 产出同一套菜单。
|
||||
*/
|
||||
protected function menu(Output $output)
|
||||
{
|
||||
$now = time();
|
||||
$ruleTable = Db::name('auth_rule');
|
||||
|
||||
// 1) 顶级菜单
|
||||
$top = $ruleTable->where('name', 'fc')->find();
|
||||
$topData = [
|
||||
'type' => 'file', 'title' => '同城业务', 'icon' => 'fa fa-map-marker',
|
||||
'ismenu' => 1, 'menutype' => 'addtabs', 'weigh' => 95,
|
||||
'status' => 'normal', 'updatetime' => $now,
|
||||
];
|
||||
if ($top) {
|
||||
$ruleTable->where('id', $top['id'])->update($topData);
|
||||
$topId = (int)$top['id'];
|
||||
} else {
|
||||
$topData['pid'] = 0;
|
||||
$topData['name'] = 'fc';
|
||||
$topData['url'] = '';
|
||||
$topData['createtime'] = $now;
|
||||
$topId = (int)$ruleTable->insertGetId($topData);
|
||||
}
|
||||
|
||||
// 2) 分组菜单
|
||||
$groups = [
|
||||
['fc/content', '内容管理', 'fa fa-file-text-o', 90],
|
||||
['fc/user', '用户与商家', 'fa fa-users', 80],
|
||||
['fc/trade', '交易管理', 'fa fa-shopping-cart', 70],
|
||||
['fc/dist', '分销管理', 'fa fa-share-alt', 60],
|
||||
['fc/base', '基础数据', 'fa fa-database', 50],
|
||||
];
|
||||
$groupId = [];
|
||||
foreach ($groups as $g) {
|
||||
$row = $ruleTable->where('name', $g[0])->find();
|
||||
$data = [
|
||||
'type' => 'menu', 'pid' => $topId, 'title' => $g[1], 'icon' => $g[2],
|
||||
'url' => '', 'ismenu' => 1, 'menutype' => 'addtabs',
|
||||
'weigh' => $g[3], 'status' => 'normal', 'updatetime' => $now,
|
||||
];
|
||||
if ($row) {
|
||||
$ruleTable->where('id', $row['id'])->update($data);
|
||||
$groupId[$g[0]] = (int)$row['id'];
|
||||
} else {
|
||||
$data['name'] = $g[0];
|
||||
$data['createtime'] = $now;
|
||||
$groupId[$g[0]] = (int)$ruleTable->insertGetId($data);
|
||||
}
|
||||
}
|
||||
|
||||
// 3) 各业务控制器归组 + 中文标题 + 图标 + 排序
|
||||
$items = [
|
||||
'fc/category' => ['fc/content', '分类管理', 'fa fa-list', 95],
|
||||
'fc/banner' => ['fc/content', '轮播管理', 'fa fa-image', 90],
|
||||
'fc/post' => ['fc/content', '信息管理', 'fa fa-file-text', 85],
|
||||
'fc/comment' => ['fc/content', '评价管理', 'fa fa-star', 80],
|
||||
'fc/report' => ['fc/content', '举报处理', 'fa fa-flag', 75],
|
||||
'fc/merchant' => ['fc/user', '商家管理', 'fa fa-building', 95],
|
||||
'fc/userext' => ['fc/user', '会员管理', 'fa fa-user-circle', 90],
|
||||
'fc/message' => ['fc/user', '消息管理', 'fa fa-bell', 85],
|
||||
'fc/order' => ['fc/trade', '订单管理', 'fa fa-file-text-o', 95],
|
||||
'fc/plan' => ['fc/trade', '会员套餐', 'fa fa-diamond', 90],
|
||||
'fc/financeflow' => ['fc/trade', '资金流水', 'fa fa-money', 85],
|
||||
'fc/commission' => ['fc/trade', '佣金明细', 'fa fa-cny', 80],
|
||||
'fc/payview' => ['fc/trade', '付费查看记录', 'fa fa-eye', 75],
|
||||
'fc/distrelation' => ['fc/dist', '分销关系', 'fa fa-sitemap', 95],
|
||||
'fc/withdraw' => ['fc/dist', '提现审核', 'fa fa-credit-card', 90],
|
||||
'fc/area' => ['fc/base', '服务区域', 'fa fa-map-o', 95],
|
||||
'fc/publish' => ['fc/base', '发布与费用配置', 'fa fa-cny', 85],
|
||||
'fc/draft' => ['fc/base', '草稿箱', 'fa fa-folder-o', 90],
|
||||
];
|
||||
$done = 0;
|
||||
foreach ($items as $name => $m) {
|
||||
if (!isset($groupId[$m[0]])) {
|
||||
continue;
|
||||
}
|
||||
$aff = $ruleTable->where('name', $name)->update([
|
||||
'pid' => $groupId[$m[0]],
|
||||
'title' => $m[1],
|
||||
'icon' => $m[2],
|
||||
'weigh' => $m[3],
|
||||
'ismenu' => 1,
|
||||
'status' => 'normal',
|
||||
'updatetime' => $now,
|
||||
]);
|
||||
$done += $aff > 0 ? 1 : 1;
|
||||
}
|
||||
|
||||
// 4) v1.7.0 新增功能项(按 name upsert:不存在则插入,存在则纠正归属/名称/图标/排序)
|
||||
// ID 交给数据库自增分配(当前 fa_auth_rule 最大 ID 为 224),不写死 ID,故不会占用已用 ID。
|
||||
// 顶级分组「同城业务」下:数据总览置首(weigh 99 > 内容管理 90)、系统设置置末(weigh 40 < 基础数据 50);
|
||||
// 「交易管理」下:优惠券管理排在会员套餐之后、资金流水之前。
|
||||
$groupId['fc'] = $topId;
|
||||
$newItems = [
|
||||
'fc/dashboard' => ['fc', '数据总览', 'fa fa-dashboard', 99],
|
||||
'fc/setting' => ['fc', '小程序设置', 'fa fa-cogs', 40],
|
||||
'fc/coupon' => ['fc/trade', '优惠券管理', 'fa fa-ticket', 88],
|
||||
];
|
||||
$newIds = [];
|
||||
$inserted = 0;
|
||||
foreach ($newItems as $name => $m) {
|
||||
if (!isset($groupId[$m[0]])) {
|
||||
continue;
|
||||
}
|
||||
$row = $ruleTable->where('name', $name)->find();
|
||||
$data = [
|
||||
'pid' => $groupId[$m[0]], 'title' => $m[1], 'icon' => $m[2], 'weigh' => $m[3],
|
||||
'ismenu' => 1, 'menutype' => 'addtabs', 'status' => 'normal', 'updatetime' => $now,
|
||||
];
|
||||
if ($row) {
|
||||
$ruleTable->where('id', $row['id'])->update($data);
|
||||
$newIds[$name] = (int)$row['id'];
|
||||
} else {
|
||||
$data['type'] = 'menu';
|
||||
$data['name'] = $name;
|
||||
$data['url'] = '';
|
||||
$data['createtime'] = $now;
|
||||
$newIds[$name] = (int)$ruleTable->insertGetId($data);
|
||||
$inserted++;
|
||||
}
|
||||
}
|
||||
|
||||
// 5) 新功能项的节点权限(Backend 按「控制器/方法」校验权限,缺节点则非超管会 403)
|
||||
$nodes = [
|
||||
'fc/dashboard/index' => ['fc/dashboard', '查看'],
|
||||
'fc/setting/index' => ['fc/setting', '查看'],
|
||||
'fc/coupon/index' => ['fc/coupon', '查看'],
|
||||
'fc/coupon/add' => ['fc/coupon', '添加'],
|
||||
'fc/coupon/edit' => ['fc/coupon', '编辑'],
|
||||
'fc/coupon/del' => ['fc/coupon', '删除'],
|
||||
'fc/coupon/multi' => ['fc/coupon', '批量更新'],
|
||||
];
|
||||
$nodeCount = 0;
|
||||
foreach ($nodes as $name => $n) {
|
||||
if (!isset($newIds[$n[0]])) {
|
||||
continue;
|
||||
}
|
||||
$row = $ruleTable->where('name', $name)->find();
|
||||
$data = [
|
||||
'pid' => $newIds[$n[0]], 'title' => $n[1], 'icon' => 'fa fa-circle-o',
|
||||
'ismenu' => 0, 'weigh' => 0, 'status' => 'normal', 'updatetime' => $now,
|
||||
];
|
||||
if ($row) {
|
||||
$ruleTable->where('id', $row['id'])->update($data);
|
||||
} else {
|
||||
$data['type'] = 'file';
|
||||
$data['name'] = $name;
|
||||
$data['url'] = '';
|
||||
$data['menutype'] = 'addtabs';
|
||||
$data['createtime'] = $now;
|
||||
$ruleTable->insert($data);
|
||||
}
|
||||
$nodeCount++;
|
||||
}
|
||||
|
||||
$output->writeln(' - 顶级 1 / 分组 ' . count($groups) . ' / 功能项 ' . $done);
|
||||
$output->writeln(' - 新功能项 ' . count($newItems) . ' 个(本次新插入 ' . $inserted . ')+ 权限节点 ' . $nodeCount . ' 个'
|
||||
. ':数据总览 fc/dashboard、系统设置 fc/setting、优惠券管理 fc/coupon');
|
||||
|
||||
// 左侧菜单来自 Auth::getSidebar() 的 `__menu__` 缓存:不清这里,本命令刚插入的
|
||||
// 「数据总览 / 系统设置 / 优惠券管理」在缓存过期前不会出现在后台侧边栏。
|
||||
try {
|
||||
\think\Cache::rm('__menu__');
|
||||
$output->writeln(' - 已清理后台菜单缓存 __menu__(新菜单项即时可见)');
|
||||
} catch (\Exception $e) {
|
||||
// 清理失败不影响主流程:缓存过期后会自动重建
|
||||
}
|
||||
FcMenu::apply($output);
|
||||
}
|
||||
|
||||
|
||||
/** 清空业务表(保留表结构) */
|
||||
protected function truncateAll()
|
||||
{
|
||||
@@ -580,13 +682,19 @@ class FcInstall extends Command
|
||||
|
||||
'area' => "CREATE TABLE IF NOT EXISTS `#P#area` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(32) NOT NULL DEFAULT '',
|
||||
`province` varchar(32) NOT NULL DEFAULT '' COMMENT '省份',
|
||||
`city` varchar(32) NOT NULL DEFAULT '' COMMENT '城市',
|
||||
`district` varchar(32) NOT NULL DEFAULT '' COMMENT '区县(最终服务区域)',
|
||||
`lat` decimal(10,6) DEFAULT NULL COMMENT '中心纬度(gcj02)',
|
||||
`lng` decimal(10,6) DEFAULT NULL COMMENT '中心经度(gcj02)',
|
||||
`sort` int(10) NOT NULL DEFAULT '0',
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`createtime` int(10) DEFAULT NULL,
|
||||
`updatetime` int(10) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='同城-服务区域';",
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `province_city` (`province`,`city`),
|
||||
KEY `enabled` (`enabled`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='同城-服务区域(省/市/区县平铺,区县为服务区域)';",
|
||||
|
||||
'post' => "CREATE TABLE IF NOT EXISTS `#P#post` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
@@ -598,7 +706,8 @@ class FcInstall extends Command
|
||||
`media` text COMMENT '媒体JSON数组',
|
||||
`price` decimal(10,2) NOT NULL DEFAULT '0.00',
|
||||
`price_unit` varchar(16) NOT NULL DEFAULT '',
|
||||
`area` varchar(32) NOT NULL DEFAULT '',
|
||||
`area` varchar(32) NOT NULL DEFAULT '' COMMENT '区县名称(展示用)',
|
||||
`district_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '服务区域ID(fc_area.id)',
|
||||
`address` varchar(128) NOT NULL DEFAULT '',
|
||||
`contact` varchar(32) NOT NULL DEFAULT '' COMMENT '联系人',
|
||||
`phone` varchar(20) NOT NULL DEFAULT '' COMMENT '联系电话(完整)',
|
||||
@@ -621,7 +730,8 @@ class FcInstall extends Command
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `category_id` (`category_id`),
|
||||
KEY `user_id` (`user_id`),
|
||||
KEY `audit_status` (`audit_status`)
|
||||
KEY `audit_status` (`audit_status`),
|
||||
KEY `district_id` (`district_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='同城-信息';",
|
||||
|
||||
'draft' => "CREATE TABLE IF NOT EXISTS `#P#draft` (
|
||||
@@ -634,6 +744,8 @@ class FcInstall extends Command
|
||||
`contact` varchar(32) NOT NULL DEFAULT '',
|
||||
`phone` varchar(20) NOT NULL DEFAULT '',
|
||||
`address` varchar(128) NOT NULL DEFAULT '',
|
||||
`area` varchar(32) NOT NULL DEFAULT '' COMMENT '区县名称',
|
||||
`district_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '服务区域ID(fc_area.id)',
|
||||
`savedat` int(10) DEFAULT NULL,
|
||||
`createtime` int(10) DEFAULT NULL,
|
||||
`updatetime` int(10) DEFAULT NULL,
|
||||
@@ -698,10 +810,14 @@ class FcInstall extends Command
|
||||
`title` varchar(64) NOT NULL DEFAULT '',
|
||||
`amount` decimal(10,2) NOT NULL DEFAULT '0.00',
|
||||
`pay_type` varchar(16) NOT NULL DEFAULT '',
|
||||
`status` varchar(16) NOT NULL DEFAULT 'pending' COMMENT 'pending/paid/refunded/closed',
|
||||
`status` varchar(16) NOT NULL DEFAULT 'pending' COMMENT 'pending/paid/refunding/refunded/closed',
|
||||
`paytime` int(10) DEFAULT NULL,
|
||||
`origin_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠前金额',
|
||||
`coupon_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠券抵扣金额',
|
||||
`coupon_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用的用户优惠券ID(fc_user_coupon.id)',
|
||||
`refund_amount` decimal(10,2) NOT NULL DEFAULT '0.00',
|
||||
`refund_reason` varchar(255) NOT NULL DEFAULT '',
|
||||
`out_refund_no` varchar(64) NOT NULL DEFAULT '' COMMENT '微信退款单号(商户侧)',
|
||||
`related_id` int(10) NOT NULL DEFAULT '0' COMMENT '关联业务ID',
|
||||
`createtime` int(10) DEFAULT NULL,
|
||||
`updatetime` int(10) DEFAULT NULL,
|
||||
@@ -734,6 +850,7 @@ class FcInstall extends Command
|
||||
`openid` varchar(64) NOT NULL DEFAULT '' COMMENT '微信openid',
|
||||
`user_type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1个人2商家',
|
||||
`realname_status` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`realname` varchar(32) NOT NULL DEFAULT '' COMMENT '收款人真实姓名(提现用)',
|
||||
`is_member` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`member_level` varchar(32) NOT NULL DEFAULT '',
|
||||
`member_expiretime` int(10) DEFAULT NULL,
|
||||
@@ -772,6 +889,7 @@ class FcInstall extends Command
|
||||
`rate` decimal(5,2) NOT NULL DEFAULT '0.00' COMMENT '分佣比例%',
|
||||
`level` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0未结算1已结算',
|
||||
`settle_due` int(10) DEFAULT NULL,
|
||||
`settletime` int(10) DEFAULT NULL,
|
||||
`createtime` int(10) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
@@ -784,14 +902,21 @@ class FcInstall extends Command
|
||||
`user_id` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`amount` decimal(10,2) NOT NULL DEFAULT '0.00',
|
||||
`channel` varchar(16) NOT NULL DEFAULT 'wxpay',
|
||||
`status` varchar(16) NOT NULL DEFAULT 'auditing' COMMENT 'auditing/paid/rejected',
|
||||
`status` varchar(16) NOT NULL DEFAULT 'auditing' COMMENT 'auditing/paying/paid/failed/rejected',
|
||||
`reason` varchar(255) NOT NULL DEFAULT '' COMMENT '驳回原因',
|
||||
`paytime` int(10) DEFAULT NULL,
|
||||
`out_bill_no` varchar(32) NOT NULL DEFAULT '' COMMENT '微信商家转账商户单号',
|
||||
`transfer_status` varchar(16) NOT NULL DEFAULT '' COMMENT 'WAIT_USER_CONFIRM/PROCESSING/SUCCESS/FAIL/CANCELLED',
|
||||
`transfer_id` varchar(64) NOT NULL DEFAULT '' COMMENT '微信转账单号',
|
||||
`package_info` varchar(512) NOT NULL DEFAULT '' COMMENT '拉起确认收款页的package',
|
||||
`fail_reason` varchar(255) NOT NULL DEFAULT '',
|
||||
`transfer_time` int(10) DEFAULT NULL,
|
||||
`createtime` int(10) DEFAULT NULL,
|
||||
`updatetime` int(10) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `withdraw_no` (`withdraw_no`),
|
||||
KEY `user_id` (`user_id`)
|
||||
KEY `user_id` (`user_id`),
|
||||
KEY `out_bill_no` (`out_bill_no`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='同城-提现';",
|
||||
|
||||
'finance_flow' => "CREATE TABLE IF NOT EXISTS `#P#finance_flow` (
|
||||
@@ -977,11 +1102,19 @@ class FcInstall extends Command
|
||||
]);
|
||||
}
|
||||
|
||||
/* ---------- 服务区域 ---------- */
|
||||
$areas = [['云岩区', 1, 1], ['南明区', 2, 1], ['观山湖区', 3, 1], ['花溪区', 4, 1], ['白云区', 5, 0]];
|
||||
/* ---------- 服务区域(省 / 市 / 区县平铺,区县为服务区域) ---------- */
|
||||
$areas = [
|
||||
['贵州省', '贵阳市', '云岩区', 1, 1, 26.605, 106.710],
|
||||
['贵州省', '贵阳市', '南明区', 2, 1, 26.568, 106.716],
|
||||
['贵州省', '贵阳市', '观山湖区', 3, 1, 26.625, 106.625],
|
||||
['贵州省', '贵阳市', '花溪区', 4, 1, 26.430, 106.670],
|
||||
['贵州省', '贵阳市', '白云区', 5, 0, 26.678, 106.623],
|
||||
];
|
||||
foreach ($areas as $a) {
|
||||
Db::name('fc_area')->insert([
|
||||
'name' => $a[0], 'sort' => $a[1], 'enabled' => $a[2],
|
||||
'province' => $a[0], 'city' => $a[1], 'district' => $a[2],
|
||||
'lat' => $a[5], 'lng' => $a[6],
|
||||
'sort' => $a[3], 'enabled' => $a[4],
|
||||
'createtime' => $now, 'updatetime' => $now,
|
||||
]);
|
||||
}
|
||||
@@ -1000,7 +1133,7 @@ class FcInstall extends Command
|
||||
'createtime' => $now, 'updatetime' => $now,
|
||||
]);
|
||||
}
|
||||
$output->writeln(' - 分类8 / 轮播3 / 区域5 / 套餐3');
|
||||
$output->writeln(' - 分类8 / 轮播3 / 服务区域5 / 套餐3');
|
||||
|
||||
/* ---------- 演示用户(显式ID,与前端 mock 数据集一致) ---------- */
|
||||
$salt = 'fcseed';
|
||||
|
||||
在新工单中引用
屏蔽一个用户