123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870 |
- <?php
- namespace app\admin\controller\marketing;
- use app\common\controller\Backend;
- use think\Db;
- use Exception;
- use think\exception\DbException;
- use think\exception\PDOException;
- use think\exception\ValidateException;
- use app\common\Enum\ChannelEnum;
- use app\common\Enum\ActivityEnum;
- /**
- * 营销活动表(整体活动)
- *
- * @icon fa fa-circle-o
- */
- class Discount extends Backend
- {
- /**
- * Discount模型对象
- * @var \app\admin\model\marketing\discount\Discount
- */
- protected $model = null;
- public function _initialize()
- {
- parent::_initialize();
- $this->model = new \app\admin\model\marketing\discount\Discount;
- // 渠道配置
- $this->view->assign("channelList", ChannelEnum::getChannelMap());
- $this->assignconfig("channelList", json_encode(ChannelEnum::getChannelMap()));
- }
- /**
- * 规格折扣设置
- */
- public function spec_discount()
- {
- $goods_id = $this->request->get('goods_id');
- if (!$goods_id) {
- $this->error('参数错误');
- }
-
- if ($this->request->isAjax()) {
- // 处理提交的数据
- $specs = $this->request->post('specs', []);
- if ($specs) {
- $result = [
- 'goodsId' => $goods_id,
- 'specs' => $specs
- ];
- $this->success('设置成功', null, $result);
- }
- $this->error('提交数据失败');
- }
-
- // 获取商品信息
- $goods = Db::name('shop_goods')->where('id', $goods_id)->find();
- if (!$goods) {
- $this->error('商品不存在');
- }
-
- // 获取规格信息
- $goods_skus = Db::name('shop_goods_sku')
- ->where('goods_id', $goods_id)
- ->select();
-
- // 获取规格属性名称和值
- $sku_specs = [];
- foreach ($goods_skus as &$sku) {
- $sku_id_arr = explode(',', $sku['spec_value_ids']);
-
- // 查询规格名称和值
- $spec_values = Db::name('shop_goods_sku_spec')
- ->alias('p')
- ->field('p.*, sp.name as spec_name, sv.value as spec_value')
- ->join('shop_spec sp', 'sp.id=p.spec_id', 'LEFT')
- ->join('shop_spec_value sv', 'sv.id=p.spec_value_id', 'LEFT')
- ->where('p.id', 'in', $sku_id_arr)
- ->select();
-
- $specs_text = [];
- foreach ($spec_values as $spec) {
- $specs_text[] = $spec['spec_name'] . ':' . $spec['spec_value'];
- }
- $sku['specs_text'] = implode(' | ', $specs_text);
- }
-
- $this->view->assign('goods', $goods);
- $this->view->assign('skus', $goods_skus);
-
- return $this->view->fetch();
- }
- /**
- * 添加
- *
- * @return string
- * @throws \think\Exception
- */
- public function add()
- {
- if (false === $this->request->isPost()) {
- return $this->view->fetch();
- }
- $params = $this->request->post('row/a');
- if (empty($params)) {
- $this->error(__('Parameter %s can not be empty', ''));
- }
- $params = $this->preExcludeFields($params);
- if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
- $params[$this->dataLimitField] = $this->auth->id;
- }
-
- // 处理活动渠道
- if (isset($params['channels']) && is_array($params['channels'])) {
- $params['channels'] = json_encode($params['channels']);
- } else {
- $params['channels'] = json_encode([]);
- }
-
- // 处理商品ID和商品数量
- $goodsIds = isset($params['goods_ids']) ? $params['goods_ids'] : '';
- if ($goodsIds) {
- $goodsIdArr = explode(',', $goodsIds);
- $params['goods_count'] = count($goodsIdArr);
- // 存储为JSON格式
- $params['goods_ids'] = json_encode($goodsIdArr);
- } else {
- $params['goods_count'] = 0;
- $params['goods_ids'] = '[]';
- }
-
- // 设置默认字段值
- $params['type'] = isset($params['type']) ? $params['type'] : 'discount';
- $params['inner_type'] = isset($params['inner_type']) ? $params['inner_type'] : 0;
- // 对于折扣活动,强制设置为指定商品参与
- if ($params['type'] == 'discount') {
- $params['goods_join_type'] = 2; // 指定商品参与
- } else {
- $params['goods_join_type'] = isset($params['goods_join_type']) ? $params['goods_join_type'] : 0;
- }
-
- // 设置活动状态
- $now = time();
- $startTime = strtotime($params['start_time']);
- $endTime = strtotime($params['end_time']);
-
- if ($startTime > $now) {
- $params['activity_status'] = 0; // 未开始
- } elseif ($startTime <= $now && $endTime > $now) {
- $params['activity_status'] = 1; // 进行中
- } else {
- $params['activity_status'] = 2; // 已结束
- }
-
- // 检查是否与其他活动时间冲突(同一时间只能有一个进行中的活动)
- $this->checkActivityTimeConflict($startTime, $endTime);
-
- $result = false;
- Db::startTrans();
- try {
- // 是否采用模型验证
- if ($this->modelValidate) {
- $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
- $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
- $this->model->validateFailException()->validate($validate);
- }
-
- // 保存活动基本信息
- $result = $this->model->allowField(true)->save($params);
-
- // 处理折扣信息
- $discountId = $this->model->id;
-
- // 保存规格折扣数据
- if ($params['type'] == 'discount') {
- $result = $this->processActivityGoodsData($discountId, $params);
- if (!$result['success']) {
- throw new Exception($result['message']);
- }
- }
-
- Db::commit();
- } catch (ValidateException|PDOException|Exception $e) {
- Db::rollback();
- $this->error($e->getMessage());
- }
- if ($result === false) {
- $this->error(__('No rows were inserted'));
- }
- $this->success();
- }
- /**
- * 编辑
- *
- * @param $ids
- * @return string
- * @throws DbException
- * @throws \think\Exception
- */
- public function edit($ids = null)
- {
- $row = $this->model->get($ids);
- if (!$row) {
- $this->error(__('No Results were found'));
- }
- $adminIds = $this->getDataLimitAdminIds();
- if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) {
- $this->error(__('You have no permission'));
- }
- if (false === $this->request->isPost()) {
- // 解码JSON数据
- if ($row['channels']) {
- $row['channels'] = json_decode($row['channels'], true);
- }
- if ($row['goods_ids']) {
- $goodsIdArr = json_decode($row['goods_ids'], true);
- $row['goods_ids'] = implode(',', $goodsIdArr);
-
- // 获取商品数据,包含完整的SKU和规格信息
- $goodsData = [];
- if (!empty($goodsIdArr)) {
- // 查询商品基础数据
- $goodsResult = Db::name('shop_goods')
- ->where('id', 'in', $goodsIdArr)
- ->select();
- $goodsData = [];
- if ($goodsResult) {
- foreach ($goodsResult as $item) {
- $goodsData[] = is_array($item) ? $item : $item->toArray();
- }
- }
-
- // 一次性查询该活动的所有SKU折扣数据
- $activitySkus = Db::table('shop_activity_sku')
- ->where('activity_id', $ids)
- ->select();
-
- // 将活动SKU数据按照goods_id和sku_id进行索引
- $activitySkuMap = [];
- foreach ($activitySkus as $activitySku) {
- $key = $activitySku['goods_id'] . '_' . $activitySku['sku_id'];
- $activitySkuMap[$key] = $activitySku;
- }
-
- // 一次性查询所有商品的SKU信息
- $allSkusResult = Db::name('shop_goods_sku')
- ->where('goods_id', 'in', $goodsIdArr)
- ->order('is_default desc, id asc')
- ->select();
-
- // 转换SKU结果为数组并按商品ID分组
- $skusByGoods = [];
- foreach ($allSkusResult as $sku) {
- $skuArray = is_array($sku) ? $sku : $sku->toArray();
- $skusByGoods[$skuArray['goods_id']][] = $skuArray;
- }
-
- // 找出多规格商品ID
- $multiSpecGoodsIds = [];
- foreach ($goodsData as $item) {
- if ($item['spec_type'] == 1) {
- $multiSpecGoodsIds[] = $item['id'];
- }
- }
-
- // 一次性查询所有多规格商品的规格信息
- $specsByGoods = [];
- if (!empty($multiSpecGoodsIds)) {
- $allSpecsResult = Db::name('shop_goods_sku_spec')
- ->alias('gss')
- ->field('gss.goods_id, sp.id as spec_id, sp.name as spec_name, sp.type as spec_type, sv.id as spec_value_id, sv.value, sv.image, sv.desc')
- ->join('shop_spec sp', 'sp.id = gss.spec_id', 'LEFT')
- ->join('shop_spec_value sv', 'sv.id = gss.spec_value_id', 'LEFT')
- ->where('gss.goods_id', 'in', $multiSpecGoodsIds)
- ->order('gss.goods_id asc, sp.id asc, sv.id asc')
- ->select();
-
- // 按商品ID分组规格数据
- foreach ($allSpecsResult as $spec) {
- $specArray = is_array($spec) ? $spec : $spec->toArray();
- $specsByGoods[$specArray['goods_id']][] = $specArray;
- }
- }
-
- // 一次性查询所有SKU的规格属性文本
- $allSkuIds = [];
- foreach ($skusByGoods as $skus) {
- foreach ($skus as $sku) {
- $allSkuIds[] = $sku['id'];
- }
- }
-
- $skuSpecTexts = [];
- if (!empty($allSkuIds)) {
- $skuSpecResults = Db::name('shop_goods_sku')
- ->alias('sku')
- ->field('sku.id, GROUP_CONCAT(sp.name,":",sv.value ORDER BY sp.id asc) as specs_text')
- ->join('shop_goods_sku_spec gss', "FIND_IN_SET(gss.id, sku.spec_value_ids)", 'LEFT')
- ->join('shop_spec sp', 'sp.id = gss.spec_id', 'LEFT')
- ->join('shop_spec_value sv', 'sv.id = gss.spec_value_id', 'LEFT')
- ->where('sku.id', 'in', $allSkuIds)
- ->group('sku.id')
- ->select();
-
- foreach ($skuSpecResults as $result) {
- $resultArray = is_array($result) ? $result : $result->toArray();
- $skuSpecTexts[$resultArray['id']] = $resultArray['specs_text'] ?: '';
- }
- }
-
- // 为每个商品添加完整的SKU和规格信息(纯数据组装,无数据库查询)
- foreach ($goodsData as &$item) {
- if ($item['image']) {
- $item['image'] = cdnurl($item['image'], true);
- }
-
- // 获取商品的SKU信息
- $skus = $skusByGoods[$item['id']] ?? [];
-
- if ($skus) {
- // 获取第一个SKU ID(单规格商品通常只有一个SKU)
- $item['sku_id'] = $skus[0]['id'];
-
- // 为每个SKU添加规格属性文本和活动折扣信息
- foreach ($skus as &$sku) {
- $sku['specs_text'] = $skuSpecTexts[$sku['id']] ?? '';
-
- // 查找该SKU是否有活动折扣数据
- $activityKey = $item['id'] . '_' . $sku['id'];
- if (isset($activitySkuMap[$activityKey])) {
- $activitySku = $activitySkuMap[$activityKey];
- $sku['activity_discount'] = $activitySku['discount'];
- $sku['activity_discount_price'] = $activitySku['discount_price'];
- $sku['activity_stocks'] = $activitySku['stocks'];
- }
- }
- $item['skus'] = $skus;
-
- // 如果是多规格商品,添加规格数据
- if ($item['spec_type'] == 1) {
- $specs = $specsByGoods[$item['id']] ?? [];
-
- // 按规格分组构建规格数据结构
- $spec_groups = [];
- foreach ($specs as $spec) {
- if (!isset($spec_groups[$spec['spec_id']])) {
- $spec_groups[$spec['spec_id']]['id'] = $spec['spec_id'];
- $spec_groups[$spec['spec_id']]['name'] = $spec['spec_name'];
- $spec_groups[$spec['spec_id']]['type'] = $spec['spec_type'] == 2 ? 'custom' : 'basic';
- $spec_groups[$spec['spec_id']]['value'] = [];
- }
- $spec_groups[$spec['spec_id']]['value'][] = [
- 'id' => $spec['spec_value_id'],
- 'name' => $spec['value'],
- 'image' => $spec['image'] ?: '',
- 'description' => $spec['desc'] ?: ''
- ];
- }
-
- // 转换为数组格式,与前端渲染一致
- $item['spec'] = array_values($spec_groups);
-
- // 构建已选择的规格折扣数据(用于前端回显)
- $selectedSpecs = [];
- $summary = [
- 'participate_count' => 0,
- 'avg_discount' => 0,
- 'total_stocks' => 0
- ];
- $totalDiscount = 0;
-
- foreach ($skus as $sku) {
- $activityKey = $item['id'] . '_' . $sku['id'];
- if (isset($activitySkuMap[$activityKey])) {
- $activitySku = $activitySkuMap[$activityKey];
- $selectedSpecs[] = [
- 'sku_id' => $sku['id'],
- 'discount' => $activitySku['discount'],
- 'discount_price' => $activitySku['discount_price'],
- 'discount_stocks' => $activitySku['stocks']
- ];
-
- $summary['participate_count']++;
- $totalDiscount += floatval($activitySku['discount']);
- $summary['total_stocks'] += intval($activitySku['stocks']);
- }
- }
-
- if ($summary['participate_count'] > 0) {
- $summary['avg_discount'] = round($totalDiscount / $summary['participate_count'], 1);
-
- // 为前端JavaScript提供已选择的规格数据
- $item['selected_discount_data'] = [
- 'goodsId' => $item['id'],
- 'spec' => $selectedSpecs,
- 'summary' => $summary
- ];
- }
- } else {
- // 单规格商品,没有spec数据
- $item['spec'] = [];
- }
- } else {
- $item['sku_id'] = 0;
- $item['skus'] = [];
- $item['spec'] = [];
- }
- }
- }
- $this->view->assign('goodsData', $goodsData);
- $this->assignconfig('goodsData', $goodsData);
- }
-
- $this->view->assign('row', $row);
- return $this->view->fetch();
- }
- $params = $this->request->post('row/a');
- if (empty($params)) {
- $this->error(__('Parameter %s can not be empty', ''));
- }
- $params = $this->preExcludeFields($params);
-
- // 处理活动渠道
- if (isset($params['channels']) && is_array($params['channels'])) {
- $params['channels'] = json_encode($params['channels']);
- } else {
- $params['channels'] = json_encode([]);
- }
-
- // 处理商品ID和商品数量
- $goodsIds = isset($params['goods_ids']) ? $params['goods_ids'] : '';
- if ($goodsIds) {
- $goodsIdArr = explode(',', $goodsIds);
- $params['goods_count'] = count($goodsIdArr);
- $params['goods_ids'] = json_encode($goodsIdArr);
- } else {
- $params['goods_count'] = 0;
- $params['goods_ids'] = '[]';
- }
-
- // // 对于折扣活动,强制设置为指定商品参与
- // if ($params['type'] == 'discount') {
- // $params['goods_join_type'] = 2;
- // }
-
- // 设置活动状态
- $now = time();
- $startTime = strtotime($params['start_time']);
- $endTime = strtotime($params['end_time']);
-
- if ($startTime > $now) {
- $params['activity_status'] = 0; // 未开始
- } elseif ($startTime <= $now && $endTime > $now) {
- $params['activity_status'] = 1; // 进行中
- } else {
- $params['activity_status'] = 2; // 已结束
- }
-
- // 检查是否与其他活动时间冲突(同一时间只能有一个进行中的活动)
- $this->checkActivityTimeConflict($startTime, $endTime, $ids);
-
- $result = false;
- Db::startTrans();
- try {
- //是否采用模型验证
- if ($this->modelValidate) {
- $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
- $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
- $row->validateFailException()->validate($validate);
- }
-
- $result = $row->allowField(true)->save($params);
-
- // 处理折扣数据
- // if ($params['type'] == 'discount') {
- // 编辑逻辑:智能处理增删改
- $result = $this->processActivityGoodsDataForEdit($ids, $params);
- if (!$result['success']) {
- throw new Exception($result['message']);
- }
- // }
-
- Db::commit();
- } catch (ValidateException|PDOException|Exception $e) {
- Db::rollback();
- $this->error($e->getMessage());
- }
- if (false === $result) {
- $this->error(__('No rows were updated'));
- }
- $this->success();
- }
- /**
- * 手动停止活动
- */
- public function stopActivity()
- {
- $id = $this->request->post('id');
- $activity = $this->model->find($id);
-
- if (!$activity) {
- $this->error('活动不存在');
- }
-
- if ($activity['activity_status'] != 1) {
- $this->error('只有进行中的活动才能手动停止');
- }
-
- // 设置停止时间和状态
- $activity->stop_time = date('Y-m-d H:i:s');
- $activity->activity_status = 3; // 手动停止
-
- if ($activity->save()) {
- $this->success('活动已手动停止');
- } else {
- $this->error('操作失败');
- }
- }
-
- /**
- * 处理活动商品数据
- * @param int $activityId 活动ID
- * @param array $params 参数数组
- * @return array
- */
- private function processActivityGoodsData($activityId, $params)
- {
- try {
- // 处理商品信息数组
- $goodsInfo = isset($params['goods_info']) ? json_decode($params['goods_info'], true) : [];
-
- if (empty($goodsInfo)) {
- return ['success' => false, 'message' => '商品信息不能为空'];
- }
-
- \think\Log::write('处理商品信息数组: ' . json_encode($goodsInfo), 'debug');
-
- $specsData = [];
-
- foreach ($goodsInfo as $goodsItem) {
- if (!isset($goodsItem['goods_id'])) {
- continue;
- }
-
- $goodsId = $goodsItem['goods_id'];
-
- // 查询商品信息
- $goods = Db::name('shop_goods')->where('id', $goodsId)->find();
- if (!$goods) {
- continue;
- }
-
- if ($goodsItem['spec_type'] == 0) {
- // 单规格商品处理
- if (!isset($goodsItem['discount_price']) || !isset($goodsItem['discount_stocks'])) {
- continue;
- }
-
- // 获取单规格商品的实际SKU ID
- $skuId = isset($goodsItem['sku_id']) ? $goodsItem['sku_id'] : 0;
- if ($skuId == 0) {
- // 如果没有传SKU ID,查询商品的第一个SKU
- $sku = Db::name('shop_goods_sku')->where('goods_id', $goodsId)->find();
- $skuId = $sku ? $sku['id'] : 0;
- }
-
- $specsData[] = [
- 'activity_id' => $activityId,
- 'goods_id' => $goodsId,
- 'sku_id' => $skuId,
- 'discount' => $goodsItem['discount'] ?: round($goodsItem['discount_price'] * 10 / $goods['price'], 1),
- 'discount_price' => $goodsItem['discount_price'],
- 'stocks' => $goodsItem['discount_stocks'],
- 'createtime' => time(),
- 'updatetime' => time(),
- ];
-
- } else if ($goodsItem['spec_type'] == 1 && isset($goodsItem['spec'])) {
- // 多规格商品处理
- foreach ($goodsItem['spec'] as $spec) {
- if (!isset($spec['sku_id']) || !isset($spec['discount_price']) || !isset($spec['discount_stocks'])) {
- continue;
- }
-
- // 查询规格原始价格
- $skuInfo = Db::name('shop_goods_sku')
- ->where(['id' => $spec['sku_id']])
- ->find();
-
- if ($skuInfo) {
- $specsData[] = [
- 'activity_id' => $activityId,
- 'goods_id' => $goodsId,
- 'sku_id' => $spec['sku_id'],
- 'discount' => $spec['discount'] ?: round($spec['discount_price'] * 10 / $skuInfo['price'], 1),
- 'discount_price' => $spec['discount_price'],
- 'stocks' => $spec['discount_stocks'],
- 'createtime' => time(),
- 'updatetime' => time(),
- ];
- }
- }
- }
- }
-
- // 批量插入规格折扣数据
- if (!empty($specsData)) {
- Db::table('shop_activity_sku')->insertAll($specsData);
- \think\Log::write('成功插入' . count($specsData) . '条活动SKU数据', 'debug');
- }
-
- return ['success' => true, 'message' => '处理成功'];
-
- } catch (Exception $e) {
- \think\Log::write('处理活动商品数据失败: ' . $e->getMessage(), 'error');
- return ['success' => false, 'message' => '处理活动商品数据失败: ' . $e->getMessage()];
- }
- }
- /**
- * 编辑活动时处理商品数据 - 智能增删改逻辑
- * @param int $activityId 活动ID
- * @param array $params 提交的参数
- * @return array
- */
- private function processActivityGoodsDataForEdit($activityId, $params)
- {
- try {
- \think\Log::write('开始处理编辑活动商品数据,活动ID: ' . $activityId, 'debug');
-
- // 1. 解析新的商品信息
- $newGoodsInfo = json_decode($params['goods_info'], true);
- if (!$newGoodsInfo || !is_array($newGoodsInfo)) {
- return ['success' => true, 'message' => '没有商品数据需要处理'];
- }
-
- // 2. 查询当前活动的所有现有SKU记录
- $existingSkus = Db::table('shop_activity_sku')
- ->where('activity_id', $activityId)
- ->select();
-
- // 构建现有SKU的索引 (goods_id_sku_id => record)
- $existingSkuMap = [];
- foreach ($existingSkus as $sku) {
- $key = $sku['goods_id'] . '_' . $sku['sku_id'];
- $existingSkuMap[$key] = $sku;
- }
-
- // 3. 构建新提交的SKU数据
- $newSkuMap = [];
- $newSkuData = [];
-
- foreach ($newGoodsInfo as $goodsInfo) {
- $goodsId = $goodsInfo['goods_id'];
-
- if ($goodsInfo['spec_type'] == 0) {
- // 单规格商品
- $skuId = isset($goodsInfo['sku_id']) && $goodsInfo['sku_id'] > 0 ? $goodsInfo['sku_id'] : 0;
- $key = $goodsId . '_' . $skuId;
-
- $newSkuMap[$key] = true;
- $newSkuData[$key] = [
- 'activity_id' => $activityId,
- 'goods_id' => $goodsId,
- 'sku_id' => $skuId,
- 'discount' => floatval($goodsInfo['discount']),
- 'discount_price' => floatval($goodsInfo['discount_price']),
- 'stocks' => intval($goodsInfo['discount_stocks']),
- 'createtime' => time(),
- 'updatetime' => time(),
- ];
-
- } elseif ($goodsInfo['spec_type'] == 1 && isset($goodsInfo['spec']) && is_array($goodsInfo['spec'])) {
- // 多规格商品
- foreach ($goodsInfo['spec'] as $spec) {
- $skuId = intval($spec['sku_id']);
- $key = $goodsId . '_' . $skuId;
-
- $newSkuMap[$key] = true;
- $newSkuData[$key] = [
- 'activity_id' => $activityId,
- 'goods_id' => $goodsId,
- 'sku_id' => $skuId,
- 'discount' => floatval($spec['discount']),
- 'discount_price' => floatval($spec['discount_price']),
- 'stocks' => intval($spec['discount_stocks']),
- 'createtime' => time(),
- 'updatetime' => time(),
- ];
- }
- }
- }
-
- // 4. 分析需要删除、修改、新增的记录
- $toDelete = []; // 需要删除的记录ID
- $toUpdate = []; // 需要更新的记录
- $toInsert = []; // 需要新增的记录
-
- // 找出需要删除的记录(存在于旧数据但不存在于新数据)
- foreach ($existingSkuMap as $key => $existingRecord) {
- if (!isset($newSkuMap[$key])) {
- $toDelete[] = $existingRecord['id'];
- }
- }
-
- // 找出需要更新和新增的记录
- foreach ($newSkuData as $key => $newRecord) {
- if (isset($existingSkuMap[$key])) {
- // 存在相同的goods_id + sku_id,需要更新
- $existingRecord = $existingSkuMap[$key];
-
- // 检查是否有数据变化
- $hasChanges =
- $existingRecord['discount'] != $newRecord['discount'] ||
- $existingRecord['discount_price'] != $newRecord['discount_price'] ||
- $existingRecord['stocks'] != $newRecord['stocks'];
-
- if ($hasChanges) {
- $toUpdate[] = [
- 'id' => $existingRecord['id'],
- 'data' => [
- 'discount' => $newRecord['discount'],
- 'discount_price' => $newRecord['discount_price'],
- 'stocks' => $newRecord['stocks'],
- 'updatetime' => time(),
- ]
- ];
- }
- } else {
- // 不存在,需要新增
- $toInsert[] = $newRecord;
- }
- }
-
- // 5. 执行数据库操作
- $deleteCount = 0;
- $updateCount = 0;
- $insertCount = 0;
-
- // 删除操作
- if (!empty($toDelete)) {
- $deleteCount = Db::table('shop_activity_sku')
- ->where('id', 'in', $toDelete)
- ->delete();
- \think\Log::write('删除了 ' . $deleteCount . ' 条活动SKU记录', 'debug');
- }
-
- // 更新操作
- foreach ($toUpdate as $updateItem) {
- $updated = Db::table('shop_activity_sku')
- ->where('id', $updateItem['id'])
- ->update($updateItem['data']);
- if ($updated) {
- $updateCount++;
- }
- }
- if ($updateCount > 0) {
- \think\Log::write('更新了 ' . $updateCount . ' 条活动SKU记录', 'debug');
- }
-
- // 新增操作
- if (!empty($toInsert)) {
- Db::table('shop_activity_sku')->insertAll($toInsert);
- $insertCount = count($toInsert);
- \think\Log::write('新增了 ' . $insertCount . ' 条活动SKU记录', 'debug');
- }
-
- $message = "编辑完成:删除 {$deleteCount} 条,更新 {$updateCount} 条,新增 {$insertCount} 条记录";
- \think\Log::write($message, 'debug');
-
- return ['success' => true, 'message' => $message];
-
- } catch (Exception $e) {
- \think\Log::write('处理编辑活动商品数据失败: ' . $e->getMessage(), 'error');
- return ['success' => false, 'message' => '处理编辑活动商品数据失败: ' . $e->getMessage()];
- }
- }
- /**
- * 检查活动时间冲突
- * @param int $startTime 开始时间戳
- * @param int $endTime 结束时间戳
- * @param int|null $excludeId 排除的活动ID(编辑时使用)
- * @throws Exception
- */
- private function checkActivityTimeConflict($startTime, $endTime, $excludeId = null)
- {
- // 构建查询条件
- $where = [
- 'status' => 1, // 启用状态
- 'type' => 'discount', // 折扣活动
- ];
-
- // 编辑时排除当前活动
- if ($excludeId) {
- $where['id'] = ['neq', $excludeId];
- }
-
- // 查询可能冲突的活动
- $conflictActivities = Db::table('shop_activity')
- ->where($where)
- ->where(function($query) use ($startTime, $endTime) {
- // 检查时间重叠的情况:
- // 1. 新活动开始时间在现有活动期间内
- // 2. 新活动结束时间在现有活动期间内
- // 3. 新活动完全包含现有活动
- // 4. 现有活动完全包含新活动
- $query->where(function($q) use ($startTime, $endTime) {
- // 新活动开始时间在现有活动期间内
- $q->where('start_time', '<=', $startTime)
- ->where('end_time', '>', $startTime);
- })->whereOr(function($q) use ($startTime, $endTime) {
- // 新活动结束时间在现有活动期间内
- $q->where('start_time', '<', $endTime)
- ->where('end_time', '>=', $endTime);
- })->whereOr(function($q) use ($startTime, $endTime) {
- // 新活动完全包含现有活动
- $q->where('start_time', '>=', $startTime)
- ->where('end_time', '<=', $endTime);
- })->whereOr(function($q) use ($startTime, $endTime) {
- // 现有活动完全包含新活动
- $q->where('start_time', '<=', $startTime)
- ->where('end_time', '>=', $endTime);
- });
- })
- ->where('activity_status', ActivityEnum::ACTIVITY_STATUS_ONGOING)
- ->field('id, name, start_time, end_time, activity_status')
- ->select();
-
- if (!empty($conflictActivities)) {
- $conflictMessages = [];
- foreach ($conflictActivities as $activity) {
- $startTimeStr = date('Y-m-d H:i:s', $activity['start_time']);
- $endTimeStr = date('Y-m-d H:i:s', $activity['end_time']);
- $statusText = $this->getActivityStatusText($activity['activity_status']);
-
- $conflictMessages[] = "活动「{$activity['name']}」({$statusText}) 时间:{$startTimeStr} ~ {$endTimeStr}";
- }
-
- $errorMessage = "同一时间只能有一个折扣活动,以下活动与新活动时间冲突:\n" . implode("\n", $conflictMessages);
- $this->error($errorMessage);
- }
- }
- /**
- * 获取活动状态文本
- * @param int $status
- * @return string
- */
- private function getActivityStatusText($status)
- {
- $statusMap = [
- 0 => '未开始',
- 1 => '进行中',
- 2 => '已结束',
- 3 => '手动停止'
- ];
-
- return $statusMap[$status] ?? '未知状态';
- }
- }
|