Files
lgp-admin-plus-api/app/Service/business/WxUserService.php

258 lines
8.2 KiB
PHP
Raw Normal View History

<?php
namespace App\Service\business;
use App\BaseApp\BaseService;
use App\Models\business\EnterpriseModel;
use App\Models\business\WxTemplateModel;
use App\Models\business\WxUserModel;
use App\Service\common\MediaUrlService;
use Exception;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
/**
* 微信用户管理
*
* 三件事认代理商is_p、给代理商设价格倍率price_number、把用户绑到企业
* 另可给经销商绑定专属装修模板template_code
* session_key 属于服务端凭据selectField 里绝不带上。
*/
class WxUserService extends BaseService
{
private MediaUrlService $media;
public function __construct()
{
parent::__construct();
$this->model = WxUserModel::class;
$this->selectField = [
'id', 'open_id', 'phone', 'nick_name', 'avatar',
'show_price', 'is_p', 'pid', 'enterprise_id', 'price_number', 'template_code',
'created_at', 'updated_at',
];
$this->queryField = [
'nick_name' => 'like',
'phone' => 'like',
'is_p' => '=',
'show_price' => '=',
'enterprise_id' => '=',
];
$this->media = MediaUrlService::getInstance();
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function list(): array
{
$this->with = ['enterprise'];
$result = $this->getPageList();
foreach ($result['items'] as &$item) {
$item['enterprise_name'] = $item['enterprise']['name'] ?? '';
unset($item['enterprise']);
$item['avatar'] = $this->media->toPublic($item['avatar'] ?? '');
}
unset($item);
return $result;
}
public function option(): mixed
{
$this->optionField = ['id', 'nick_name as name', 'phone'];
return $this->getOption();
}
/**
* 详情:带所属企业、上级代理商与下级数量
* @throws Exception
*/
public function detail($id): mixed
{
$this->with = ['enterprise'];
$info = $this->getDetail($id);
$info->avatar = $this->media->toPublic($info->avatar);
$info->enterprise_name = $info->enterprise->name ?? '';
$info->parent_name = $info->pid > 0
? (string) (WxUserModel::where('id', $info->pid)->value('nick_name') ?? '')
: '';
$info->child_count = WxUserModel::where('pid', $info->id)->where('deleted_at', 0)->count();
return $info;
}
/**
* 后台不创建微信用户(用户只能由小程序授权登录产生)
* @throws Exception
*/
public function create($params): mixed
{
return $this->utils->errorThrow('微信用户由小程序授权登录产生,后台不支持新建');
}
/**
* 后台只允许改这几项,避免把 open_id 之类的身份字段改花
* @throws Exception
*/
public function update($id, $params): mixed
{
$allowed = ['nick_name', 'phone', 'enterprise_id', 'show_price', 'price_number', 'is_p', 'template_code'];
$payload = array_intersect_key($params, array_flip($allowed));
if (empty($payload)) {
$this->utils->errorThrow('没有可更新的字段');
}
if (array_key_exists('price_number', $payload)) {
$payload['price_number'] = $this->normalizeMultiplier($payload['price_number']);
}
if (array_key_exists('template_code', $payload)) {
$payload['template_code'] = trim((string) $payload['template_code']);
}
return $this->save($id, $payload);
}
/**
* @throws Exception
*/
public function delete($id): mixed
{
return $this->del(is_array($id) ? $id : [$id]);
}
/**
* 切换代理商身份
*
* 老接口是「翻转」语义(不传目标值,后端读当前值取反),前端的开关点快了就会和后端打反。
* 这里改成显式传 is_p同时保留不传时的翻转以兼容老调用。
* @throws Exception
*/
public function updateUserIsP($id, mixed $isP = null): bool
{
$user = WxUserModel::where('id', $id)->where('deleted_at', 0)->first();
if (empty($user)) {
$this->utils->errorThrow('用户不存在');
}
$target = $isP === null || $isP === ''
? ((int) $user->is_p === 1 ? 0 : 1)
: (int) $isP;
// 认成代理商就默认可见价格、倍率归 1取消代理商则收回价格可见性并清空专属模板
$data = $target === 1
? ['is_p' => 1, 'show_price' => 1, 'price_number' => 1]
: ['is_p' => 0, 'show_price' => 0, 'price_number' => 1, 'template_code' => ''];
$data['updated_at'] = time();
WxUserModel::where('id', $id)->update($data);
return true;
}
/**
* 给经销商绑定专属装修模板(空字符串=跟随品牌默认)
* @throws Exception
*/
public function bindTemplate($id, mixed $templateCode): bool
{
$user = WxUserModel::where('id', $id)->where('deleted_at', 0)->first();
if (empty($user)) {
$this->utils->errorThrow('用户不存在');
}
if ((int) $user->is_p !== 1) {
$this->utils->errorThrow('仅经销商可绑定专属模板');
}
$code = trim((string) $templateCode);
if ($code !== '') {
$exists = WxTemplateModel::where('code', $code)
->where('deleted_at', 0)
->where('status', 0)
->exists();
if (!$exists) {
$this->utils->errorThrow('模板不存在或已停用');
}
}
WxUserModel::where('id', $id)->update([
'template_code' => $code,
'updated_at' => time(),
]);
return true;
}
/**
* 设置价格倍率(同时打开价格可见)
* @throws Exception
*/
public function updateShowPrice($id, mixed $number): bool
{
$user = WxUserModel::where('id', $id)->where('deleted_at', 0)->first();
if (empty($user)) {
$this->utils->errorThrow('用户不存在');
}
$multiplier = $this->normalizeMultiplier($number);
WxUserModel::where('id', $id)->update([
'show_price' => 1,
'price_number' => $multiplier,
'updated_at' => time(),
]);
return true;
}
/**
* 单独控制价格可见性(不动倍率)
* @throws Exception
*/
public function updateShowPriceStatus($id, mixed $showPrice): bool
{
$user = WxUserModel::where('id', $id)->where('deleted_at', 0)->first();
if (empty($user)) {
$this->utils->errorThrow('用户不存在');
}
WxUserModel::where('id', $id)->update([
'show_price' => (int) $showPrice === 1 ? 1 : 0,
'updated_at' => time(),
]);
return true;
}
/**
* 绑定企业
* @throws Exception
*/
public function bindUser($id, $enterpriseId): bool
{
$enterpriseId = (int) $enterpriseId;
if (!WxUserModel::where('id', $id)->where('deleted_at', 0)->exists()) {
$this->utils->errorThrow('用户不存在');
}
if ($enterpriseId > 0 && !EnterpriseModel::where('id', $enterpriseId)->where('deleted_at', 0)->exists()) {
$this->utils->errorThrow('企业不存在');
}
WxUserModel::where('id', $id)->update([
'enterprise_id' => $enterpriseId,
'updated_at' => time(),
]);
return true;
}
/**
* 该代理商名下的下级用户
*/
public function children(int $id): array
{
return WxUserModel::where('pid', $id)
->where('deleted_at', 0)
->orderBy('id', 'desc')
->get(['id', 'nick_name', 'phone', 'price_number', 'show_price', 'created_at'])
->toArray();
}
/**
* 倍率兜底0 或负数会把价格直接乘成 0
*/
private function normalizeMultiplier(mixed $number): string
{
if (!is_numeric($number) || (float) $number <= 0) {
return '1';
}
return (string) $number;
}
}