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; } }