|
|
@@ -7,7 +7,8 @@ use Yii;
|
|
|
|
|
|
/**
|
|
|
* 门店首页配置业务类
|
|
|
- * 配置项顺序与开关、顶部导航详情均按 mainId 维度落 Redis,不落库。
|
|
|
+ * 配置项顺序与开关、顶部导航详情按 shopId 维度落 MySQL(xhHomePageModuleConfig,唯一权威数据源),
|
|
|
+ * Redis 仅作兼容镜像;历史仅按 mainId 存在 Redis 的存量数据读取时自动回退迁移,见 HomePageModuleConfigClass。
|
|
|
*/
|
|
|
class HomePageConfigClass
|
|
|
{
|
|
|
@@ -74,30 +75,27 @@ class HomePageConfigClass
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 模块配置 Redis key
|
|
|
+ * 模块配置 Redis key;$id 现按 shopId 生成新 key,传 mainId 则生成历史迁移用的旧 key
|
|
|
*/
|
|
|
- public static function getModulesKey($mainId)
|
|
|
+ public static function getModulesKey($id)
|
|
|
{
|
|
|
- //return self::MODULES_PREFIX . intval($mainId);
|
|
|
- return sprintf(self::MODULES_PREFIX, $mainId);
|
|
|
+ return sprintf(self::MODULES_PREFIX, $id);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 顶部导航 Redis key
|
|
|
+ * 顶部导航 Redis key;$id 现按 shopId 生成新 key,传 mainId 则生成历史迁移用的旧 key
|
|
|
*/
|
|
|
- public static function getTopNavKey($mainId)
|
|
|
+ public static function getTopNavKey($id)
|
|
|
{
|
|
|
- //return self::TOP_NAV_PREFIX . intval($mainId);
|
|
|
- return sprintf(self::TOP_NAV_PREFIX, $mainId);
|
|
|
+ return sprintf(self::TOP_NAV_PREFIX, $id);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 轮播图 Redis key(按 mainId,便于 mallApp 按店铺主账号读取)
|
|
|
+ * 轮播图 Redis key;$id 现按 shopId 生成新 key,传 mainId 则生成历史迁移用的旧 key
|
|
|
*/
|
|
|
- public static function getBannerKey($mainId)
|
|
|
+ public static function getBannerKey($id)
|
|
|
{
|
|
|
- //return self::BANNER_PREFIX . intval($mainId);
|
|
|
- return sprintf(self::BANNER_PREFIX, $mainId);
|
|
|
+ return sprintf(self::BANNER_PREFIX, $id);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -132,23 +130,29 @@ class HomePageConfigClass
|
|
|
* 读取模块顺序与开关;缺失时用默认值补全
|
|
|
*
|
|
|
* @param int $mainId
|
|
|
+ * @param int $shopId
|
|
|
* @return array
|
|
|
*/
|
|
|
- public static function getModules($mainId)
|
|
|
+ public static function getModules($mainId, $shopId)
|
|
|
{
|
|
|
$mainId = intval($mainId);
|
|
|
- if ($mainId <= 0) {
|
|
|
+ $shopId = intval($shopId);
|
|
|
+ if ($shopId <= 0) {
|
|
|
util::fail('无效门店');
|
|
|
}
|
|
|
|
|
|
- $raw = Yii::$app->redis->executeCommand('GET', [self::getModulesKey($mainId)]);
|
|
|
- $saved = [];
|
|
|
- if (!empty($raw)) {
|
|
|
- $decoded = json_decode($raw, true);
|
|
|
- if (is_array($decoded)) {
|
|
|
- $saved = $decoded;
|
|
|
- }
|
|
|
+ $saved = HomePageModuleConfigClass::getConfigValue($shopId, 'modules');
|
|
|
+ if ($saved === null) {
|
|
|
+ // MySQL 无记录:回退历史 Redis 存量数据(按 mainId 存),命中后自愈迁移落库+镜像新 key
|
|
|
+ $saved = HomePageModuleConfigClass::migrateFromRedis(
|
|
|
+ $mainId,
|
|
|
+ $shopId,
|
|
|
+ 'modules',
|
|
|
+ self::getModulesKey($shopId),
|
|
|
+ self::getModulesKey($mainId)
|
|
|
+ );
|
|
|
}
|
|
|
+ $saved = is_array($saved) ? $saved : [];
|
|
|
|
|
|
// 按已保存顺序保留合法项,再补全缺失的默认模块
|
|
|
$result = [];
|
|
|
@@ -178,27 +182,35 @@ class HomePageConfigClass
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 保存模块顺序与开关(合并写入同一 Redis key)
|
|
|
+ * 保存模块顺序与开关:落库 MySQL(权威数据源),并镜像写入 Redis
|
|
|
* 请求形态校验由 SaveModulesForm 完成;$items 应为已规范化的 [{key,enabled}, ...]
|
|
|
*
|
|
|
* @param int $mainId
|
|
|
+ * @param int $shopId
|
|
|
* @param array $items [{key,enabled}, ...]
|
|
|
* @return bool
|
|
|
*/
|
|
|
- public static function saveModules($mainId, $items)
|
|
|
+ public static function saveModules($mainId, $shopId, $items)
|
|
|
{
|
|
|
$mainId = intval($mainId);
|
|
|
- if ($mainId <= 0) {
|
|
|
+ $shopId = intval($shopId);
|
|
|
+ if ($shopId <= 0) {
|
|
|
util::fail('无效门店');
|
|
|
}
|
|
|
if (!is_array($items)) {
|
|
|
util::fail('配置项格式错误');
|
|
|
}
|
|
|
|
|
|
- Yii::$app->redis->executeCommand('SET', [
|
|
|
- self::getModulesKey($mainId),
|
|
|
- json_encode(array_values($items), JSON_UNESCAPED_UNICODE),
|
|
|
- ]);
|
|
|
+ $payload = array_values($items);
|
|
|
+ HomePageModuleConfigClass::saveConfigValue($mainId, $shopId, 'modules', $payload);
|
|
|
+ try {
|
|
|
+ Yii::$app->redis->executeCommand('SET', [
|
|
|
+ self::getModulesKey($shopId),
|
|
|
+ json_encode($payload, JSON_UNESCAPED_UNICODE),
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Yii::error('同步首页模块配置到Redis失败: ' . $e->getMessage());
|
|
|
+ }
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -206,12 +218,13 @@ class HomePageConfigClass
|
|
|
* 从模块配置中取某个模块的开关状态
|
|
|
*
|
|
|
* @param int $mainId
|
|
|
+ * @param int $shopId
|
|
|
* @param string $moduleKey
|
|
|
* @return int 0|1
|
|
|
*/
|
|
|
- public static function getModuleEnabled($mainId, $moduleKey)
|
|
|
+ public static function getModuleEnabled($mainId, $shopId, $moduleKey)
|
|
|
{
|
|
|
- $modules = self::getModules($mainId);
|
|
|
+ $modules = self::getModules($mainId, $shopId);
|
|
|
foreach ($modules as $item) {
|
|
|
if (($item['key'] ?? '') === $moduleKey) {
|
|
|
return !empty($item['enabled']) ? 1 : 0;
|
|
|
@@ -221,20 +234,21 @@ class HomePageConfigClass
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 更新单个模块开关,并写回 modules Redis(与列表页共用同一份状态)
|
|
|
+ * 更新单个模块开关,并写回 modules 配置(与列表页共用同一份状态)
|
|
|
*
|
|
|
* @param int $mainId
|
|
|
+ * @param int $shopId
|
|
|
* @param string $moduleKey
|
|
|
* @param int $enabled
|
|
|
* @return bool
|
|
|
*/
|
|
|
- public static function updateModuleEnabled($mainId, $moduleKey, $enabled)
|
|
|
+ public static function updateModuleEnabled($mainId, $shopId, $moduleKey, $enabled)
|
|
|
{
|
|
|
$moduleKey = strval($moduleKey);
|
|
|
if (!in_array($moduleKey, self::DEFAULT_KEYS, true)) {
|
|
|
util::fail('无效配置项');
|
|
|
}
|
|
|
- $modules = self::getModules($mainId);
|
|
|
+ $modules = self::getModules($mainId, $shopId);
|
|
|
foreach ($modules as &$item) {
|
|
|
if (($item['key'] ?? '') === $moduleKey) {
|
|
|
$item['enabled'] = !empty($enabled) ? 1 : 0;
|
|
|
@@ -242,36 +256,41 @@ class HomePageConfigClass
|
|
|
}
|
|
|
}
|
|
|
unset($item);
|
|
|
- return self::saveModules($mainId, $modules);
|
|
|
+ return self::saveModules($mainId, $shopId, $modules);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 读取顶部导航与搜索配置,与默认值合并
|
|
|
- * 模块开关 enabled 以 modules Redis 为准,保证与门店首页配置列表同步
|
|
|
+ * 模块开关 enabled 以 modules 配置为准,保证与门店首页配置列表同步
|
|
|
*
|
|
|
* @param int $mainId
|
|
|
+ * @param int $shopId
|
|
|
* @return array
|
|
|
*/
|
|
|
- public static function getTopNav($mainId)
|
|
|
+ public static function getTopNav($mainId, $shopId)
|
|
|
{
|
|
|
$mainId = intval($mainId);
|
|
|
- if ($mainId <= 0) {
|
|
|
+ $shopId = intval($shopId);
|
|
|
+ if ($shopId <= 0) {
|
|
|
util::fail('无效门店');
|
|
|
}
|
|
|
|
|
|
$defaults = self::getDefaultTopNav();
|
|
|
- $raw = Yii::$app->redis->executeCommand('GET', [self::getTopNavKey($mainId)]);
|
|
|
- $saved = [];
|
|
|
- if (!empty($raw)) {
|
|
|
- $decoded = json_decode($raw, true);
|
|
|
- if (is_array($decoded)) {
|
|
|
- $saved = $decoded;
|
|
|
- }
|
|
|
+ $saved = HomePageModuleConfigClass::getConfigValue($shopId, 'topNav');
|
|
|
+ if ($saved === null) {
|
|
|
+ $saved = HomePageModuleConfigClass::migrateFromRedis(
|
|
|
+ $mainId,
|
|
|
+ $shopId,
|
|
|
+ 'topNav',
|
|
|
+ self::getTopNavKey($shopId),
|
|
|
+ self::getTopNavKey($mainId)
|
|
|
+ );
|
|
|
}
|
|
|
+ $saved = is_array($saved) ? $saved : [];
|
|
|
|
|
|
return [
|
|
|
// 开关以首页模块配置为准,不读 topNav 详情里的旧字段
|
|
|
- 'enabled' => self::getModuleEnabled($mainId, 'topNav'),
|
|
|
+ 'enabled' => self::getModuleEnabled($mainId, $shopId, 'topNav'),
|
|
|
'placeholder' => isset($saved['placeholder']) ? strval($saved['placeholder']) : $defaults['placeholder'],
|
|
|
'searchBtnColor' => isset($saved['searchBtnColor']) ? strval($saved['searchBtnColor']) : $defaults['searchBtnColor'],
|
|
|
'searchFontColor' => isset($saved['searchFontColor']) ? strval($saved['searchFontColor']) : $defaults['searchFontColor'],
|
|
|
@@ -282,55 +301,67 @@ class HomePageConfigClass
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 保存顶部导航与搜索配置(不含门店名称)
|
|
|
+ * 保存顶部导航与搜索配置(不含门店名称):落库 MySQL,并镜像写入 Redis
|
|
|
* 请求形态校验由 SaveTopNavForm 完成;$payload 为已规范化样式字段
|
|
|
*
|
|
|
* @param int $mainId
|
|
|
+ * @param int $shopId
|
|
|
* @param array $payload {placeholder,searchBtnColor,searchFontColor,customerServiceEnabled}
|
|
|
* @param int $enabled 模块开关
|
|
|
* @return bool
|
|
|
*/
|
|
|
- public static function saveTopNav($mainId, $payload, $enabled = 0)
|
|
|
+ public static function saveTopNav($mainId, $shopId, $payload, $enabled = 0)
|
|
|
{
|
|
|
$mainId = intval($mainId);
|
|
|
- if ($mainId <= 0) {
|
|
|
+ $shopId = intval($shopId);
|
|
|
+ if ($shopId <= 0) {
|
|
|
util::fail('无效门店');
|
|
|
}
|
|
|
if (!is_array($payload)) {
|
|
|
util::fail('参数错误');
|
|
|
}
|
|
|
|
|
|
- Yii::$app->redis->executeCommand('SET', [
|
|
|
- self::getTopNavKey($mainId),
|
|
|
- json_encode($payload, JSON_UNESCAPED_UNICODE),
|
|
|
- ]);
|
|
|
+ HomePageModuleConfigClass::saveConfigValue($mainId, $shopId, 'topNav', $payload);
|
|
|
+ try {
|
|
|
+ Yii::$app->redis->executeCommand('SET', [
|
|
|
+ self::getTopNavKey($shopId),
|
|
|
+ json_encode($payload, JSON_UNESCAPED_UNICODE),
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Yii::error('同步顶部导航配置到Redis失败: ' . $e->getMessage());
|
|
|
+ }
|
|
|
// 同步到门店首页配置列表的 topNav 开关
|
|
|
- self::updateModuleEnabled($mainId, 'topNav', $enabled);
|
|
|
+ self::updateModuleEnabled($mainId, $shopId, 'topNav', $enabled);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 读取首页轮播图配置;模块开关以 modules Redis 为准
|
|
|
+ * 读取首页轮播图配置;模块开关以 modules 配置为准
|
|
|
*
|
|
|
* @param int $mainId
|
|
|
+ * @param int $shopId
|
|
|
* @return array {enabled, interval, list:[{img,type,value}]}
|
|
|
*/
|
|
|
- public static function getBanner($mainId)
|
|
|
+ public static function getBanner($mainId, $shopId)
|
|
|
{
|
|
|
$mainId = intval($mainId);
|
|
|
- if ($mainId <= 0) {
|
|
|
+ $shopId = intval($shopId);
|
|
|
+ if ($shopId <= 0) {
|
|
|
util::fail('无效门店');
|
|
|
}
|
|
|
|
|
|
$defaults = self::getDefaultBanner();
|
|
|
- $raw = Yii::$app->redis->executeCommand('GET', [self::getBannerKey($mainId)]);
|
|
|
- $saved = [];
|
|
|
- if (!empty($raw)) {
|
|
|
- $decoded = json_decode($raw, true);
|
|
|
- if (is_array($decoded)) {
|
|
|
- $saved = $decoded;
|
|
|
- }
|
|
|
+ $saved = HomePageModuleConfigClass::getConfigValue($shopId, 'banner');
|
|
|
+ if ($saved === null) {
|
|
|
+ $saved = HomePageModuleConfigClass::migrateFromRedis(
|
|
|
+ $mainId,
|
|
|
+ $shopId,
|
|
|
+ 'banner',
|
|
|
+ self::getBannerKey($shopId),
|
|
|
+ self::getBannerKey($mainId)
|
|
|
+ );
|
|
|
}
|
|
|
+ $saved = is_array($saved) ? $saved : [];
|
|
|
|
|
|
$list = [];
|
|
|
if (!empty($saved['list']) && is_array($saved['list'])) {
|
|
|
@@ -364,25 +395,27 @@ class HomePageConfigClass
|
|
|
}
|
|
|
|
|
|
return [
|
|
|
- 'enabled' => self::getModuleEnabled($mainId, 'banner'),
|
|
|
+ 'enabled' => self::getModuleEnabled($mainId, $shopId, 'banner'),
|
|
|
'interval' => $interval,
|
|
|
'list' => $list,
|
|
|
];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 保存首页轮播图配置,并同步模块开关;会删除本次被移除的 OSS 图片
|
|
|
+ * 保存首页轮播图配置:落库 MySQL,镜像写入 Redis,并同步模块开关;会删除本次被移除的 OSS 图片
|
|
|
* 请求形态校验由 SaveBannerForm 完成;$payload 为已规范化 {interval,list}
|
|
|
*
|
|
|
* @param int $mainId
|
|
|
+ * @param int $shopId
|
|
|
* @param array $payload {interval, list:[{img,type,value}]}
|
|
|
* @param int $enabled 模块开关
|
|
|
* @return bool
|
|
|
*/
|
|
|
- public static function saveBanner($mainId, $payload, $enabled = 0)
|
|
|
+ public static function saveBanner($mainId, $shopId, $payload, $enabled = 0)
|
|
|
{
|
|
|
$mainId = intval($mainId);
|
|
|
- if ($mainId <= 0) {
|
|
|
+ $shopId = intval($shopId);
|
|
|
+ if ($shopId <= 0) {
|
|
|
util::fail('无效门店');
|
|
|
}
|
|
|
if (!is_array($payload)) {
|
|
|
@@ -393,7 +426,7 @@ class HomePageConfigClass
|
|
|
$list = isset($payload['list']) && is_array($payload['list']) ? $payload['list'] : [];
|
|
|
|
|
|
// 对比旧配置,删除本次不再使用的 OSS 图片
|
|
|
- $old = self::getBanner($mainId);
|
|
|
+ $old = self::getBanner($mainId, $shopId);
|
|
|
$oldImgs = [];
|
|
|
foreach ($old['list'] as $oldItem) {
|
|
|
if (!empty($oldItem['img'])) {
|
|
|
@@ -418,11 +451,16 @@ class HomePageConfigClass
|
|
|
'interval' => $interval,
|
|
|
'list' => $list,
|
|
|
];
|
|
|
- Yii::$app->redis->executeCommand('SET', [
|
|
|
- self::getBannerKey($mainId),
|
|
|
- json_encode($savePayload, JSON_UNESCAPED_UNICODE),
|
|
|
- ]);
|
|
|
- self::updateModuleEnabled($mainId, 'banner', $enabled);
|
|
|
+ HomePageModuleConfigClass::saveConfigValue($mainId, $shopId, 'banner', $savePayload);
|
|
|
+ try {
|
|
|
+ Yii::$app->redis->executeCommand('SET', [
|
|
|
+ self::getBannerKey($shopId),
|
|
|
+ json_encode($savePayload, JSON_UNESCAPED_UNICODE),
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Yii::error('同步首页轮播图配置到Redis失败: ' . $e->getMessage());
|
|
|
+ }
|
|
|
+ self::updateModuleEnabled($mainId, $shopId, 'banner', $enabled);
|
|
|
return true;
|
|
|
}
|
|
|
|