Files
lgp-admin-plus-api/app/Service/business/WxUserService.php
LQ bcf54c2727 初始化
缺陷:主题配色需要优化整体的同风格
2026-08-14 23:21:21 +08:00

258 lines
8.2 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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;
}
}