258 lines
8.2 KiB
PHP
258 lines
8.2 KiB
PHP
<?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;
|
||
}
|
||
}
|