初始化项目

This commit is contained in:
2026-09-01 22:15:50 +08:00
commit b5a26a8848
11217 changed files with 1710987 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use cores\exception\BaseException;
use app\common\model\Article as ArticleModel;
/**
* 商品评价模型
* Class Article
* @package app\api\model
*/
class Article extends ArticleModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'is_delete',
'store_id',
'create_time',
'update_time'
];
/**
* 获取器:文章详情HTML实体转换回普通字符
* @param $value
* @return string
*/
public function getArticleContentAttr($value)
{
return htmlspecialchars_decode($value);
}
/**
* 获取文章详情并累计阅读次数
* @param int $articleId 文章ID
* @return static|null
* @throws BaseException
*/
public static function getDetail(int $articleId)
{
// 获取文章详情
$detail = parent::detail($articleId, ['image']);
if (empty($detail) || $detail['is_delete']) {
throwError('很抱歉,当前文章不存在');
}
// 累积文章实际阅读数
static::setIncActualViews($articleId);
return $detail;
}
/**
* 累积文章实际阅读数
* @param int $articleId 文章ID
* @param int $num 递增的数量
* @return mixed
*/
private static function setIncActualViews(int $articleId, int $num = 1)
{
return (new static)->setInc($articleId, 'actual_views', $num);
}
/**
* 获取文章列表
* @param int $categoryId
* @param int $limit
* @return \think\Paginator
* @throws \think\db\exception\DbException
*/
public function getList(int $categoryId = 0, int $limit = 15)
{
// 检索查询条件
$filter = [];
$categoryId > 0 && $filter[] = ['category_id', '=', $categoryId];
// 获取列表数据
return $this->withoutField(['content'])
->with(['image', 'category'])
->where($filter)
->where('status', '=', 1)
->where('is_delete', '=', 0)
->order(['sort' => 'asc', 'create_time' => 'desc'])
->paginate($limit);
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Card as CardModel;
/**
* 兑换卡模型
* Class Card
* @package app\api\model
*/
class Card extends CardModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
}
+167
View File
@@ -0,0 +1,167 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\model\Goods as GoodsModel;
use app\api\model\GoodsSku as GoodsSkuModel;
use app\api\service\User as UserService;
use app\common\model\Cart as CartModel;
use app\common\enum\goods\Status as GoodsStatusEnum;
use app\common\exception\BaseException;
/**
* 购物车管理
* Class Cart
* @package app\api\model
*/
class Cart extends CartModel
{
/**
* 加入购物车
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品sku唯一标识
* @param int $goodsNum 商品数量
* @return bool
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add(int $goodsId, string $goodsSkuId, int $goodsNum)
{
// 判断是否已存在购物车记录
$detail = $this->getInfo($goodsId, $goodsSkuId, false);
// 如果已存在购物车记录, 则累计商品数量
// !empty($detail) && $goodsNum += $detail['goods_num'];
$goodsNum = 1;
// 验证商品的状态
$this->checkGoodsStatus($goodsId, $goodsSkuId, $goodsNum);
// 获取当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 实例化模型
$model = $detail ?: (new static);
return $model->save([
'goods_id' => $goodsId,
'goods_sku_id' => $goodsSkuId,
'goods_num' => $goodsNum,
'user_id' => $userId,
'store_id' => self::$storeId,
]);
}
/**
* 更新购物车记录
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品sku唯一标识
* @param int $goodsNum 商品数量
* @return bool
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function sUpdate(int $goodsId, string $goodsSkuId, int $goodsNum)
{
// 验证商品的状态
$this->checkGoodsStatus($goodsId, $goodsSkuId, $goodsNum);
// 获取购物车记录
$model = $this->getInfo($goodsId, $goodsSkuId, true);
// 更新记录
return $model->save(['goods_num' => $goodsNum]);
}
/**
* 验证商品的状态
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品sku唯一标识
* @param int $goodsNum 商品数量
* @return bool
* @throws BaseException
*/
private function checkGoodsStatus(int $goodsId, string $goodsSkuId, int $goodsNum)
{
// 获取商品详情
$goods = GoodsModel::detail($goodsId);
// 商品不存在
if (empty($goods) || $goods['is_delete']) {
throwError('很抱歉, 商品信息不存在');
}
// 商品已下架
if ($goods['status'] == GoodsStatusEnum::OFF_SALE) {
throwError('很抱歉, 该商品已经下架');
}
// 获取SKU信息
$skuInfo = GoodsSkuModel::detail($goodsId, $goodsSkuId);
if ($skuInfo['stock_num'] < $goodsNum) {
throwError('很抱歉, 该商品库存数量不足');
}
return true;
}
/**
* 获取购物车记录
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品sku唯一标识
* @param bool $isForce
* @return static|bool
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getInfo(int $goodsId, string $goodsSkuId, bool $isForce = true)
{
// 获取当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 获取购物车记录
$model = static::detail($userId, $goodsId, $goodsSkuId);
if (empty($model)) {
$isForce && throwError('购物车中没有该记录');
return false;
}
return $model;
}
/**
* 删除购物车中指定记录
* @param array $cartIds 购物车ID集, 如果为空删除所有
* @return bool
* @throws BaseException
*/
public function clear(array $cartIds = [])
{
// 获取当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 设置更新条件
$where = [['user_id', '=', $userId]];
// 购物车ID集
!empty($cartIds) && $where[] = ['id', 'in', $cartIds];
// 更新记录
return $this->updateBase(['is_delete' => 1], $where);
}
/**
* 获取当前用户购物车商品总数量
* @return float
* @throws BaseException
*/
public function getCartTotal()
{
if (!UserService::isLogin()) return 0;
$userId = UserService::getCurrentLoginUserId();
return $this->where('user_id', '=', $userId)
->where('is_delete', '=', 0)
->sum('goods_num');
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Category as CategoryModel;
/**
* 商品分类模型
* Class Category
* @package app\common\model
*/
class Category extends CategoryModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
'update_time'
];
/**
* 获取列表记录
* @param array $param
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getListPublic(array $param = []): array
{
return parent::getList(array_merge($param, ['status' => 1]));
}
}
+489
View File
@@ -0,0 +1,489 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Code as CodeModel;
use app\api\model\Order as OrderModel;
use app\common\library\helper;
use cores\exception\BaseException;
use think\facade\Cache;
use think\Request;
/**
* 订单模型
* Class Order
* @package app\api\model
*/
class Code extends CodeModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
// 信息提示
private $message = '';
/**
* 等待支付产码列表
* @param $zone
* @return array
* @throws \think\exception\DbException
*/
public function getList($zone=1)
{
// 获取数据列表->where(" code_id in (select code_id from yoshop_order where order_status = 10) ")
return $this->where('status', '=', 2)
->where('order_id', '=', 0)
->where('zone', '=', $zone)
->order(['allot_time' => 'asc'])
->select()
->toArray();
}
/**
* 等待支付产码列表
* @param $page
* @return array
* @throws \think\exception\DbException
*/
/*public function getList($page=1)
{
// 获取数据列表
return $this->where('status', '=', 2)
->where('order_id', '=', 0)
->where(" code_id in (select code_id from yoshop_order where order_status = 10) ")
->order(['allot_time' => 'asc'])
->page($page, 20)
->select()
->toArray();
}*/
/**
* 等待支付产码列表倒序
* @param $page
* @return array
* @throws \think\exception\DbException
*/
public function getListDesc($page=1)
{
// 获取数据列表
return $this->where('status', '=', 2)
->where('order_id', '=', 0)
->where(" code_id in (select code_id from yoshop_order where order_status = 10) ")
->order(['allot_time' => 'desc'])
->page($page, 20)
->select()
->toArray();
}
/**
* 获取非失效码
* @return \think\Paginator
* @throws \think\exception\DbException
*/
public function getNonFailure()
{
// 获取数据列表
return $this->where('status != 3 ')
->where('order_id', '=', 0)
->where(" (((allot_time+360) < unix_timestamp(NOW()) and allot_time > 0) or (create_time+expiration_time+60) < unix_timestamp(NOW())) ")
->order(['allot_time' => 'asc'])
->paginate(1000);
}
/**
* 支付码
* @param $money
* @param $passageway
* @return null|static
* @throws \app\common\exception\BaseException
* @throws \think\exception\DbException
*/
public function getCodeDetailOld($money,$passageway)
{
//连接本地的 Redis 服务
// 字符串操作
$conn = new \think\cache\driver\Redis(config('cache.stores.redis'));
$codesIp = $conn->get('codesIp');
$codesPort = $conn->get('codesPort');
$codeNum = $conn->get('codeNum');
if(empty($codesIp) || empty($codeNum) || $codeNum <= 0){
//获取IP组
$iPGroup = $this->getIPGroup();
$codesIp = isset($iPGroup[0]['ip'])?$iPGroup[0]['ip']:'';
$codesPort = isset($iPGroup[0]['port'])?$iPGroup[0]['port']:'';
$codeNum = 20;
$conn->set('codesIp',$codesIp);
$conn->set('codesPort',$codesPort);
}
$filter = [];
$codeM = new CodeModel();
$zone = 0; //分区
//支付码未过期,并且过期剩余时间超过5分钟,并且退回码池超过2分钟
$where = " (create_time+expiration_time) > unix_timestamp(NOW()) and (create_time+expiration_time) - unix_timestamp(NOW()) > 300 and (back_time+120) < unix_timestamp(NOW()) ";
$filter[] = ['passageway', '=', $passageway]; //通道
$filter[] = ['status', '=', 1]; //未使用状态
$filter[] = ['state', '=', 1]; //启用状态
$filter[] = ['money', '=', $money]; //金额
$code = [];
//尝试三次
for ($i=0;$i<3;$i++) {
//随机起点
$offset = $this->field([
'FLOOR(RAND() * COUNT(*)) AS `offset`',
])->where($where)->where(
$filter
)->find();
$code = $this->field([
'order_no as order_no_sn',
'shop_id',
'code_id',
'store_user_id',
'search_url',
'link',
'alipay',
'passageway',
'num',
])->where($where)->where(
$filter
)->limit((int)$offset['offset'], 1)->select();
$code = isset($code[0]) ? $code[0] : [];
//未查到进入下一次尝试
if(!$code){
continue;
}
//查询队列
//if(!$this->checkQueue($code['code_id'])) continue;
//查询支付状态
if($passageway == 'ZFBH5'){
$res = $this->checkStatus(htmlspecialchars_decode($code['search_url']), $passageway, '订单未支付');
if ($res === false) { //订单不是未支付状态
continue;
}
}else{
if(!empty($codesIp)) {
$conn->set('codeNum',$codeNum-1);
$res = $this->checkStatusProxy(htmlspecialchars_decode($code['search_url']), $passageway, $codesIp, $codesPort, '该订单已完成支付');
}else {
$res = $this->checkStatus(htmlspecialchars_decode($code['search_url']), $passageway, '该订单已完成支付');
}
if ($res !== false) { //已支付 重新匹配
continue;
}
}
for ($j = 1; $j <= 6; $j++) {
$num = $this->getZoneCodeTotal(['status' => '2', 'order_id' => '0', 'zone' => $j]);
if ($num < 20) {
$zone = $j;
break 2;
}
}
}
if(!$code || $zone==0) {
throw new BaseException(['message' => '匹配支付码失败']);
}
$code['zone'] = $zone;
$codeM->update([
'num' => $code['num']+1,
'status' => 2,
'zone' => $zone,
'allot_time' => time(),
],['code_id'=>$code['code_id']]);
return $code;
}
/**
* 支付码
* @param $money
* @param $passageway
* @return null|array
* @throws \app\common\exception\BaseException
* @throws \think\exception\DbException
*/
public function getCodeDetail($money,$passageway)
{
if(empty($money) || empty($passageway)) {
throw new BaseException(['message' => '参数错误']);
}
$money = round($money,2);
//组成队列名称
$queue_name = $passageway.'_'.$money;
//连接本地的 Redis 服务
// 字符串操作-获取代理IP
/*$codesIp = Cache::store('redis')->get('codesIp');
$codesPort = Cache::store('redis')->get('codesPort');
$codeNum = Cache::store('redis')->get('codeNum');
if(empty($codesIp) || empty($codeNum) || $codeNum <= 0){
//获取IP组
$iPGroup = $this->getIPGroup();
$codesIp = isset($iPGroup[0]['ip'])?$iPGroup[0]['ip']:'';
$codesPort = isset($iPGroup[0]['port'])?$iPGroup[0]['port']:'';
$codeNum = 20;
Cache::store('redis')->set('codesIp',$codesIp);
Cache::store('redis')->set('codesPort',$codesPort);
}*/
// 获取分布式锁
$lock_key = $queue_name . '_lock';
$max_wait_time = 10; // 最大等待时间(秒)
$retry_interval = 100; // 重试间隔时间(毫秒)
$lock_ttl = 40; // 锁定时间(秒)
$lock_count = 0; // 锁的重试次数
// 获取分布式锁
$redis = Cache::store('redis');
$lock = false;
$wait_time = 0;
$lock_value = '';
while ($wait_time <= $max_wait_time) {
$lock_value = uniqid(); // 生成唯一的锁值
if ($redis->set($lock_key, $lock_value, 'EX', $lock_ttl, 'NX')) {
$lock = true;
break;
} else {
// 获取锁失败,等待一段时间后重试
$lock_count++;
usleep($retry_interval * 1000);
$wait_time += ($retry_interval / 1000);
if ($lock_count > 20) {
// 重试次数超过限制,抛出异常
throw new BaseException(['message' => '匹配支付码失败,超出重试次数']);
}
}
}
// 获取队列的长度
$queue_length = $redis->lLen($queue_name);
//数组初始化
$codeM = new CodeModel();
$zone = 0; //分区
$code = [];
// 获取锁成功
if ($lock && $queue_length > 0) {
try {
// TODO: 需要加锁的业务逻辑
// 开始匹配
for ($i = 0; $i < $queue_length; $i++) {
// 从队列中取出元素
$timeout = 0; // 不需要设置等待时间
$result_data = $redis->brpop($queue_name, $timeout);
// 反序列化产码信息
$code_data = json_decode($result_data[1],true);
// 判断码是否已经过期
if (time() > $code_data['expire_time']) {
continue;
}
if (empty($code_data['code_id'])) {
continue;
}
//匹配成功处理逻辑
$code = CodeModel::detail($code_data['code_id']);
//查询支付状态
if($passageway == 'ZFBH5'){
$res = $this->checkStatus(htmlspecialchars_decode($code['search_url']), $passageway, '订单未支付');
if ($res === false) { //订单不是未支付状态
continue;
}
}
/*else{
if(!empty($codesIp)) {
$redis->set('codeNum',$codeNum-1);
$res = $this->checkStatusProxy(htmlspecialchars_decode($code['search_url']), $passageway, $codesIp, $codesPort, '该订单已完成支付');
}else {
$res = $this->checkStatus(htmlspecialchars_decode($code['search_url']), $passageway, '该订单已完成支付');
}
if ($res !== false) { //已支付 重新匹配
continue;
}
}*/
for ($j = 1; $j <= 6; $j++) {
$num = $this->getZoneCodeTotal(['status' => '2', 'order_id' => '0', 'zone' => $j]);
if ($num < 20) {
$zone = $j;
break 2;
}
}
}
} finally {
// 释放锁
$lock_value_in_redis = $redis->get($lock_key);
if ($lock_value_in_redis === $lock_value) { // 如果当前锁的值和刚才设置的值相等,则说明当前线程持有该锁,可以进行释放
$redis->del($lock_key); // 删除锁
}else{
//throw new BaseException(['message' => '匹配支付码失败,锁竞争']);
}
}
}
if(!$code || $zone == 0) {
throw new BaseException(['message' => '匹配支付码失败']);
}
$code['zone'] = $zone;
$code['order_no_sn'] = $code['order_no'];
$codeM->update([
'num' => $code['num']+1,
'status' => 2,
'zone' => $zone,
'allot_time' => time(),
],['code_id'=>$code['code_id']]);
return $code;
}
public function checkStatus($url,$passageway,$text='该订单已完成支付'){
if(in_array($passageway,['WX','SNZFBH5'])){
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT,10);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt ($ch, CURLOPT_MAXREDIRS, 3);
$content = curl_exec($ch);
}else {
$publicPath = app()->getRootPath() . 'public/';
$escaped_url = escapeshellarg($url);
$command = "node {$publicPath}myscript.js {$escaped_url} 2>&1";
$content = shell_exec($command);
}
$res = strpos((string)$content,$text);
return $res;
}
/**
* 按条件修改支付码状态为失效
* @param array $field
* @param array $filter
* @return false|int
*/
public function setStatusLose($field,$filter)
{
return $this->update(array_merge(['status' => 3],$field),$filter) !== false;
}
/**
* 等待支付产码列表
* @param $page
* @return array
* @throws \think\exception\DbException
*/
public function getSx($page=1)
{
// 获取数据列表
return $this->where('status', '=', 1)
->where(" num > 0 ")
->order(['back_time' => 'asc'])
->page($page, 20)
->select()
->toArray();
}
public function getIPGroup(){
$html = @file_get_contents("http://http.tiqu.letecs.com/getip3?num=1&type=2&pro=&city=0&yys=0&port=1&time=1&ts=0&ys=0&cs=0&lb=1&sb=0&pb=4&mr=1&regions=");
$result = json_decode($html,true);
$ips = is_array($result['data'])?$result['data']:[];
return $ips;
}
public function checkStatusProxy($targetUrl,$passageway,$ip,$port,$text='该订单已完成支付'){
if(in_array($passageway,['WX','SNZFBH5'])){
// 代理服务器
$proxyServer = "http://" . $ip . ":" . $port;
// 隧道身份信息
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $targetUrl);
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// 设置代理服务器
//curl_setopt($ch, CURLOPT_PROXYTYPE, 0); //http
curl_setopt($ch, CURLOPT_PROXYTYPE, 5); //sock5
curl_setopt($ch, CURLOPT_PROXY, $proxyServer);
// 设置隧道验证信息
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727;)");
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
}else{
$publicPath = app()->getRootPath() . 'public/';
$escaped_url = escapeshellarg($targetUrl);
//$command = "node {$publicPath}myscript_proxy.js {$escaped_url} {$ip} {$port} 2>&1";
$command = "node {$publicPath}myscript.js {$escaped_url} 2>&1";
$result = shell_exec($command);
}
$res = strpos((string)$result,$text);
return $res;
}
/**
* 获取分区产码总数量
* @param array $filter
* @return int|string
*/
public function getZoneCodeTotal($filter = [])
{
return $this->where($filter)->count();
}
/**
* 插入队列判断当前是否可执行
* @param $code_id
* @return
*/
public function checkQueue($code_id)
{
$message = Cache::store('redis')->lPop("queue:$code_id");
// 如果队列为空,则写入队列
if ($message === null || $message === false) {
// 消息内容
$message = 1;
// 监控客户的消息 Hash
Cache::store('redis')->watch("code:$code_id");
// 开始事务
Cache::store('redis')->multi();
// 将消息添加到队列末尾
Cache::store('redis')->rPush("queue:$code_id", $message);
// 提交事务
$result = Cache::store('redis')->exec();
if ($result !== null && $result !== false) {
return true;
}
}
return false;
}
}
+274
View File
@@ -0,0 +1,274 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\model\Order as OrderModel;
use app\common\model\Comment as CommentModel;
use app\api\model\OrderGoods as OrderGoodsModel;
use app\api\service\User as UserService;
use app\common\library\helper;
use app\common\exception\BaseException;
/**
* 商品评价模型
* Class Comment
* @package app\api\model
*/
class Comment extends CommentModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'status',
'sort',
'order_id',
'goods_id',
'order_goods_id',
'is_delete',
'update_time'
];
/**
* 获取指定商品评价列表
* @param int $goodsId 商品ID
* @param int|null $scoreType 评分 (10好评 20中评 30差评)
* @return \think\Paginator
* @throws \think\db\exception\DbException
*/
public function getCommentList(int $goodsId, int $scoreType = null)
{
$filter = $this->getFilter($goodsId, $scoreType);
return $this->with(['user.avatar', 'orderGoods', 'images.file'])
->where($filter)
->order(['sort' => 'asc', 'create_time' => 'desc'])
->paginate(15);
}
/**
* 获取指定商品评价列表 (限制数量, 不分页)
* @param int $goodsId 商品ID
* @param int $limit 限制的数量
* @return \think\Collection
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function listRows(int $goodsId, int $limit = 5)
{
$filter = $this->getFilter($goodsId);
return $this->with(['user.avatar'])
->where($filter)
->order(['sort' => 'asc', $this->getPk()])
->limit($limit)
->select();
}
/**
* 获取指定商品评价总数量
* @param int $goodsId
* @return int
*/
public function rowsTotal(int $goodsId)
{
$filter = $this->getFilter($goodsId);
return $this->where($filter)->count();
}
/**
* 获取查询条件
* @param int $goodsId 商品ID
* @param int|null $scoreType 评分 (10好评 20中评 30差评)
* @return array[]
*/
private function getFilter(int $goodsId, int $scoreType = null)
{
// 筛选条件
$filter = [
['goods_id', '=', $goodsId],
['status', '=', 1],
['is_delete', '=', 0],
];
// 评分
$scoreType > 0 && $filter[] = ['score', '=', $scoreType];
return $filter;
}
/**
* 获取指定评分总数
* @param int $goodsId
* @return array|null|\think\Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getTotal(int $goodsId)
{
return $this->field([
'count(comment_id) AS `all`',
'count(score = 10 OR NULL) AS `praise`',
'count(score = 20 OR NULL) AS `review`',
'count(score = 30 OR NULL) AS `negative`',
])->where([
'goods_id' => $goodsId,
'is_delete' => 0,
'status' => 1
])->find();
}
/**
* 验证订单是否允许评价
* @param OrderModel $order
* @return boolean
*/
public function checkOrderAllowComment(OrderModel $order)
{
// 验证订单是否已完成
if ($order['order_status'] != 30) {
$this->error = '该订单未完成,无法评价';
return false;
}
// 验证订单是否已评价
if ($order['is_comment'] == 1) {
$this->error = '该订单已完成评价';
return false;
}
return true;
}
/**
* 根据已完成订单商品 添加评价
* @param OrderModel $order
* @param $goodsList
* @param array $data
* @return boolean
* @throws BaseException
*/
public function increased(OrderModel $order, $goodsList, array $data)
{
// 生成 formData
$formData = $this->formatFormData($data);
// 生成评价数据
$data = $this->createCommentData($order['order_id'], $goodsList, $formData);
if (empty($data)) {
$this->error = '没有输入评价内容';
return false;
}
return $this->transaction(function () use ($order, $goodsList, $formData, $data) {
// 记录评价内容
$result = $this->addAll($data);
// 记录评价图片`
$this->saveAllImages($result, $formData);
// 更新订单评价状态
$isComment = count($goodsList) === count($data);
$this->updateOrderIsComment($order, $isComment, $result);
return true;
});
}
/**
* 更新订单评价状态
* @param OrderModel $order
* @param $isComment
* @param $commentList
* @return array|false
* @throws \Exception
*/
private function updateOrderIsComment(OrderModel $order, $isComment, $commentList)
{
// 更新订单商品
$orderGoodsData = [];
foreach ($commentList as $comment) {
$orderGoodsData[] = [
'where' => [
'order_goods_id' => $comment['order_goods_id'],
],
'data' => [
'is_comment' => 1
]
];
}
// 更新订单
$isComment && $order->save(['is_comment' => 1]);
return (new OrderGoods)->updateAll($orderGoodsData);
}
/**
* 生成评价数据
* @param int $orderId
* @param $goodsList
* @param array $formData
* @return array
* @throws BaseException
*/
private function createCommentData(int $orderId, $goodsList, array $formData)
{
$data = [];
foreach ($goodsList as $goods) {
if (!isset($formData[$goods['order_goods_id']])) {
throwError('提交的数据不合法');
}
$commentItem = $formData[$goods['order_goods_id']];
$commentItem['content'] = trim($commentItem['content']);
!empty($commentItem['content']) && $data[$goods['order_goods_id']] = [
'score' => $commentItem['score'],
'content' => $commentItem['content'],
'is_picture' => !empty($commentItem['uploaded']),
'sort' => 100,
'status' => 1,
'user_id' => UserService::getCurrentLoginUserId(),
'order_id' => $orderId,
'goods_id' => $commentItem['goods_id'],
'order_goods_id' => $commentItem['order_goods_id'],
'store_id' => self::$storeId
];
}
return $data;
}
/**
* 格式化 formData
* @param array $data
* @return array
*/
private function formatFormData(array $data)
{
return helper::arrayColumn2Key($data, 'order_goods_id');
}
/**
* 记录评价图片
* @param $commentList
* @param $formData
* @return bool
*/
private function saveAllImages($commentList, $formData)
{
// 生成评价图片数据
$imageData = [];
foreach ($commentList as $comment) {
$item = $formData[$comment['order_goods_id']];
foreach ($item['uploaded'] as $imageId) {
$imageData[] = [
'comment_id' => $comment['comment_id'],
'image_id' => $imageId,
'store_id' => self::$storeId
];
}
}
$model = new CommentImage;
return !empty($imageData) && $model->addAll($imageData) !== false;
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\CommentImage as CommentImageModel;
/**
* 商品图片模型
* Class GoodsImage
* @package app\api\model
*/
class CommentImage extends CommentImageModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
];
/**
* 关联文件库
* @return \think\model\relation\BelongsTo
*/
public function file()
{
return parent::file()->bind(['image_url' => 'preview_url']);
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Company as CompanyModel;
use app\common\library\helper;
use cores\exception\BaseException;
use think\cache\driver\Redis;
/**
* 产码模型
* Class Order
* @package app\api\model
*/
class Company extends CompanyModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
}
+86
View File
@@ -0,0 +1,86 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\service\User as UserService;
use app\common\model\Coupon as CouponModel;
use cores\exception\BaseException;
/**
* 优惠券模型
* Class Coupon
* @package app\api\model
*/
class Coupon extends CouponModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'receive_num',
'is_delete',
'create_time',
'update_time',
];
/**
* 获取优惠券列表
* @param int|null $limit 获取的数量
* @param bool $onlyReceive 只显示可领取
* @return mixed
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getList(int $limit = null, bool $onlyReceive = false)
{
// 查询构造器
$query = $this->getNewQuery();
// 只显示可领取(未过期,未发完)的优惠券
if ($onlyReceive) {
$query->where('IF ( `total_num` > - 1, `receive_num` < `total_num`, 1 = 1 )')
->where('IF ( `expire_type` = 20, (`end_time` + 86400) >= ' . time() . ', 1 = 1 )');
}
// 查询数量
$limit > 0 && $query->limit($limit);
// 优惠券列表
$couponList = $query->where('status', '=', 1)
->where('is_delete', '=', 0)
->order(['sort', 'create_time' => 'desc'])
->select();
// 获取用户已领取的优惠券
return $this->setIsReceive($couponList);
}
/**
* 获取用户已领取的优惠券
* @param mixed $couponList
* @return mixed
* @throws BaseException
*/
private function setIsReceive($couponList)
{
// 获取用户已领取的优惠券
$userInfo = UserService::getCurrentLoginUser();
if ($userInfo !== false) {
$UserCouponModel = new UserCoupon;
$userCouponIds = $UserCouponModel->getUserCouponIds($userInfo['user_id']);
foreach ($couponList as $key => $item) {
$couponList[$key]['is_receive'] = in_array($item['coupon_id'], $userCouponIds);
}
}
return $couponList;
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Delivery as DeliveryModel;
/**
* 配送模板模型
* Class Delivery
* @package app\api\model
*/
class Delivery extends DeliveryModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
'update_time'
];
}
+34
View File
@@ -0,0 +1,34 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\DeliveryRule as DeliveryRuleModel;
/**
* 配送模板区域及运费模型
* Class DeliveryRule
* @package app\api\model
*/
class DeliveryRule extends DeliveryRuleModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
'update_time'
];
}
+36
View File
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Express as ExpressModel;
/**
* 物流公司模型
* Class Express
* @package app\api\model
*/
class Express extends ExpressModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'kuaidi100_code',
'sort',
'store_id',
'create_time',
'update_time'
];
}
+265
View File
@@ -0,0 +1,265 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\service\Goods as GoodsService;
use app\api\service\user\Grade as UserGradeService;
use app\api\model\GoodsSku as GoodsSkuModel;
use app\api\model\GoodsSpecRel as GoodsSpecRelModel;
use app\common\model\Goods as GoodsModel;
use app\common\enum\goods\Status as GoodsStatusEnum;
use cores\exception\BaseException;
/**
* 商品模型
* Class Goods
* @package app\api\model
*/
class Goods extends GoodsModel
{
/**
* 隐藏字段
* @var array
*/
public $hidden = [
'images',
'delivery',
'deduct_stock_type',
'sales_initial',
'sales_actual',
'sort',
'is_delete',
'store_id',
'create_time',
'update_time'
];
// 是否设置会员折扣价
private $isGoodsGradeMoney = true;
/**
* 商品详情:HTML实体转换回普通字符
* @param $value
* @return string
*/
public function getContentAttr($value): string
{
return htmlspecialchars_decode((string)$value);
}
/**
* 是否设置会员折扣价
* @param bool $value
* @return $this
*/
public function isGoodsGradeMoney(bool $value): Goods
{
$this->isGoodsGradeMoney = $value;
return $this;
}
/**
* 获取商品列表
* @param array $param 查询条件
* @param int $listRows 分页数量
* @return mixed|\think\model\Collection|\think\Paginator
* @throws \think\db\exception\DbException
*/
public function getList(array $param = [], int $listRows = 15)
{
// 整理查询参数
$params = array_merge($param, ['status' => GoodsStatusEnum::ON_SALE]);
// 获取商品列表
$list = parent::getList($params, $listRows);
if ($list->isEmpty()) {
return $list;
}
// 隐藏冗余的属性
$list->hidden(static::getHidden(['content', 'goods_images', 'images']));
// 整理列表数据并返回
return $this->setGoodsListDataFromApi($list);
}
/**
* 获取商品详情 (详细数据用于页面展示)
* @param int $goodsId 商品ID
* @param bool $verifyStatus 是否验证商品状态(上架)
* @return mixed
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getDetails(int $goodsId, bool $verifyStatus = true)
{
// 关联查询(商品图片、sku列表)
$with = ['images.file', 'skuList.image', 'video', 'videoCover'];
// 获取商品记录
$goodsInfo = $this->getGoodsMain($goodsId, $with, $verifyStatus);
// 商品规格列表
$goodsInfo['specList'] = GoodsSpecRelModel::getSpecList($goodsInfo['goods_id']);
return $goodsInfo->hidden(static::getHidden(['images']));
}
/**
* 获取商品详情 (仅包含主商品信息和商品图片)
* @param int $goodsId 商品ID
* @param bool $verifyStatus 是否验证商品状态(上架)
* @return mixed
* @throws BaseException
*/
public function getBasic(int $goodsId, bool $verifyStatus = true)
{
// 关联查询(商品图片)
$with = ['images.file'];
// 获取商品记录
return $this->getGoodsMain($goodsId, $with, $verifyStatus);
}
/**
* 获取商品规格数据
* @param int $goodsId
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getSpecData(int $goodsId): array
{
$data = [];
// 商品SKU列表
$data['skuList'] = GoodsSkuModel::getSkuList($goodsId);
// 商品规格列表
$data['specList'] = GoodsSpecRelModel::getSpecList($goodsId);
return $data;
}
/**
* 获取商品主体信息
* @param int $goodsId 商品ID
* @param array $with 关联查询
* @param bool $verifyStatus 是否验证商品状态(上架)
* @return mixed
* @throws BaseException
*/
private function getGoodsMain(int $goodsId, array $with = [], bool $verifyStatus = true)
{
// 获取商品记录
$goodsInfo = static::detail($goodsId, $with);
// 判断商品是否存在
if (empty($goodsInfo) || $goodsInfo['is_delete']) {
throwError('很抱歉,商品信息不存在');
}
// 判断商品状态(上架)
if ($verifyStatus && $goodsInfo['status'] == GoodsStatusEnum::OFF_SALE) {
throwError('很抱歉,当前商品已下架');
}
// 整理商品数据并返回
return $this->setGoodsDataFromApi($goodsInfo);
}
/**
* 根据商品id集获取商品列表
* @param array $goodsIds
* @return mixed
*/
public function getListByIdsFromApi(array $goodsIds)
{
// 获取商品列表
$data = $this->getListByIds($goodsIds, GoodsStatusEnum::ON_SALE);
// 整理列表数据并返回
return $this->setGoodsListDataFromApi($data);
}
/**
* 获取商品指定的sku信息并且设置商品的会员价
* @param mixed $goodsInfo 商品信息
* @param string $goodsSkuId 商品SKUID
* @param bool $isGoodsGradeMoney 是否设置会员折扣价
* @return \app\common\model\GoodsSku|array|null
* @throws BaseException
*/
public static function getSkuInfo($goodsInfo, string $goodsSkuId, bool $isGoodsGradeMoney = true)
{
$goodsInfo['skuInfo'] = GoodsService::getSkuInfo($goodsInfo['goods_id'], $goodsSkuId);
$isGoodsGradeMoney && (new static)->setGoodsGradeMoney($goodsInfo);
return $goodsInfo['skuInfo'];
}
/**
* 设置商品展示的数据 api模块
* @param $data
* @return mixed
*/
private function setGoodsListDataFromApi($data)
{
return $this->setGoodsListData($data, function ($goods) {
// 整理商品数据 api模块
$this->setGoodsDataFromApi($goods);
});
}
/**
* 整理商品数据 api模块
* @param $goodsInfo
* @return mixed
*/
private function setGoodsDataFromApi($goodsInfo)
{
return $this->setGoodsData($goodsInfo, function ($goods) {
// 计算并设置商品会员价
$this->isGoodsGradeMoney && $this->setGoodsGradeMoney($goods);
});
}
/**
* 设置商品的会员价
* @param Goods $goods
* @throws BaseException
*/
private function setGoodsGradeMoney(self $goods)
{
// 设置当前商品是否使用会员等级折扣价
$goods['is_user_grade'] = false;
// 获取当前登录用户的会员等级信息
$gradeInfo = UserGradeService::getCurrentGradeInfo();
// 判断商品是否参与会员折扣
if (empty($gradeInfo) || !$goods['is_enable_grade']) {
return;
}
// 默认的折扣比例
$discountRatio = $gradeInfo['equity']['discount'];
// 商品单独设置了会员折扣
if ($goods['is_alone_grade'] && isset($goods['alone_grade_equity'][$gradeInfo['grade_id']])) {
$discountRatio = $goods['alone_grade_equity'][$gradeInfo['grade_id']];
}
if (empty($discountRatio)) {
return;
}
// 标记参与会员折扣
$goods['is_user_grade'] = true;
// 会员折扣价: 商品基础价格
$goods['goods_price_min'] = UserGradeService::getDiscountPrice($goods['goods_price_min'], $discountRatio);
$goods['goods_price_max'] = UserGradeService::getDiscountPrice($goods['goods_price_max'], $discountRatio);
// 会员折扣价: 商品sku列表
if ($goods->getRelation('skuList')) {
foreach ($goods['skuList'] as &$skuItem) {
$skuItem['goods_price'] = UserGradeService::getDiscountPrice($skuItem['goods_price'], $discountRatio);
}
}
// 会员折扣价: 已选择的商品sku(用于购物车)
if ($goods->getAttr('skuInfo')) {
$goods['skuInfo']['goods_price'] = UserGradeService::getDiscountPrice($goods['skuInfo']['goods_price'], $discountRatio);
}
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\GoodsImage as GoodsImageModel;
/**
* 商品图片模型
* Class GoodsImage
* @package app\api\model
*/
class GoodsImage extends GoodsImageModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
];
}
+43
View File
@@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\GoodsSku as GoodsSkuModel;
/**
* 商品规格模型
* Class GoodsSku
* @package app\api\model
*/
class GoodsSku extends GoodsSkuModel
{
/**
* 关联模型:规格图片
* @return \think\model\relation\HasOne
*/
public function image(): \think\model\relation\HasOne
{
return parent::image()->bind(['image_url' => 'preview_url']);
}
/**
* 隐藏字段
* @var array
*/
public $hidden = [
'image',
'store_id',
'create_time',
'update_time'
];
}
+24
View File
@@ -0,0 +1,24 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\GoodsSpecRel as GoodsSpecRelModel;
/**
* 商品规格关系模型
* Class GoodsSpecRel
* @package app\api\model
*/
class GoodsSpecRel extends GoodsSpecRelModel
{
}
+32
View File
@@ -0,0 +1,32 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Help as HelpModel;
/**
* 模型类:帮助中心
* Class Help
* @package app\api\model
*/
class Help extends HelpModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'create_time',
'update_time',
];
}
+36
View File
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Merchant as MerchantModel;
use app\common\library\helper;
use cores\exception\BaseException;
use think\cache\driver\Redis;
/**
* 产码模型
* Class Order
* @package app\api\model
*/
class Merchant extends MerchantModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
}
+80
View File
@@ -0,0 +1,80 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Notify as NotifyModel;
use app\common\library\helper;
use cores\exception\BaseException;
use think\cache\driver\Redis;
/**
* 通知模型
* Class Order
* @package app\api\model
*/
class Notify extends NotifyModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
// 信息提示
private $message = '';
private $redis = null;
/**
* 通知列表
* @return \think\Paginator
* @throws \think\exception\DbException
*/
public function getList()
{
// 获取数据列表
return $this->where('status', '=', 0)
->where('num', '<', 3)
->order(['create_time' => 'asc'])
->paginate(200);
}
/**
* 新增通知记录
* @param $order
* @return false|int
*/
public function add($order)
{
return $this->save([
'order_id' => $order['order_id'],
'notify_url' => $order['notify_url'],
'store_id' => 10001,
]);
}
/**
* 修改通知状态
* @param $data
* @return bool
*/
public function sureNotify($data)
{
return $this->save([
'status' => $data['status'],
'num' => $data['num'],
'last_time' => time(),
]) !== false;
}
}
+521
View File
@@ -0,0 +1,521 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\model\{Goods as GoodsModel, OrderRefund as OrderRefundModel, Setting as SettingModel};
use app\api\service\{User as UserService, Payment as PaymentService};
use app\api\service\order\{PaySuccess as OrderPaySuccesService, source\Factory as OrderSourceFactory};
use app\common\model\Order as OrderModel;
use app\common\service\{Order as OrderService, order\Complete as OrderCompleteService};
use app\common\enum\{
Setting as SettingEnum,
OrderType as OrderTypeEnum,
order\PayType as OrderPayTypeEnum,
order\PayStatus as PayStatusEnum,
order\OrderStatus as OrderStatusEnum,
// order\DeliveryType as DeliveryTypeEnum,
order\ReceiptStatus as ReceiptStatusEnum,
order\DeliveryStatus as DeliveryStatusEnum
};
use app\common\library\helper;
use cores\exception\BaseException;
/**
* 订单模型
* Class Order
* @package app\api\model
*/
class Order extends OrderModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
// 信息提示
private $message = '';
/**
* 待支付订单详情
* @param string $orderNo 订单号
* @return null|static
*/
public static function getPayDetail(string $orderNo): ?Order
{
return self::detail(['order_no' => $orderNo, 'pay_status' => PayStatusEnum::PENDING, 'is_delete' => 0], ['goods', 'user']);
}
/**
* 订单支付事件
* @param int $payType
* @return bool
*/
public function onPay(int $payType = OrderPayTypeEnum::WECHAT): bool
{
// 判断订单状态
$orderSource = OrderSourceFactory::getFactory($this['order_source']);
if (!$orderSource->checkOrderStatusOnPay($this)) {
$this->error = $orderSource->getError();
return false;
}
// 余额支付
if ($payType == OrderPayTypeEnum::BALANCE) {
return $this->onPaymentByBalance($this['order_no']);
}
return true;
}
/**
* 构建支付请求的参数
* @param self $order 订单信息
* @param int $payType 订单支付方式
* @return array
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function onOrderPayment(self $order, int $payType): array
{
if ($payType == OrderPayTypeEnum::WECHAT) {
return $this->onPaymentByWechat($order);
}
return [];
}
/**
* 构建微信支付请求
* @param self $order 订单详情
* @return array
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function onPaymentByWechat(self $order): array
{
return PaymentService::wechat(
$order['order_id'],
$order['order_no'],
$order['pay_price'],
OrderTypeEnum::ORDER
);
}
/**
* 立即购买:获取订单商品列表
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品SKU
* @param int $goodsNum 购买数量
* @return mixed
* @throws BaseException
*/
public function getOrderGoodsListByNow(int $goodsId, string $goodsSkuId, int $goodsNum)
{
// 获取商品列表
$model = new GoodsModel;
$goodsList = $model->isGoodsGradeMoney(false)->getListByIdsFromApi([$goodsId]);
if ($goodsList->isEmpty()) {
throwError('未找到商品信息');
}
// 隐藏冗余的属性
$goodsList->hidden(GoodsModel::getHidden(['content', 'goods_images', 'images']));
foreach ($goodsList as &$item) {
// 商品sku信息
$goodsInfo['skuInfo'] = GoodsModel::getSkuInfo($item, $goodsSkuId, false);
// 商品封面 (优先sku封面)
$item['goods_image'] = $item['skuInfo']['goods_image'] ?: $item['goods_image'];
// 商品单价
$item['goods_price'] = $item['skuInfo']['goods_price'];
// 商品购买数量
$item['total_num'] = $goodsNum;
// 商品SKU索引
$item['goods_sku_id'] = $item['skuInfo']['goods_sku_id'];
// 商品购买总金额
$item['total_price'] = helper::bcmul($item['goods_price'], $goodsNum);
}
return $goodsList;
}
/**
* 余额支付标记订单已支付
* @param string $orderNo 订单号
* @return bool
*/
public function onPaymentByBalance(string $orderNo): bool
{
// 获取订单详情
$service = new OrderPaySuccesService($orderNo);
// 发起余额支付
$status = $service->onPaySuccess(OrderPayTypeEnum::BALANCE);
if (!$status) {
throwError($service->getError());
}
return $status;
}
/**
* 获取用户订单列表
* @param string $type 订单类型 (all全部 payment待付款 received待发货 deliver待收货 comment待评价)
* @return \think\Paginator
* @throws \think\db\exception\DbException
* @throws BaseException
*/
public function getList(string $type = 'all'): \think\Paginator
{
// 筛选条件
$filter = [];
// 订单数据类型
switch ($type) {
case 'all':
break;
case 'payment':
$filter['pay_status'] = PayStatusEnum::PENDING;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'progress':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'complete':
$filter['order_status'] = OrderStatusEnum::COMPLETED;
break;
case 'delivery':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['delivery_status'] = DeliveryStatusEnum::NOT_DELIVERED;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'received':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['delivery_status'] = DeliveryStatusEnum::DELIVERED;
$filter['receipt_status'] = ReceiptStatusEnum::NOT_RECEIVED;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'comment':
$filter['is_comment'] = 0;
$filter['order_status'] = OrderStatusEnum::COMPLETED;
break;
}
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 查询列表数据
return $this->with(['goods.image'])
->where($filter)
->where('user_id', '=', $userId)
->where('is_delete', '=', 0)
->order(['create_time' => 'desc'])
->paginate(15);
}
/**
* 取消订单
* @return bool|mixed
*/
public function cancel()
{
if ($this['delivery_status'] == DeliveryStatusEnum::DELIVERED) {
$this->error = '已发货订单不可取消';
return false;
}
// 订单是否已支付
$isPay = $this['pay_status'] == PayStatusEnum::SUCCESS;
// 提示信息
$this->message = $isPay ? '订单已申请取消,需等待后台审核' : '订单已取消成功';
// 订单取消事件
return $this->transaction(function () use ($isPay) {
// 订单取消事件
$isPay == false && OrderService::cancelEvent($this);
// 更新订单状态: 已付款的订单设置为"待取消", 等待后台审核
return $this->save(['order_status' => $isPay ? OrderStatusEnum::APPLY_CANCEL : OrderStatusEnum::CANCELLED]);
});
}
/**
* 确认收货
* @return bool|mixed
*/
public function receipt()
{
// 验证订单是否合法
// 条件1: 订单必须已发货
// 条件2: 订单必须未收货
if ($this['delivery_status'] != 20 || $this['receipt_status'] != 10) {
$this->error = '该订单不合法';
return false;
}
return $this->transaction(function () {
// 更新订单状态
$status = $this->save([
'receipt_status' => 20,
'receipt_time' => time(),
'order_status' => 30
]);
// 执行订单完成后的操作
$OrderCompleteService = new OrderCompleteService();
$OrderCompleteService->complete([$this], static::$storeId);
return $status;
});
}
/**
* 获取当前用户订单数量
* @param string $type 订单类型 (all全部 payment待付款 received待发货 deliver待收货 comment待评价)
* @return int
* @throws BaseException
*/
public function getCount(string $type = 'all'): int
{
// 筛选条件
$filter = [];
// 订单数据类型
switch ($type) {
case 'all':
break;
case 'payment':
$filter['pay_status'] = PayStatusEnum::PENDING;
break;
case 'progress':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'complete':
$filter['order_status'] = OrderStatusEnum::COMPLETED;
break;
case 'received':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['delivery_status'] = DeliveryStatusEnum::DELIVERED;
$filter['receipt_status'] = ReceiptStatusEnum::NOT_RECEIVED;
break;
case 'delivery':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['delivery_status'] = DeliveryStatusEnum::NOT_DELIVERED;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'comment':
$filter['is_comment'] = 0;
$filter['order_status'] = OrderStatusEnum::COMPLETED;
break;
}
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 查询数据
return $this->where('user_id', '=', $userId)
->where('order_status', '<>', 20)
->where($filter)
->where('is_delete', '=', 0)
->count();
}
/**
* 获取用户订单详情(含关联数据)
* @param int $orderId 订单ID
* @return Order|array|null
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function getUserOrderDetail(int $orderId)
{
// 关联查询
$with = [
'goods' => ['image', 'goods', 'refund'],
'address', 'express'
];
// 查询订单记录
$order = static::getDetail($orderId, $with);
// 该订单是否允许申请售后
$order['isAllowRefund'] = static::isAllowRefund($order);
return $order;
}
/**
* 获取用户订单详情(仅订单记录)
* @param int $orderId
* @param array $with
* @return Order|array|null
* @throws BaseException
*/
public static function getDetail(int $orderId, array $with = [])
{
// 查询订单记录
$order = static::detail([
'order_id' => $orderId,
// 'user_id' => UserService::getCurrentLoginUserId(),
], $with);
empty($order) && throwError('订单不存在');
return $order;
}
/**
* 获取当前用户待处理的订单数量
* @return array
* @throws BaseException
*/
public function getTodoCounts(): array
{
return [
'payment' => $this->getCount('payment'), // 待付款的订单
'delivery' => $this->getCount('delivery'), // 待发货的订单
'received' => $this->getCount('received'), // 待收货的订单
'progress' => $this->getCount('progress'), // 进行中的订单
'complete' => $this->getCount('complete'), // 已完成的订单
'refund' => OrderRefundModel::getCountByUnderway(), // 进行中的售后单
];
}
// 返回提示信息
public function getMessage(): string
{
return $this->message;
}
/**
* 当前订单是否允许申请售后
* @param Order $order
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private static function isAllowRefund(self $order): bool
{
// 必须是已发货的订单
if ($order['delivery_status'] != DeliveryStatusEnum::DELIVERED) {
return false;
}
// 允许申请售后期限(天)
$refundDays = SettingModel::getItem(SettingEnum::TRADE)['order']['refund_days'];
// 不允许售后
if ($refundDays == 0) {
return false;
}
// 当前时间超出允许申请售后期限
if (
$order['receipt_status'] == ReceiptStatusEnum::RECEIVED
&& time() > ($order->getData('receipt_time') + ((int)$refundDays * 86400))
) {
return false;
}
return true;
}
/**
* 订单详情
* @param $order_no
* @return null|static
* @throws BaseException
* @throws \think\exception\DbException
*/
public function getOrderDetail($order_no)
{
if (!$order = $this->field([
'name',
'bank_ownership',
'bank_no',
'total_price as `money`',
'order_no',
'client_status',
'order_status',
'create_time',
])->where([
['order_no', '=', $order_no],
])->find()) {
throw new BaseException(['msg' => '订单不存在']);
}
return $order;
}
/**
* 订单详情
* @param $order_id
* @return null|static
* @throws BaseException
* @throws \think\exception\DbException
*/
public function getOrderDetailById($order_id)
{
if (!$order = $this->field([
'name',
'total_price as `money`',
'order_no',
'order_no_sn',
'order_status',
'create_time',
'merchant_id',
])->where([
['order_id', '=', $order_id],
])->find()) {
throw new BaseException(['message' => '订单不存在']);
}
return $order;
}
/**
* 新增订单记录
* @param $order
* @return false|int
*/
public function putInto($order)
{
return $this->save([
'store_id' => 10001,
'name' => $order['name'],
'total_price' => $order['money'],
'order_no' => $order['order_no'],
'notify_url' => $order['notifyUrl'],
'pay_price' => $order['money'],
'merchant_id' => $order['merchant_id'],
'callback' => $order['callback'],
'passageway' => $order['passageway'],
'ip' => $order['ip'],
]);
}
/**
* 订单用户状态修改
* @param $order_no
* @return false|int
*/
public function setClientStatus($order_no)
{
$where = array(
['order_no', '=', $order_no],
);
return $this->where($where)->update(['client_status' => 20]) !== false;
}
/**
* 获取分区订单总数量
* @param array $filter
* @return int|string
*/
public function getZoneOrderTotal($filter = [])
{
return $this->where($filter)->count();
}
/**
* 修改订单状态
* @param $where
* @param $field
* @return false|int
*/
public static function orderUpdate($where, $field)
{
return (new static())->where($where)->update($field) !== false;
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\OrderAddress as OrderAddressModel;
/**
* 订单收货地址模型
* Class OrderAddress
* @package app\api\model
*/
class OrderAddress extends OrderAddressModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
];
}
+62
View File
@@ -0,0 +1,62 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\OrderGoods as OrderGoodsModel;
/**
* 订单商品模型
* Class OrderGoods
* @package app\api\model
*/
class OrderGoods extends OrderGoodsModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'image',
'content',
'store_id',
'create_time',
];
/**
* 获取未评价的商品
* @param int $orderId 订单ID
* @return \think\Collection
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function getNotCommentGoodsList(int $orderId)
{
return (new static)->with(['image'])
->where('order_id', '=', $orderId)
->where('is_comment', '=', 0)
->select();
}
/**
* 修改订单状态
* @param $where
* @param $field
* @return false|int
*/
public static function orderUpdate($where, $field)
{
return (new static())->where($where)->update($field) !== false;
}
}
+234
View File
@@ -0,0 +1,234 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\service\User as UserService;
use app\api\model\OrderGoods as OrderGoodsModel;
use app\common\model\OrderRefund as OrderRefundModel;
use app\common\enum\order\refund\RefundType as RefundTypeEnum;
use app\common\enum\order\refund\AuditStatus as AuditStatusEnum;
use app\common\enum\order\refund\RefundStatus as RefundStatusEnum;
use cores\exception\BaseException;
/**
* 售后单模型
* Class OrderRefund
* @package app\api\model
*/
class OrderRefund extends OrderRefundModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
/**
* 追加字段
* @var array
*/
protected $append = [
'state_text', // 售后单状态文字描述
];
/**
* 售后单状态文字描述
* @param $value
* @param $data
* @return string
*/
public function getStateTextAttr($value, $data): string
{
// 已完成
if ($data['status'] == RefundStatusEnum::COMPLETED) {
$text = [RefundTypeEnum::RETURN => '已同意退货并已退款', RefundTypeEnum::EXCHANGE => '已同意换货'];
return $text[$data['type']];
}
// 已取消
if ($data['status'] == RefundStatusEnum::CANCELLED) {
return '已取消';
}
// 已拒绝
if ($data['status'] == RefundStatusEnum::REJECTED) {
// return '已拒绝';
return $data['type'] == RefundTypeEnum::RETURN ? '已拒绝退货退款' : '已拒绝换货';
}
// 进行中
if ($data['status'] == RefundStatusEnum::NORMAL) {
if ($data['audit_status'] == AuditStatusEnum::WAIT) {
return '等待审核中';
}
if ($data['type'] == RefundTypeEnum::RETURN) {
return $data['is_user_send'] ? '已发货,待平台确认' : '已同意退货,请及时发货';
}
}
return $value;
}
/**
* 获取用户售后单列表
* @param int $state 售后单状态 -1为全部
* @return \think\Paginator
* @throws \app\common\exception\BaseException
* @throws \think\db\exception\DbException
* @throws BaseException
*/
public function getList(int $state = -1): \think\Paginator
{
// 检索查询条件
$filter = [];
// 售后单状态
$state > -1 && $filter[] = ['status', '=', $state];
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 查询列表记录
return $this->with(['orderGoods.image'])
->where($filter)
->where('user_id', '=', $userId)
->order(['create_time' => 'desc'])
->paginate(15);
}
/**
* 获取当前用户的售后单详情
* @param int $orderRefundId 售后单ID
* @param bool $isWith 是否关联
* @return static|null
* @throws BaseException
*/
public static function getDetail(int $orderRefundId, bool $isWith = false): ?OrderRefund
{
// 关联查询
$with = $isWith ? ['orderGoods' => ['image'], 'images.file', 'address', 'express'] : [];
// 获取记录
$detail = static::detail([
'user_id' => UserService::getCurrentLoginUserId(),
'order_refund_id' => $orderRefundId
], $with);
if (empty($detail)) throwError('未找到该售后单');
return $detail;
}
/**
* 获取当前用户的售后单数量(进行中的)
* @return int
* @throws BaseException
*/
public static function getCountByUnderway(): int
{
$userId = UserService::getCurrentLoginUserId();
return (new static)->where('user_id', '=', $userId)
->where('status', '=', 0)
->count();
}
/**
* 订单商品详情
* @param int $orderGoodsId 订单商品ID
* @return \app\common\model\OrderGoods|null
* @throws BaseException
*/
public function getRefundGoods(int $orderGoodsId)
{
$goods = OrderGoodsModel::detail($orderGoodsId);
if (isset($goods['refund']) && !empty($goods['refund'])) {
throwError('当前商品已申请售后');
}
return $goods;
}
/**
* 用户发货
* @param $data
* @return false|int
*/
public function delivery(array $data)
{
if (
$this['type'] != RefundTypeEnum::RETURN
|| $this['audit_status'] != AuditStatusEnum::REVIEWED
|| $this['is_user_send'] != 0
) {
$this->error = '当前售后单不合法,不允许该操作';
return false;
}
if ($data['expressId'] <= 0) {
$this->error = '请选择物流公司';
return false;
}
if (empty($data['expressNo'])) {
$this->error = '请填写物流单号';
return false;
}
return $this->save([
'is_user_send' => 1,
'send_time' => time(),
'express_id' => (int)$data['expressId'],
'express_no' => $data['expressNo'],
]);
}
/**
* 新增售后单记录
* @param int $orderGoodsId 订单商品ID
* @param array $data 用户提交的表单数据
* @return mixed
* @throws BaseException
*/
public function apply(int $orderGoodsId, array $data)
{
// 订单商品详情
$goods = $this->getRefundGoods($orderGoodsId);
return $this->transaction(function () use ($orderGoodsId, $data, $goods) {
// 新增售后单记录
$this->save([
'order_goods_id' => $orderGoodsId,
'order_id' => $goods['order_id'],
'user_id' => UserService::getCurrentLoginUserId(),
'type' => $data['type'],
'apply_desc' => $data['content'],
'audit_status' => AuditStatusEnum::WAIT,
'status' => 0,
'store_id' => self::$storeId
]);
// 记录凭证图片关系
if (isset($data['images']) && !empty($data['images'])) {
$this->saveImages((int)$this['order_refund_id'], $data['images']);
}
return true;
});
}
/**
* 记录售后单图片
* @param int $orderRefundId 售后单ID
* @param array $images 图片列表
* @return bool
*/
private function saveImages(int $orderRefundId, array $images)
{
// 生成评价图片数据
$data = [];
foreach ($images as $imageId) {
$data[] = [
'order_refund_id' => $orderRefundId,
'image_id' => $imageId,
'store_id' => self::$storeId
];
}
return !empty($data) && (new OrderRefundImage)->addAll($data) !== false;
}
}
@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\OrderRefundAddress as OrderRefundAddressModel;
/**
* 售后单退货地址模型
* Class OrderRefundAddress
* @package app\api\model
*/
class OrderRefundAddress extends OrderRefundAddressModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time'
];
}
@@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\OrderRefundImage as OrderRefundImageModel;
/**
* 售后单图片模型
* Class OrderRefundImage
* @package app\api\model
*/
class OrderRefundImage extends OrderRefundImageModel
{
}
+161
View File
@@ -0,0 +1,161 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\model\Goods as GoodsModel;
use app\api\model\Coupon as CouponModel;
use app\common\model\Page as PageModel;
use app\common\library\helper;
use cores\exception\BaseException;
/**
* 页面模型
* Class Page
* @package app\api\model
*/
class Page extends PageModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
'update_time'
];
/**
* DIY页面详情
* @param int|null $pageId 页面ID
* @return array
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getPageData(int $pageId = null)
{
// 页面详情
$detail = $pageId > 0 ? parent::detail($pageId) : parent::getHomePage();
if (empty($detail)) {
throwError('很抱歉,未找到该页面');
}
// 页面diy元素
$pageData = $detail['page_data'];
// 获取动态数据
foreach ($pageData['items'] as &$item) {
// 移出默认数据
if (array_key_exists('defaultData', $item)) {
unset($item['defaultData']);
}
if ($item['type'] === 'window') {
$item['data'] = array_values($item['data']);
} else if ($item['type'] === 'goods') {
$item['data'] = $this->getGoodsList($item);
} else if ($item['type'] === 'coupon') {
$item['data'] = $this->getCouponList($item);
} else if ($item['type'] === 'article') {
$item['data'] = $this->getArticleList($item);
} else if ($item['type'] === 'special') {
$item['data'] = $this->getSpecialList($item);
}
}
return $pageData;
}
/**
* 商品组件:获取商品列表
* @param $item
* @return array
* @throws \think\db\exception\DbException
*/
private function getGoodsList($item)
{
// 获取商品数据
$model = new GoodsModel;
if ($item['params']['source'] === 'choice') {
// 数据来源:手动
$goodsIds = helper::getArrayColumn($item['data'], 'goods_id');
if (empty($goodsIds)) return [];
$goodsList = $model->getListByIdsFromApi($goodsIds);
} else {
// 数据来源:自动
$goodsList = $model->getList([
'status' => 10,
'categoryId' => $item['params']['auto']['category'],
'sortType' => $item['params']['auto']['goodsSort'],
], $item['params']['auto']['showNum']);
}
if ($goodsList->isEmpty()) return [];
// 格式化商品列表
$data = [];
foreach ($goodsList as $goods) {
$data[] = [
'goods_id' => $goods['goods_id'],
'goods_name' => $goods['goods_name'],
'selling_point' => $goods['selling_point'],
'goods_image' => $goods['goods_images'][0]['preview_url'],
'goods_price_min' => $goods['goods_price_min'],
'goods_price_max' => $goods['goods_price_max'],
'line_price_min' => $goods['line_price_min'],
'line_price_max' => $goods['line_price_max'],
'goods_sales' => $goods['goods_sales'],
];
}
return $data;
}
/**
* 优惠券组件:获取优惠券列表
* @param $item
* @return array|mixed
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getCouponList($item)
{
// 获取优惠券数据
return (new CouponModel)->getList($item['params']['limit'], true);
}
/**
* 文章组件:获取文章列表
* @param $item
* @return array
* @throws \think\db\exception\DbException
*/
private function getArticleList($item)
{
// 获取文章数据
$model = new Article;
$articleList = $model->getList($item['params']['auto']['category'], $item['params']['auto']['showNum']);
return $articleList->isEmpty() ? [] : $articleList->toArray()['data'];
}
/**
* 头条快报:获取头条列表
* @param $item
* @return array
* @throws \think\db\exception\DbException
*/
private function getSpecialList($item)
{
// 获取头条数据
$model = new Article;
$articleList = $model->getList($item['params']['auto']['category'], $item['params']['auto']['showNum']);
return $articleList->isEmpty() ? [] : $articleList->toArray()['data'];
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Partners as PartnersModel;
use app\common\library\helper;
use cores\exception\BaseException;
use think\cache\driver\Redis;
/**
* 产码模型
* Class Order
* @package app\api\model
*/
class Partners extends PartnersModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
}
@@ -0,0 +1,27 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\PartnersGoods as PartnersGoodsModel;
use app\common\library\helper;
use cores\exception\BaseException;
/**
* 用户优惠券模型
* Class PartnersGoods
* @package app\api\model
*/
class PartnersGoods extends PartnersGoodsModel
{
}
+25
View File
@@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Region as RegionModel;
/**
* 地区模型
* Class Region
* @package app\api\model
*/
class Region extends RegionModel
{
}
+33
View File
@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\store\Setting as SettingModel;
/**
* 系统设置模型
* Class Setting
* @package app\api\model
*/
class Setting extends SettingModel
{
/**
* 获取积分名称
* @return string
*/
public static function getPointsName()
{
return static::getItem('points')['points_name'];
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace app\api\controller;
use app\store\controller\Controller;
use app\common\exception\BaseException;
use think\Db;
/**
* 店铺控制器
* Class StoreUser
* @package app\store\controller
*/
class Shop extends Controller
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
}
+24
View File
@@ -0,0 +1,24 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Spec as SpecModel;
/**
* 规格/属性(组)模型
* Class Spec
* @package app\api\model
*/
class Spec extends SpecModel
{
}
+24
View File
@@ -0,0 +1,24 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\SpecValue as SpecValueModel;
/**
* 规格/属性(值)模型
* Class SpecValue
* @package app\api\model
*/
class SpecValue extends SpecValueModel
{
}
+55
View File
@@ -0,0 +1,55 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Store as StoreModel;
use think\model\relation\HasOne;
/**
* 商家记录表模型
* Class Store
* @package app\store\model
*/
class Store extends StoreModel
{
/**
* 隐藏的字段
* @var string[]
*/
protected $hidden = [
'sort',
'is_recycle',
'is_delete',
'create_time',
'update_time'
];
/**
* 关联logo图片
* @return HasOne
*/
public function logoImage(): HasOne
{
return $this->hasOne('UploadFile', 'file_id', 'logo_image_id')
->bind(['image_url' => 'preview_url']);
}
/**
* 获取当前商城的基本信息
* @return Store|array|null
*/
public static function getInfo()
{
return static::detail(static::$storeId);
}
}
+56
View File
@@ -0,0 +1,56 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\UploadFile as UploadFileModel;
/**
* 文件库模型
* Class UploadFile
* @package app\api\model
*/
class UploadFile extends UploadFileModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
];
/**
* 添加新记录
* @param array $data 文件信息
* @param int $fileType 文件类型
* @param int $userId 用户ID
* @return bool
*/
public function add(array $data, int $fileType, int $userId)
{
return $this->save([
'channel' => 20,
'storage' => $data['storage'],
'domain' => $data['domain'],
'file_name' => $data['file_name'],
'file_path' => $data['file_path'],
'file_size' => $data['file_size'],
'file_ext' => $data['file_ext'],
'file_type' => $fileType,
'uploader_id' => $userId,
'store_id' => self::$storeId
]);
}
}
+166
View File
@@ -0,0 +1,166 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\enum\user\balanceLog\Scene as SceneEnum;
use app\common\library\helper;
use app\store\model\user\BalanceLog as BalanceLogModel;
use think\facade\Cache;
use app\api\service\User as UserService;
use app\api\model\UserOauth as UserOauthModel;
use app\common\model\User as UserModel;
use cores\exception\BaseException;
use yiovo\captcha\facade\CaptchaApi;
/**
* 用户模型类
* Class User
* @package app\api\model
*/
class User extends UserModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'open_id',
'is_delete',
'store_id',
'create_time',
'update_time'
];
/**
* 获取器:隐藏手机号中间四位
* @param string $value
* @return string
*/
public function getMobileAttr(string $value): string
{
return strlen($value) === 11 ? hide_mobile($value) : $value;
}
/**
* 获取用户信息
* @param string $token
* @return User|array|false|null
* @throws BaseException
*/
public static function getUserByToken(string $token)
{
// 检查登录态是否存在
if (!Cache::has($token)) {
return false;
}
// 用户的ID
$userId = (int)Cache::get($token)['user']['user_id'];
// 用户基本信息
$userInfo = self::detail($userId);
if (empty($userInfo) || $userInfo['is_delete']) {
throwError('很抱歉,用户信息不存在或已删除', config('status.not_logged'));
}
// 获取用户关联的第三方用户信息(当前客户端)
try {
$userInfo['currentOauth'] = UserOauthModel::getOauth($userId, getPlatform());
} catch (\Throwable $e) {
throwError($e->getMessage());
}
return $userInfo;
}
/**
* 绑定手机号(当前登录用户)
* @param array $data
* @return bool
* @throws BaseException
*/
public function bindMobile(array $data): bool
{
// 当前登录的用户信息
$userInfo = UserService::getCurrentLoginUser(true);
// 验证绑定的手机号
$this->checkBindMobile($data);
// 更新手机号记录
return $userInfo->save(['mobile' => $data['mobile']]);
}
/**
* 修改个人信息(头像昵称)
* @param array $form
* @return bool
* @throws BaseException
*/
public function personal(array $form): bool
{
// 当前登录的用户信息
$userInfo = UserService::getCurrentLoginUser(true);
// 默认数据
$data['avatar_id'] = $form['avatarId'] ?: $userInfo['avatar_id'];
$data['nick_name'] = $form['nickName'] ?: $userInfo['nick_name'];
// 更新用户记录
return $userInfo->save($data);
}
/**
* 验证绑定的手机号
* @param array $data
* @return void
* @throws BaseException
*/
private function checkBindMobile(array $data): void
{
// 验证短信验证码是否匹配
if (!CaptchaApi::checkSms($data['smsCode'], $data['mobile'])) {
throwError('短信验证码不正确');
}
// 判断手机号是否已存在
if (static::checkExistByMobile($data['mobile'])) {
throwError('很抱歉,该手机号已绑定其他账户');
}
}
/**
* 用户充值:余额
* @param string $storeUserName
* @param array $data
* @return bool
*/
public function rechargeToBalance(string $storeUserName, array $data)
{
if (!isset($data['money']) || $data['money'] === '' || $data['money'] < 0) {
$this->error = '请输入正确的金额';
return false;
}
// 判断充值方式,计算最终金额
if ($data['mode'] === 'inc') {
$diffMoney = $data['money'];
} elseif ($data['mode'] === 'dec') {
$diffMoney = -$data['money'];
} else {
$diffMoney = helper::bcsub($data['money'], $this['balance']);
}
// 更新记录
$this->transaction(function () use ($storeUserName, $data, $diffMoney) {
// 更新账户余额
static::setIncBalance((int)$this['user_id'], (float)$diffMoney);
// 新增余额变动记录
BalanceLogModel::add(SceneEnum::SHARE, [
'user_id' => $this['user_id'],
'money' => (float)$diffMoney,
'remark' => $data['remark'],
], [$storeUserName]);
});
return true;
}
}
+180
View File
@@ -0,0 +1,180 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\model\User as UserModel;
use app\api\service\User as UserService;
use app\common\model\UserAddress as UserAddressModel;
use cores\exception\BaseException;
/**
* 用户收货地址模型
* Class UserAddress
* @package app\common\model
*/
class UserAddress extends UserAddressModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'is_delete',
'store_id',
'create_time',
'update_time'
];
// /**
// * 地区名称
// * @param $value
// * @param $data
// * @return array
// */
// public function getRegionAttr($value, $data)
// {
// return array_values(parent::getRegionAttr($value, $data));
// }
/**
* 获取收货地址列表
* @return \think\Collection
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws BaseException
*/
public function getList()
{
$userId = UserService::getCurrentLoginUserId();
return $this->where('user_id', '=', $userId)
->where('is_delete', '=', 0)
->select();
}
/**
* 新增收货地址
* @param array $data
* @return mixed
* @throws BaseException
*/
public function add(array $data)
{
// 当前用户信息
$user = UserService::getCurrentLoginUser(true);
// 省市区ID
[$data['province_id'], $data['city_id'], $data['region_id']] = $this->getRegionId($data);
// 添加收货地址
return $this->transaction(function () use ($user, $data) {
$this->save([
'name' => $data['name'],
'phone' => $data['phone'],
'province_id' => $data['province_id'],
'city_id' => $data['city_id'],
'region_id' => $data['region_id'],
'detail' => $data['detail'],
'user_id' => $user['user_id'],
'store_id' => self::$storeId
]);
// 设为默认收货地址
!$user['address_id'] && $this->setDefault((int)$this['address_id']);
return true;
});
}
/**
* 格式化用户上传的省市区数据
* @param array $data
* @return array
* @throws BaseException
*/
private function getRegionId(array $data)
{
if (!isset($data['region'])) {
throwError('省市区不能为空');
}
if (count($data['region']) != 3) {
throwError('省市区数据不合法');
}
return array_map(function ($item) {
return $item['value'];
}, $data['region']);
}
/**
* 编辑收货地址
* @param array $data
* @return bool
* @throws BaseException
*/
public function edit(array $data)
{
// 省市区ID
[$data['province_id'], $data['city_id'], $data['region_id']] = $this->getRegionId($data);
// 更新收货地址
return $this->save([
'name' => $data['name'],
'phone' => $data['phone'],
'province_id' => $data['province_id'],
'city_id' => $data['city_id'],
'region_id' => $data['region_id'],
'detail' => $data['detail']
]) !== false;
}
/**
* 设为默认收货地址
* @param int $addressIid
* @return bool
* @throws BaseException
*/
public function setDefault(int $addressIid)
{
// 设为默认地址
$userId = UserService::getCurrentLoginUserId();
return UserModel::updateBase(['address_id' => $addressIid], ['user_id' => $userId]);
}
/**
* 删除收货地址
* @return bool
* @throws BaseException
*/
public function remove()
{
// 查询当前是否为默认地址
$user = UserService::getCurrentLoginUser(true);
// 清空默认地址
if ($user['address_id'] == $this['address_id']) {
UserModel::updateBase(['address_id' => 0], ['user_id' => $this['user_id']]);
}
// 标记为已删除
return $this->save(['is_delete' => 1]);
}
/**
* 收货地址详情
* @param int $addressId
* @return UserAddress|array|null
* @throws BaseException
*/
public static function detail(int $addressId)
{
$userId = UserService::getCurrentLoginUserId();
$detail = self::get(['user_id' => $userId, 'address_id' => $addressId]);
if (empty($detail)) {
throwError('未找到该收货地址');
}
return $detail;
}
}
+206
View File
@@ -0,0 +1,206 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\service\User as UserService;
use app\api\model\Coupon as CouponModel;
use app\common\model\UserCoupon as UserCouponModel;
use app\common\enum\coupon\CouponType as CouponTypeEnum;
use app\common\enum\coupon\ApplyRange as ApplyRangeEnum;
use app\common\library\helper;
use cores\exception\BaseException;
/**
* 用户优惠券模型
* Class UserCoupon
* @package app\api\model
*/
class UserCoupon extends UserCouponModel
{
/**
* 获取用户优惠券列表
* @param int $userId
* @param array $param
* @return \think\Paginator
* @throws \think\db\exception\DbException
*/
public function getList(int $userId, array $param): \think\Paginator
{
$filter = $this->getFilter($param);
return $this->where($filter)
->where('user_id', '=', $userId)
->paginate(100);
}
/**
* 检索查询条件
* @param array $param
* @return array
*/
private function getFilter(array $param = []): array
{
// 设置默认查询参数
$params = $this->setQueryDefaultValue($param, [
'dataType' => 'all', // all:全部 isUsable:可用的 isExpire:已过期 isUse:已使用
'amount' => null, // 订单消费金额
]);
// 检索列表类型
$filter = [];
// 可用的优惠券
if ($params['dataType'] === 'isUsable') {
$filter[] = ['is_use', '=', 0];
$filter[] = ['is_expire', '=', 0];
$filter[] = ['start_time', '<=', time()];
$filter[] = ['end_time', '>', time()];
}
// 未使用的优惠券
if ($params['dataType'] === 'isUnused') {
$filter[] = ['is_use', '=', 0];
$filter[] = ['is_expire', '=', 0];
$filter[] = ['end_time', '>', time()];
}
// 已过期的优惠券
if ($params['dataType'] === 'isExpire') {
$filter[] = ['is_expire', '=', 1];
}
// 已使用的优惠券
if ($params['dataType'] === 'isUse') {
$filter[] = ['is_use', '=', 1];
}
// 订单消费金额
$params['amount'] > 0 && $filter[] = ['min_price', '<=', $params['amount']];
return $filter;
}
/**
* 获取用户优惠券总数量(可用)
* @param int $userId
* @return int
*/
public function getCount(int $userId): int
{
return $this->where('user_id', '=', $userId)
->where('is_use', '=', 0)
->where('is_expire', '=', 0)
->where('end_time', '>', time())
->count();
}
/**
* 获取用户优惠券ID集
* @param int $userId
* @return array
*/
public function getUserCouponIds(int $userId): array
{
return $this->where('user_id', '=', $userId)->column('coupon_id');
}
/**
* 领取优惠券
* @param int $couponId 优惠券ID
* @return bool
* @throws BaseException
*/
public function receive(int $couponId): bool
{
// 当前用户ID
$userId = UserService::getCurrentLoginUserId(true);
// 获取优惠券信息
$couponInfo = Coupon::detail($couponId);
// 验证优惠券是否可领取
if (!$this->checkReceive($userId, $couponInfo)) {
return false;
}
// 添加领取记录
return $this->add($userId, $couponInfo);
}
/**
* 验证优惠券是否可领取
* @param int $userId 当前用户ID
* @param CouponModel $couponInfo 优惠券详情
* @return bool
*/
private function checkReceive(int $userId, CouponModel $couponInfo): bool
{
if (empty($couponInfo)) {
$this->error = '当前优惠券不存在';
return false;
}
// 验证优惠券状态是否可领取
$model = new CouponModel;
if (!$model->checkReceive($couponInfo)) {
$this->error = $model->getError() ?: '优惠券状态不可领取';
return false;
}
// 验证当前用户是否已领取
if (static::checktUserCoupon($couponInfo['coupon_id'], $userId)) {
$this->error = '当前用户已领取该优惠券';
return false;
}
return true;
}
/**
* 订单结算优惠券列表
* @param int $userId 用户id
* @param float $orderPayPrice 订单商品总金额
* @return array
* @throws \think\db\exception\DbException
*/
public static function getUserCouponList(int $userId, float $orderPayPrice): array
{
// 获取用户可用的优惠券列表
$list = (new static)->getList($userId, ['dataType' => 'isUsable', 'amount' => $orderPayPrice]);
$data = $list->isEmpty() ? [] : $list->toArray()['data'];
foreach ($data as &$item) {
// 计算最大能折扣的金额
if ($item['coupon_type'] == CouponTypeEnum::DISCOUNT) {
$reducePrice = helper::bcmul($orderPayPrice, $item['discount'] / 10);
$item['reduced_price'] = helper::bcsub($orderPayPrice, $reducePrice);
} else {
$item['reduced_price'] = $item['reduce_price'];
}
}
// 根据折扣金额排序并返回
return !empty($data) ? array_sort($data, 'reduced_price', true) : [];
}
/**
* 判断当前优惠券是否满足订单使用条件
* @param array $couponList
* @param array $orderGoodsIds 订单商品ID集
* @return array
*/
public static function couponListApplyRange(array $couponList, array $orderGoodsIds): array
{
// 名词解释(is_apply):允许用于抵扣当前订单
foreach ($couponList as &$item) {
if ($item['apply_range'] == ApplyRangeEnum::ALL) {
// 1. 全部商品
$item['is_apply'] = true;
} elseif ($item['apply_range'] == ApplyRangeEnum::SOME) {
// 2. 指定商品, 判断订单商品是否存在可用
$applyGoodsIds = array_intersect($item['apply_range_config']['applyGoodsIds'], $orderGoodsIds);
$item['is_apply'] = !empty($applyGoodsIds);
} elseif ($item['apply_range'] == ApplyRangeEnum::EXCLUDE) {
// 2. 排除商品, 判断订单商品是否全部都在排除行列
$excludedGoodsIds = array_intersect($item['apply_range_config']['excludedGoodsIds'], $orderGoodsIds);
$item['is_apply'] = count($excludedGoodsIds) != count($orderGoodsIds);
}
!$item['is_apply'] && $item['not_apply_info'] = '该优惠券不支持当前商品';
}
return $couponList;
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\UserOauth as UserOauthModel;
/**
* 模型类:第三方用户信息
* Class UserOauth
* @package app\api\model
*/
class UserOauth extends UserOauthModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'is_delete',
'create_time',
'update_time',
];
/**
* 新增数据
* @param array $data
* @return bool
*/
public function add(array $data)
{
return $this->save($data);
}
}
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\article;
use app\common\model\article\Category as CategoryModel;
/**
* 文章分类模型
* Class Category
* @package app\api\model\article
*/
class Category extends CategoryModel
{
/**
* 获取分类列表(未隐藏的)
* @return \think\Collection
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getShowList()
{
$where = ['status', '=', 1];
return $this->getList([$where]);
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\card;
use app\api\service\User as UserService;
use app\common\model\card\CardLog as CardLogModel;
/**
* 兑换明细模型
* Class CardLog
* @package app\api\model\card
*/
class CardLog extends CardLogModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
];
/**
* 获取账单明细列表
* @return \think\Paginator
* @throws \app\common\exception\BaseException
* @throws \think\db\exception\DbException
*/
public function getList()
{
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 获取列表数据
return $this->where('user_id', '=', $userId)
->order(['create_time' => 'desc'])
->paginate(15);
}
}
@@ -0,0 +1,54 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\goods;
use app\common\model\goods\Service as ServiceModel;
use app\api\model\goods\ServiceRel as ServiceRelModel;
/**
* 商品服务与承诺模型
* Class Service
*/
class Service extends ServiceModel
{
// 隐藏的字段
protected $hidden = [
'is_default',
'status',
'sort',
'is_delete',
'store_id',
'update_time',
];
/**
* 获取指定商品的服务与承诺
* @param int $goodsId
* @return \think\Collection
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getListByGoods(int $goodsId)
{
// 获取指定商品的服务承诺id集
$serviceIds = ServiceRelModel::getServiceIds($goodsId);
// 获取服务与承诺列表
return $this->where('service_id', 'in', $serviceIds)
->where('status', '=', 1)
->where('is_delete', '=', 0)
->order(['sort', $this->getPk()])
->select();
}
}
@@ -0,0 +1,24 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\goods;
use app\common\model\goods\ServiceRel as ServiceRelModel;
/**
* 商品服务与承诺模型
* Class ServiceRel
*/
class ServiceRel extends ServiceRelModel
{
}
+35
View File
@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\h5;
use app\common\model\h5\Setting as SettingModel;
/**
* H5设置模型
* Class Setting
* @package app\api\model\h5
*/
class Setting extends SettingModel
{
/**
* 验证当前是否允许访问
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function checkStatus(): bool
{
return (bool)static::getItem('basic', static::$storeId)['enabled'];
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\order;
use app\common\model\order\Record as RecordModel;
use think\db\exception\DbException;
/**
* 分油通知记录模型
* Class Record
* @package app\api\model\order
*/
class Record extends RecordModel
{
/**
* 获取导出记录
* @return \think\Paginator
* @throws DbException
*/
public function getList(): \think\Paginator
{
// 获取列表记录
return $this->order(['create_time' => 'desc'])->paginate(10);
}
/**
* 新增数据
* @param $data
* @return bool
*/
public function add($data): bool
{
return $this->save($data);
}
}
+110
View File
@@ -0,0 +1,110 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\partners;
use app\common\model\partners\Order as OrderModel;
use app\api\model\PartnersGoods as PartnersGoodsModel;
use app\common\library\helper;
use cores\exception\BaseException;
/**
* 用户充值订单模型
* Class Order
* @package app\api\model\recharge
*/
class Order extends OrderModel
{
/**
* 保存订单记录
* @param $data
* @return bool|false|int
*/
public function saveOrder(array $data)
{
// 事务处理
$this->transaction(function () use ($data) {
// 写入订单记录
$this->save($data);
// 修改合作商商品库存
PartnersGoodsModel::setIncUseNum(['partners_id' => $data['partners_id'], 'goods_id' => $data['goods_id']], 1);
PartnersGoodsModel::setDecStockNum(['partners_id' => $data['partners_id'], 'goods_id' => $data['goods_id']], 1);
});
return true;
}
/**
* 获取用户订单列表
* @param array $params 条件
* @return \think\Paginator
* @throws \think\db\exception\DbException
* @throws BaseException
*/
public function getList(array $params = []): \think\Paginator
{
// 时间戳转换
$begin = \DateTime::createFromFormat('Ymd', $params['beginDate'])->setTime(0, 0, 0)->getTimestamp();
$end = \DateTime::createFromFormat('Ymd', $params['endDate'])->setTime(23, 59, 59)->getTimestamp();
// 组装筛选条件
$filter = [
['create_time', '>=', $begin],
['create_time', '<=', $end],
];
if (!empty($params['mobile'])) {
$filter[] = ['mobile', '=', $params['mobile']];
}
if (!empty($params['shareNo'])) {
$filter[] = ['shareNo', '=', $params['shareNo']];
}
if (!empty($params['saleOrderNo'])) {
$filter[] = ['partners_order_no', '=', $params['saleOrderNo']];
}
if (!empty($params['partners_id'])) {
$filter[] = ['partners_id', '=', $params['partners_id']];
}
// 查询列表数据
return $this->where($filter)
->order(['create_time' => 'desc'])
->paginate([
'list_rows' => $params['pageLimit'],
'page' => $params['pageNum']
]);
}
/**
* 获取当前用户订单数量
* @param array $filter 附件条件
* @param string $type 订单类型 (all全部 success已发券 used已使用)
* @return int
* @throws BaseException
*/
public function getCount(array $filter = [], string $type = 'all'): int
{
// 订单数据类型
switch ($type) {
case 'all':
break;
case 'success':
$filter['oil_status_zsy'] = 2;
break;
case 'used':
$filter['oil_status_zsy'] = 2;
$filter['use_status'] = 1;
break;
}
// 查询数据
return $this->where($filter)
->count();
}
}
+251
View File
@@ -0,0 +1,251 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\recharge;
use app\api\model\Setting as SettingModel;
use app\api\model\recharge\Plan as PlanModel;
use app\api\model\recharge\OrderPlan as OrderPlanModel;
use app\api\service\User as UserService;
use app\common\library\helper;
use app\common\model\recharge\Order as OrderModel;
use app\common\service\Order as OrderService;
use app\common\enum\recharge\order\PayStatus as PayStatusEnum;
use app\common\enum\recharge\order\RechargeType as RechargeTypeEnum;
use app\common\exception\BaseException;
/**
* 用户充值订单模型
* Class Order
* @package app\api\model\recharge
*/
class Order extends OrderModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'transaction_id',
'store_id',
'create_time',
'update_time',
];
/**
* 获取订单列表
* @return \think\Paginator
* @throws BaseException
* @throws \think\db\exception\DbException
*/
public function getList()
{
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 获取列表数据
return $this->where('user_id', '=', $userId)
->where('pay_status', '=', PayStatusEnum::SUCCESS)
->order(['create_time' => 'desc'])
->paginate(15);
}
/**
* 获取订单详情(待付款状态)
* @param $orderNo
* @return array|null|static
*/
public static function getPayDetail(string $orderNo)
{
return self::detail(['order_no' => $orderNo, 'pay_status' => PayStatusEnum::PENDING]);
}
/**
* 创建充值订单
* @param int|null $planId
* @param float $customMoney
* @return bool|int
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function createOrder(?int $planId = null, float $customMoney = 0.00)
{
// 确定充值方式
$rechargeType = $planId > 0 ? RechargeTypeEnum::PLAN : RechargeTypeEnum::CUSTOM;
// 验证用户输入
if (!$this->validateForm($rechargeType, $planId, $customMoney)) {
$this->error = $this->error ?: '数据验证错误';
return false;
}
// 获取订单数据
$data = $this->getOrderData($rechargeType, $planId, $customMoney);
// 记录订单信息
return $this->saveOrder($data);
}
/**
* 保存订单记录
* @param $data
* @return bool|false|int
*/
private function saveOrder(array $data)
{
// 写入订单记录
$this->save($data['order']);
// 记录订单套餐快照
if (!empty($data['plan'])) {
$PlanModel = new OrderPlanModel;
return $PlanModel->add($this['order_id'], $data['plan']);
}
return true;
}
/**
* 生成充值订单
* @param int $rechargeType 充值方式
* @param int $planId 方案ID
* @param float $customMoney 自定义金额
* @return array|array[]|bool
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getOrderData(int $rechargeType, int $planId, float $customMoney)
{
// 订单信息
$data = [
'order' => [
'user_id' => UserService::getCurrentLoginUserId(),
'order_no' => 'RC' . OrderService::createOrderNo(),
'recharge_type' => $rechargeType,
'gift_money' => 0.00,
'store_id' => self::$storeId,
],
'plan' => [] // 订单套餐快照
];
// 自定义金额充值
if ($rechargeType == RechargeTypeEnum::CUSTOM) {
$data = $this->createDataByCustom($data, $customMoney);
}
// 套餐充值
if ($rechargeType == RechargeTypeEnum::PLAN) {
$data = $this->createDataByPlan($data, $planId);
}
// 实际到账金额
$data['order']['actual_money'] = helper::bcadd($data['order']['pay_price'], $data['order']['gift_money']);
return $data;
}
/**
* 创建套餐充值订单数据
* @param array $order
* @param int $planId
* @return array
* @throws BaseException
*/
private function createDataByPlan(array $order, int $planId)
{
// 获取套餐详情
$planInfo = PlanModel::detail($planId);
if (empty($planInfo)) {
throwError('充值套餐不存在');
}
$order['plan'] = $planInfo;
$order['order']['plan_id'] = $planInfo['plan_id'];
$order['order']['gift_money'] = $planInfo['gift_money'];
$order['order']['pay_price'] = $planInfo['money'];
return $order;
}
/**
* 创建自定义充值订单数据
* @param array $order
* @param float $customMoney
* @return array|bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function createDataByCustom(array $order, float $customMoney)
{
// 用户支付金额
$order['order']['pay_price'] = $customMoney;
// 充值设置
$setting = SettingModel::getItem('recharge');
if ($setting['is_custom'] == false) {
return true;
}
// 根据自定义充值金额匹配满足的套餐
if ($setting['is_match_plan'] == true) {
$matchPlanInfo = (new PlanModel)->getMatchPlan($customMoney);
if (!empty($matchPlanInfo)) {
$order['plan'] = $matchPlanInfo;
$order['order']['plan_id'] = $matchPlanInfo['plan_id'];
$order['order']['gift_money'] = $matchPlanInfo['gift_money'];
}
}
return $order;
}
/**
* 表单验证
* @param int $rechargeType
* @param int $planId
* @param float $customMoney
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function validateForm(int $rechargeType, int $planId, float $customMoney)
{
if (empty($planId) && $customMoney <= 0) {
$this->error = '请选择充值套餐或输入充值金额';
return false;
}
// 验证自定义的金额
if ($rechargeType == RechargeTypeEnum::CUSTOM && !$this->validateFormCustom($customMoney)) {
return false;
}
return true;
}
/**
* 表单验证 [自定义充值]
* @param float $customMoney 充值金额
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function validateFormCustom(float $customMoney)
{
// 充值设置
$setting = SettingModel::getItem('recharge');
if ($setting['is_custom'] == false) {
$this->error = '很抱歉,当前不允许充值自定义金额';
return false;
}
if ($customMoney <= 0) {
$this->error = '请输入正确的充值金额';
return false;
}
// 验证最低充值金额
if (helper::bccomp($customMoney, $setting['lowest_money']) === -1) {
$this->error = "很抱歉,当前最低充值金额不能低于{$setting['lowest_money']}元";
return false;
}
return true;
}
}
@@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\recharge;
use app\common\model\recharge\OrderPlan as OrderPlanModel;
/**
* 用户充值订单套餐快照模型
* Class OrderPlan
* @package app\api\model\recharge
*/
class OrderPlan extends OrderPlanModel
{
/**
* 新增记录
* @param $orderId
* @param $data
* @return false|int
*/
public function add($orderId, $data)
{
return $this->save([
'order_id' => $orderId,
'plan_id' => $data['plan_id'],
'plan_name' => $data['plan_name'],
'money' => $data['money'],
'gift_money' => $data['gift_money'],
'store_id' => self::$storeId
]);
}
}
@@ -0,0 +1,67 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\recharge;
use app\common\model\recharge\Plan as PlanModel;
/**
* 用户充值订单模型
* Class Plan
* @package app\api\model\recharge
*/
class Plan extends PlanModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'sort',
'is_delete',
'store_id',
'create_time',
'update_time',
];
/**
* 获取可用的充值套餐列表
* @return \think\Collection
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getList()
{
// 获取列表数据
return $this->where('is_delete', '=', 0)
->order(['sort' => 'asc', 'money' => 'desc', 'create_time' => 'desc'])
->select();
}
/**
* 根据自定义充值金额匹配满足的套餐
* @param $payPrice
* @return array|\think\Model|null
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getMatchPlan($payPrice)
{
return (new static)->where('money', '<=', $payPrice)
->where('is_delete', '=', 0)
->order(['money' => 'desc'])
->find();
}
}
@@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\user;
use app\api\service\User as UserService;
use app\common\model\user\BalanceLog as BalanceLogModel;
/**
* 用户余额变动明细模型
* Class BalanceLog
* @package app\api\model\user
*/
class BalanceLog extends BalanceLogModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
];
/**
* 获取账单明细列表
* @return \think\Paginator
* @throws \app\common\exception\BaseException
* @throws \think\db\exception\DbException
*/
public function getList()
{
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 获取列表数据
return $this->where('user_id', '=', $userId)
->order(['create_time' => 'desc'])
->paginate(15);
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\user;
use app\common\model\user\Grade as GradeModel;
/**
* 用户会员等级模型
* Class Grade
* @package app\api\model\user
*/
class Grade extends GradeModel
{
}
@@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\user;
use app\common\model\user\GradeLog as GradeLogModel;
/**
* 用户会员等级变更记录模型
* Class GradeLog
* @package app\api\model\user
*/
class GradeLog extends GradeLogModel
{
}
@@ -0,0 +1,41 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\user;
use app\api\service\User as UserService;
use app\common\model\user\PointsLog as PointsLogModel;
/**
* 用户余额变动明细模型
* Class PointsLog
* @package app\api\model\user
*/
class PointsLog extends PointsLogModel
{
/**
* 获取日志明细列表
* @return \think\Paginator
* @throws \cores\exception\BaseException
* @throws \think\db\exception\DbException
*/
public function getList()
{
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 获取列表数据
return $this->where('user_id', '=', $userId)
->order(['create_time' => 'desc'])
->paginate(15);
}
}
@@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model\wxapp;
use app\common\model\wxapp\Setting as SettingModel;
/**
* 微信小程序设置模型
* Class Setting
* @package app\api\model\wxapp
*/
class Setting extends SettingModel
{
}