Files
huangjingfen/pro_v3.5.1_副本/app/services/activity/live/LiveGoodsServices.php

282 lines
10 KiB
PHP
Raw Normal View History

feat(fsgx): 完成全部24项开发任务 Phase1-7 Phase1 后端核心: - 新增 fsgx_v1.sql 迁移脚本(is_queue_goods/frozen_points/available_points/no_assess) - SystemConfigServices 返佣设置扩展(周期人数/分档比例/范围/时机) - StoreOrderCreateServices 周期循环佣金计算 - StoreOrderTakeServices 佣金发放后同步冻结积分 - StoreProductServices/StoreProduct 保存 is_queue_goods Phase2 后端接口: - GET /api/hjf/brokerage/progress 佣金周期进度 - GET /api/hjf/assets/overview 资产总览 - HjfPointsServices 每日 frozen_points 0.4‰ 释放定时任务 - PUT /adminapi/hjf/member/{uid}/no_assess 不考核接口 - GET /adminapi/hjf/points/release_log 积分日志接口 Phase3 前端清理: - hjfCustom.js 路由精简(仅保留 points/log) - hjfQueue.js/hjfMember.js API 清理/重定向至 CRMEB 原生接口 - pages.json 公排→推荐佣金/佣金记录/佣金规则 Phase4-5 前端改造: - queue/status.vue 推荐佣金进度页整体重写 - 商品详情/订单确认/支付结果页文案与逻辑改造 - 个人中心/资产页/引导页/规则页文案改造 - HjfQueueProgress/HjfRefundNotice/HjfAssetCard 组件改造 - 推广中心嵌入佣金进度摘要 - hjfMockData.js 全量更新(公排字段→佣金字段) Phase6 Admin 增强: - 用户列表新增 frozen_points/available_points 列及不考核操作按钮 - hjfPoints.js USE_MOCK=false 对接真实积分日志接口 Phase7 配置文档: - docs/fsgx-phase7-config-checklist.md 后台配置与全链路验收清单 Made-with: Cursor
2026-03-23 22:32:19 +08:00
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\services\activity\live;
use app\dao\activity\live\LiveGoodsDao;
use app\services\BaseServices;
use app\services\product\product\StoreProductServices;
use crmeb\exceptions\AdminException;
use crmeb\services\DownloadImageService;
use crmeb\services\wechat\MiniProgram;
use crmeb\services\wechat\OfficialAccount;
use think\annotation\Inject;
use think\facade\Log;
/**
* 直播商品
* Class LiveGoodsServices
* @package app\services\activity\live
* @mixin LiveGoodsDao
*/
class LiveGoodsServices extends BaseServices
{
/**
* @var LiveGoodsDao
*/
#[Inject]
protected LiveGoodsDao $dao;
/**
* 获取直播商品列表
* @param array $where 查询条件
* @return array
*/
public function getList(array $where)
{
[$page, $limit] = $this->getPageValue();
$where['is_del'] = 0;
$list = $this->dao->getList($where, '*', ['product'], $page, $limit);
$count = $this->dao->count($where);
return compact('count', 'list');
}
/**
* 创建直播商品(验证商品有效性)
* @param array $product_ids 商品ID数组
* @return array
* @throws AdminException
*/
public function create(array $product_ids)
{
/** @var StoreProductServices $product */
$productServices = app()->make(StoreProductServices::class);
$products = $productServices->getColumn([['id', 'IN', $product_ids], ['is_del', '=', 0], ['is_show', '=', 1]], 'id,image,store_name,price,price as cost_price,stock', 'id');
if (count($product_ids) != count($products)) {
throw new AdminException('已选商品中包括已下架或移入回收站商品');
}
$checkGoods = $this->dao->getCount([['product_id', 'IN', $product_ids], ['is_del', '=', 0], ['audit_status', '<>', 3]]);
if ($checkGoods > 0) {
throw new AdminException('其中有商品已经添加');
}
return array_merge($products);
}
/**
* @param array $data
* @return bool|mixed
* @throws \EasyWeChat\Core\Exceptions\InvalidArgumentException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add(array $goods_info)
{
$product_ids = array_column($goods_info, 'id');
$this->create($product_ids);
/** @var DownloadImageService $download */
$download = app()->make(DownloadImageService::class);
$dataAll = $data = [];
$time = time();
foreach ($goods_info as $product) {
$data = [
'product_id' => $product['id'],
'name' => substrUTf8($product['store_name'], 12, 'UTF-8', ''),
'cover_img' => $product['image'] ?? '',
'price_type' => 1,
'cost_price' => $product['cost_price'] ?? 0.00,
'price' => $product['price'] ?? 0.00,
'url' => 'pages/goods_details/index?id=' . $product['id'],
'sort' => $product['sort'] ?? 0,
'add_time' => $time
];
try {
$path = root_path() . 'public' . $download->thumb(true)->downloadImage($data['cover_img'])['path'];
$coverImgUrl = MiniProgram::temporaryUpload($path)['media_id'];
@unlink($path);
} catch (\Throwable $e) {
Log::error('添加直播商品图片错误,原因:' . $e->getMessage());
$coverImgUrl = $data['cover_img'];
}
$res = MiniProgram::addGoods($coverImgUrl, $data['name'], $data['price_type'], $data['url'], floatval($data['price']));
$data['goods_id'] = $res['goodsId'];
$data['audit_id'] = $res['auditId'];
$data['audit_status'] = 1;
$dataAll[] = $data;
}
if (!$goods = $this->dao->saveAll($dataAll)) {
throw new AdminException('添加商品失败');
}
return true;
}
/**
* 同步商品
* @return bool
* @throws \EasyWeChat\Core\Exceptions\InvalidArgumentException
*/
public function syncGoods()
{
$liveGoods = $this->dao->getColumn([['goods_id', '>', 0]], '*', 'id');
if ($liveGoods) {
foreach ($liveGoods as $good) {
$path = root_path() . 'public' . app()->make(DownloadImageService::class)->thumb(true)->downloadImage($good['cover_img'])['path'];
$materialInfo = MiniProgram::temporaryUpload($path);
$coverImgUrl = $materialInfo['media_id'];
@unlink($path);
$res = MiniProgram::addGoods($coverImgUrl, $good['name'], $good['price_type'], $good['url'], floatval($good['price']));
$data['goods_id'] = $res['goodsId'];
$data['audit_id'] = $res['auditId'];
$data['audit_status'] = 1;
if (!$this->dao->update($good['id'], $data, 'id')) {
throw new AdminException('同步失败');
}
}
}
return true;
}
/**
* 微信小程序创建直播商品
* @param mixed $goods 商品信息
* @return array
* @throws AdminException
*/
public function wxCreate($goods)
{
if ($goods['goods_id'])
throw new AdminException('商品已创建');
$goods = $goods->toArray();
$path = root_path() . 'public' . app()->make(DownloadImageService::class)->thumb(true)->downloadImage($goods['cover_img'])['path'];
$url = 'pages/goods_details/index?id=' . $goods['product_id'];
$coverImgUrl = MiniProgram::temporaryUpload($path)['media_id'];
@unlink($path);
return MiniProgram::addGoods($coverImgUrl, $goods['name'], 1, $url, floatval($goods['price']));
}
/**
* 设置直播商品显示状态
* @param int $id 商品ID
* @param int $is_show 显示状态
* @return string
* @throws AdminException
*/
public function isShow(int $id, $is_show)
{
$goods = $this->dao->get(['id' => $id, 'audit_status' => 2]);
if (!$goods) {
throw new AdminException('审核中或审核失败不允许此操作');
}
$this->dao->update($id, ['is_show' => $is_show]);
return $is_show == 1 ? '显示成功' : '隐藏成功';
}
/**
* 重新提交审核
* @param int $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function audit(int $id)
{
$goods = $this->dao->get($id);
if (!$goods) {
throw new AdminException('数据不存在');
}
if ($goods['audit_status'] != 0) {
throw new AdminException('在审核中或已经审核通过');
}
if (!$this->dao->update($id, ['audit_status' => 1])) {
throw new AdminException('修改审核状态失败');
}
return MiniProgram::auditGoods((int)$goods['good_id']);
}
/**
* 撤回审核
* @param int $id
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function resetAudit(int $id)
{
$goods = $this->dao->get($id);
if (!$goods) {
throw new AdminException('数据不存在');
}
if ($goods['audit_status'] == 0) {
return true;
}
if ($goods['audit_status'] != 1) {
throw new AdminException('审核通过或失败');
}
if (!$this->dao->update($id, ['audit_status' => 0])) {
throw new AdminException('修改审核状态失败');
}
return MiniProgram::resetauditGoods((int)$goods['good_id'], $goods['audit_id']);
}
/**
* 删除商品
* @param int $id
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function delete(int $id)
{
$goods = $this->dao->get(['id' => $id, 'is_del' => 0]);
if ($goods) {
if (in_array($goods['audit_status'], [0, 1])) {
throw new AdminException('商品审核中,无法删除');
}
if (!$this->dao->update($id, ['is_del' => 1])) {
throw new AdminException('删除失败');
}
if (MiniProgram::deleteGoods((int)$goods->goods_id)) {
/** @var LiveRoomGoodsServices $liveRoomGoods */
$liveRoomGoods = app()->make(LiveRoomGoodsServices::class);
$liveRoomGoods->delete(['live_goods_id' => $id]);
}
}
return true;
}
/**
* 同步直播商品审核状态
* @return bool
*/
public function syncGoodStatus()
{
$goodsIds = $this->dao->goodsStatusAll();
if (!count($goodsIds)) return true;
$res = MiniProgram::getGooodsInfo(array_keys($goodsIds));
foreach ($res as $item) {
if (isset($goodsIds[$item['goods_id']]) && $item['audit_status'] != $goodsIds[$item['goods_id']]) {
$data = ['audit_status' => $item['audit_status']];
// 同步商品审核状态
$this->dao->update((int)$goodsIds[$item['goods_id']]['id'], $data);
}
}
return true;
}
}