初始化本地仓库

This commit is contained in:
2026-08-31 11:33:59 +08:00
commit 663f74b633
2390 changed files with 402918 additions and 0 deletions
@@ -0,0 +1,363 @@
<?php
declare(strict_types=1);
namespace app\service\api\member;
use app\api\CurrentMember;
use app\dao\member\MemberDao;
use app\dao\member\MemberThirdPartyDao;
use app\model\member\Member;
use app\model\member\MemberAddress;
use app\enum\common\EnabledStatus;
use core\base\BaseService;
use support\Container;
use support\Redis;
/**
* 会员用户服务
*/
class MemberService extends BaseService
{
/**
* 构造方法
*/
public function __construct(MemberDao $dao)
{
$this->dao = $dao;
}
/**
* 更新会员信息
*
* @throws \Exception
* @throws \Throwable
*/
public function updateInfo(array $data): void
{
$currentMember = Container::make(CurrentMember::class);
$id = $currentMember->id();
if (empty($id)) {
throw new \Exception('用户未登录', 401);
}
$model = $this->dao->get($id);
if (!$model) {
throw new \Exception('用户不存在', 401);
}
$allowedFields = ['nickname', 'avatar', 'gender', 'birthday','bio'];
$updateData = [];
foreach ($allowedFields as $field) {
if (isset($data[$field])) {
$updateData[$field] = $data[$field];
}
}
if (empty($updateData)) {
throw new \Exception('没有可更新的数据', 400);
}
$model->fill($updateData);
if (!$model->isDirty()) {
throw new \Exception('数据没有变化', 400);
}
$model->save();
}
/**
* 绑定会员手机号
*/
public function bindPhone(array $data): array
{
if (empty($data['phone']) || empty($data['verify_code'])) {
throw new \Exception('手机号和验证码不能为空', 400);
}
// 验证短信验证码
$this->verifySmsCode($data['phone'], $data['verify_code']);
$memberId = $this->getCurrentMemberId();
$member = Member::find($memberId);
if (!$member) {
throw new \Exception('用户不存在', 401);
}
// 检查手机号是否已被其他用户绑定
$existingMember = Member::where('phone', $data['phone'])
->where('id', '!=', $memberId)
->first();
if ($existingMember) {
throw new \Exception('手机号已被其他用户绑定', 400);
}
// 更新手机号
$member->phone = $data['phone'];
$member->save();
return [
'code' => 200,
'msg' => '绑定成功',
];
}
/**
* 修改密码
*
* @throws \Exception
*/
public function changePassword(array $data): void
{
if (empty($data['old_password']) || empty($data['new_password'])) {
throw new \Exception('旧密码和新密码不能为空', 400);
}
$currentMember = Container::make(CurrentMember::class);
$id = $currentMember->id();
if (empty($id)) {
throw new \Exception('用户未登录', 401);
}
$model = $this->dao->get($id);
if (!$model) {
throw new \Exception('用户不存在', 401);
}
if (!$model->verifyPassword($data['old_password'])) {
throw new \Exception('旧密码错误', 400);
}
$model->password = $data['new_password'];
$model->save();
}
/**
* 获取地址列表
*/
public function getAddressList(): array
{
$memberId = $this->getCurrentMemberId();
$addresses = MemberAddress::where('member_id', $memberId)
->where('enabled', EnabledStatus::ENABLED->value)
->orderBy('is_default', 'desc')
->orderBy('id', 'desc')
->get();
return $addresses->toArray();
}
/**
* 创建地址
*/
public function createAddress(array $data): array
{
if (empty($data['name']) || empty($data['phone']) || empty($data['province']) ||
empty($data['city']) || empty($data['district']) || empty($data['address'])) {
throw new \Exception('请填写完整的地址信息', 400);
}
$memberId = $this->getCurrentMemberId();
// 如果设置为默认地址,取消其他默认地址
if ($data['is_default'] ?? false) {
MemberAddress::where('member_id', $memberId)
->where('is_default', true)
->update(['is_default' => false]);
}
$addressData = [
'member_id' => $memberId,
'name' => $data['name'],
'phone' => $data['phone'],
'province' => $data['province'],
'city' => $data['city'],
'district' => $data['district'],
'address' => $data['address'],
'is_default' => $data['is_default'] ?? false,
'enabled' => EnabledStatus::ENABLED->value,
];
$address = MemberAddress::create($addressData);
return ['id' => $address->id];
}
/**
* 更新地址
*/
public function updateAddress(int $id, array $data): array
{
$memberId = $this->getCurrentMemberId();
$address = MemberAddress::where('id', $id)
->where('member_id', $memberId)
->first();
if (!$address) {
throw new \Exception('地址不存在', 404);
}
// 如果设置为默认地址,取消其他默认地址
if ($data['is_default'] ?? false) {
MemberAddress::where('member_id', $memberId)
->where('id', '!=', $id)
->where('is_default', true)
->update(['is_default' => false]);
}
// 允许更新的字段
$allowedFields = ['name', 'phone', 'province', 'city', 'district', 'address', 'is_default'];
$updateData = [];
foreach ($allowedFields as $field) {
if (isset($data[$field])) {
$updateData[$field] = $data[$field];
}
}
if (empty($updateData)) {
throw new \Exception('没有可更新的数据', 400);
}
$address->update($updateData);
return [];
}
/**
* 删除地址
*/
public function deleteAddress(int $id): array
{
$memberId = $this->getCurrentMemberId();
$address = MemberAddress::where('id', $id)
->where('member_id', $memberId)
->first();
if (!$address) {
throw new \Exception('地址不存在', 404);
}
// 软删除
$address->enabled = EnabledStatus::DISABLED->value;
$address->save();
return [];
}
/**
* 验证短信验证码
*/
private function verifySmsCode(string $mobile, string $code): void
{
$cacheKey = 'sms_code:' . $mobile;
$cachedCode = Redis::get($cacheKey);
if (!$cachedCode || $cachedCode !== $code) {
throw new \Exception('验证码错误或已过期', 400);
}
// 验证成功后删除验证码
Redis::del($cacheKey);
}
/**
* 获取当前用户ID
*/
private function getCurrentMemberId(): int
{
$request = \request();
$token = $request->header('Authorization');
if (!$token) {
throw new \Exception('未登录', 401);
}
$tokenData = Redis::get('user_token:' . md5($token));
if (!$tokenData) {
throw new \Exception('登录已过期', 401);
}
$data = json_decode($tokenData, true);
return $data['member_id'] ?? 0;
}
/**
* 上传头像
*/
public function uploadAvatar(\Webman\Http\UploadFile $file): array
{
$memberId = $this->getCurrentMemberId();
// 验证文件类型
$allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($file->getUploadMimeType(), $allowedTypes)) {
throw new \Exception('只支持jpg、png、gif、webp格式的图片', 400);
}
// 验证文件大小(最大2MB)
$maxSize = 2 * 1024 * 1024;
if ($file->getSize() > $maxSize) {
throw new \Exception('图片大小不能超过2MB', 400);
}
// 生成文件名
$extension = pathinfo($file->getUploadName(), PATHINFO_EXTENSION);
$filename = 'avatar_' . $memberId . '_' . time() . '.' . $extension;
// 保存文件
$uploadPath = public_path() . '/uploads/avatar/';
if (!is_dir($uploadPath)) {
mkdir($uploadPath, 0755, true);
}
$file->moveTo($uploadPath . $filename);
// 生成访问URL
$url = '/uploads/avatar/' . $filename;
// 更新会员头像
$member = Member::find($memberId);
if ($member) {
$member->avatar = $url;
$member->save();
}
return [
'url' => $url,
'filename' => $filename
];
}
/**
* 获取活跃用户
*/
public function getActiveUsers(int $limit = 10): array
{
$member = $this->dao->getActiveUsers($limit);
return $member->map(function ($item) {
return [
'id' => $item->id,
'username' => $item->username,
'nickname' => $item->nickname,
'avatar' => $item->avatar,
'intro' => $item->intro ?? "",
'last_active' => $item->last_time,
];
})->toArray();
}
/**
* 检查用户是否是管理员
* 暂时返回 false,只有问题作者可以设置最佳答案
*/
public function isAdmin(int|string $userId): bool
{
return false;
}
}