- 框架初始化
 - 安装插件
 - 修复PHP8.4报错
This commit is contained in:
2025-04-19 17:21:20 +08:00
commit c6a4e1f5f6
5306 changed files with 967782 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\Admin as BaseAdmin;
use addons\shopro\library\notify\traits\Notifiable;
class Admin extends BaseAdmin
{
use Notifiable;
/**
* 判断管理员是否由特定权限
*
* @param \think\Model $admin
* @param array $rules
* @return boolean
*/
public function hasAccess(\think\Model $admin, ?array $rules = [])
{
$auth = \app\admin\library\Auth::instance();
$RuleIds = $auth->getRuleIds($admin->id);
$is_super = in_array('*', $RuleIds) ? 1 : 0;
if ($is_super) {
return true;
}
if ($auth->check(implode(',', $rules), $admin->id)) {
return true;
}
return false;
}
/**
* 是否是超级管理员
*
* @param \think\Model $admin
* @return boolean
*/
public function isSuper(\think\Model $admin)
{
$auth = \app\admin\library\Auth::instance();
$RuleIds = $auth->getRuleIds($admin->id);
$is_super = in_array('*', $RuleIds) ? 1 : 0;
return $is_super;
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\goods\Goods;
use app\admin\model\shopro\goods\SkuPrice;
use addons\shopro\facade\Activity as ActivityFacade;
class Cart extends Common
{
protected $name = 'shopro_cart';
// 追加属性
protected $append = [
];
/**
* 获取器获取所有活动
*
* @param string $value
* @param array $data
* @return array
*/
public function getActivitiesAttr($value, $data)
{
$activities = ActivityFacade::getGoodsActivitys($data['id']);
return $activities;
}
public function getStatusAttr($value, $data)
{
$status = 'normal';
if (!$this->goods || !is_null($this->goods->deletetime) || !$this->sku_price) {
$status = 'deleted'; // 已删除
} else if ($this->goods->status == 'down' || $this->sku_price->status == 'down') {
$status = 'down'; // 已下架
}
return $status;
}
public function getTagsAttr($value, $data)
{
$tags = [
'activity' => [],
];
$activities = $this->activities;
foreach ($activities as $activity) {
$tags['activity'][] = $activity['type_text'] . $activity['status_text'];
}
if ($this->sku_price && $this->sku_price->price < $data['snapshot_price']) {
// 当前规格价格,低于加入购物车时候的价格,则提示商品比加入时降价
$tags['price'] = '距加入降 ¥ ' . bcsub($data['snapshot_price'], $this->sku_price->price, 2);
}
return $tags;
}
public function goods()
{
return $this->belongsTo(Goods::class, 'goods_id');
}
public function skuPrice()
{
return $this->belongsTo(SkuPrice::class, 'goods_sku_price_id');
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
class Category extends Common
{
protected $name = 'shopro_category';
// 追加属性
protected $append = [
'status_text',
];
public function getChildrenString($category)
{
$style = $category->style;
$string = 'children';
if (strpos($style, 'second') === 0) {
$string .= '.children';
} else if (strpos($style, 'third') === 0) {
$string .= '.children.children';
}
return $string;
}
public function children()
{
return $this->hasMany(self::class, 'parent_id', 'id')->normal()->order('weigh', 'desc')->order('id', 'asc');
}
}

View File

@@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
namespace app\admin\model\shopro;
use think\Model;
use addons\shopro\filter\BaseFilter;
use think\db\Query;
use app\admin\model\shopro\traits\ModelAttr;
class Common extends Model
{
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
protected $dateFormat = 'Y-m-d H:i:s';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = false;
use ModelAttr;
/**
* 当前 model 对应的 filter 实例
*
* @return BaseFilter
*/
public function filterInstance()
{
$filter_class = static::class;
$class = str_replace('app\admin\model\shopro', 'addons\shopro\filter', $filter_class) . 'Filter';
if (!class_exists($class)) {
return new BaseFilter();
}
return new $class();
}
/**
* 查询范围 filter 搜索入口
*
* @param Query $query
* @return void
*/
public function scopeSheepFilter($query, $sort = true, $filters = null)
{
$instance = $this->filterInstance();
$query = $instance->apply($query, $filters);
if ($sort) {
$query = $instance->filterOrder($query);
}
return $query;
}
/**
* 获取模型中文名
*
* @return string|null
*/
// public function getModelName()
// {
// if (isset($this->modelName)) {
// $model_name = $this->modelName;
// } else {
// $tableComment = $this->tableComment();
// $table_name = $this->getQuery()->getTable();
// $model_name = $tableComment[$table_name] ?? null;
// }
// return $model_name;
// }
}

View File

@@ -0,0 +1,192 @@
<?php
namespace app\admin\model\shopro;
class Config extends Common
{
/**
* 主键
*/
protected $pk = 'code';
protected $name = 'shopro_config';
protected $autoWriteTimestamp = false;
/**
* 获取配置组
*
* @param string $code
* @param boolean $cache
* @return array
*/
public static function getConfigs($code, $cache = true)
{
// 从缓存中获取
if ($cache) {
$config = operate_disabled(false) ? cache("config:{$code}") : null;
if (empty($config)) {
$config = self::getConfigs($code, false);
}
}
// 从数据库中查找
if (!$cache) {
$row = self::where('code', $code)->find();
if(!$row) return null;
if($row['type'] !== 'group') {
$config = $row->value;
}else {
$config = [];
$list = self::where('parent_code', $code)->select();
foreach ($list as &$row) {
if ($row['type'] === 'group') {
$row->value = self::getConfigs($row->code, false);
} else {
cache("config:{$row->code}", $row->value);
}
$config[self::getShortCode($row)] = $row->value;
}
}
// 设置配置缓存
cache("config:{$code}", $config);
}
return $config;
}
/**
* 获取单一配置项
*
* @param string $code
* @param boolean $cache
* @return mixed
*/
public static function getConfigField($code, $cache = true)
{
// 从缓存中获取
if ($cache) {
$config = cache("config:{$code}");
if (empty($config)) {
$config = self::getConfigField($code, false);
}
}
// 从数据库中查找
if (!$cache) {
$config = self::where('code', $code)->value('value');
// 设置配置缓存
cache("config:{$code}", $config);
}
return $config;
}
private static function getShortCode($config)
{
if (!empty($config['parent_code'])) {
return str_replace("{$config['parent_code']}.", "", $config['code']);
}
return $config['code'];
}
/**
* 更新配置
*
* @param string $code
* @param array $configParams
* @return void
*/
public static function setConfigs(string $code, ?array $configParams)
{
operate_filter();
foreach ($configParams as $configKey => $configValue) {
self::setConfigField($code . '.' . $configKey, $configValue);
}
self::getConfigs(explode('.', $code)[0], false);
return self::getConfigs($code);
}
/**
* 更新配置项
*/
private static function setConfigField($code, $value)
{
$config = self::where('code', $code)->find();
if ($config) {
if ($config['type'] === 'group') {
foreach ($value as $k => $v) {
self::setConfigField($code . '.' . $k, $v);
}
} else {
$config->value = $value;
$config->save();
}
}
}
/**
* 修改器 数据的保存格式
*
* @param string|array $value
* @param array $data
* @return string
*/
public function setValueAttr($value, $data)
{
switch ($data['type']) {
case 'array':
$value = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
break;
}
return $value;
}
/**
* 获取器,选项
*
* @param string|array $value
* @param array $data
* @return array
*/
public function getStoreRangeAttr($value, $data)
{
return $this->attrFormatJson($value, $data, 'store_range');
}
/**
* 获取器,返回的格式
*
* @param string|array $value
* @param array $data
* @return array
*/
public function getValueAttr($value, $data)
{
$value = $value ?: ($data['value'] ?? null);
switch ($data['type']) {
case 'array':
$value = $this->attrFormatJson($value, $data, 'value', true);
break;
case 'boolean':
$value = intval($value) ? 1 : 0;
break;
case 'int':
$value = intval($value);
break;
case 'float':
$value = floatval($value);
break;
}
return config_show($value, $data);
}
}

View File

@@ -0,0 +1,320 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\Coupon as UserCouponModel;
use app\admin\model\shopro\goods\Goods;
use app\admin\model\shopro\Category;
use traits\model\SoftDelete;
class Coupon extends Common
{
use SoftDelete;
protected $deleteTime = 'deletetime';
protected $name = 'shopro_coupon';
protected $type = [
'get_start_time' => 'timestamp',
'get_end_time' => 'timestamp',
// 'use_start_time' => 'timestamp',
// 'use_end_time' => 'timestamp',
];
// 追加属性
protected $append = [
'type_text',
'status_text',
'use_scope_text',
'amount_text',
'get_time_status',
'get_time_text'
];
/**
* 默认类型列表
*
* @return array
*/
public function typeList()
{
return [
'reduce' => '满减券',
'discount' => '折扣券'
];
}
/**
* 可用范围列表
*
* @return array
*/
public function useScopeList()
{
return [
'all_use' => '全场通用',
'goods' => '指定商品可用',
'disabled_goods' => '指定商品不可用',
'category' => '指定分类可用',
];
}
/**
* 默认状态列表
*
* @return array
*/
public function statusList()
{
return [
'normal' => '公开发放',
'hidden' => '后台发放',
'disabled' => '禁止使用',
];
}
/**
* 优惠券领取状态
*
* @return void
*/
public function getStatusList()
{
return [
'can_get' => '立即领取',
'cannot_get' => '已领取',
'get_over' => '已领完',
// 用户优惠券的状态
'used' => '已使用',
'can_use' => '立即使用',
'expired' => '已过期',
'cannot_use' => '暂不可用'
];
}
public function scopeCanGet($query)
{
return $query->where('get_start_time', '<=', time())
->where('get_end_time', '>=', time());
}
/**
* 查询指定商品满足的优惠券
*
* @param [type] $query
* @param [type] $goods
* @return void
*/
public function scopeGoods($query, $goods)
{
$goods_id = $goods['id'];
$category_ids = $goods['category_ids'];
// 查询符合商品的优惠券
return $query->where(function ($query) use ($goods_id, $category_ids) {
$query->where('use_scope', 'all_use')
->whereOr(function ($query) use ($goods_id) {
$query->where('use_scope', 'goods')->whereRaw("find_in_set($goods_id, items)");
})
->whereOr(function ($query) use ($goods_id) {
$query->where('use_scope', 'disabled_goods')->whereRaw("not find_in_set($goods_id, items)");
})
->whereOr(function ($query) use ($goods_id, $category_ids) {
$query->where('use_scope', 'category')->where(function ($query) use ($category_ids) {
$category_ids = array_filter(array_map('intval', explode(',', $category_ids)));
foreach ($category_ids as $key => $category_id) {
$query->whereOrRaw("find_in_set($category_id, items)");
}
});
});
});
}
/**
* 开始使用时间获取器
*
* @param string $value
* @param array $data
* @return int
*/
public function setUseStartTimeAttr($value, $data)
{
return $value ? strtotime($value) : (isset($data['use_start_time']) ? strtotime($data['use_start_time']) : 0);
}
/**
* 结束使用时间获取器
*
* @param string $value
* @param array $data
* @return int
*/
public function setUseEndTimeAttr($value, $data)
{
return $value ? strtotime($value) : (isset($data['use_end_time']) ? strtotime($data['use_end_time']) : 0);
}
/**
* 可用范围获取器
*
* @param string $value
* @param array $data
* @return string
*/
public function getUseScopeTextAttr($value, $data)
{
$value = $value ?: ($data['use_scope'] ?? null);
$list = $this->useScopeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getAmountTextAttr($value, $data)
{
return '满' . $data['enough'] . '元,' . ($data['type'] == 'reduce' ? '减' . floatval($data['amount']) . '元' : '打' . floatval($data['amount']) . '折');
}
public function getItemsValueAttr($value, $data)
{
if (in_array($data['use_scope'], ['goods', 'disabled_goods'])) {
$items_value = Goods::whereIn('id', $data['items'])->select();
$items_value = collection($items_value);
$items_value = $items_value->each(function ($goods) {
// 前端要显示活动标签
$goods->promos = $goods->promos;
});
} else {
$items_value = Category::whereIn('id', $data['items'])->select();
}
return $items_value ?? [];
}
public function getGetStatusAttr($value, $data)
{
$limit_num = $data['limit_num'] ?? 0;
// 不限制领取次数,或者限制次数,领取数量还没达到最大值
$get_status = (!$limit_num || ($limit_num && $limit_num > count($this->user_coupons))) ? 'can_get' : 'cannot_get';
if ($get_status == 'can_get' && $data['stock'] <= 0) {
$get_status = 'get_over'; // 已领完
}
$user_coupon_id = request()->param('user_coupon_id', 0);
if ($user_coupon_id) {
// 从我领取的优惠券进详情,覆盖 状态
$user = auth_user();
$userCoupon = UserCouponModel::where('user_id', ($user ? $user->id : 0))->find($user_coupon_id);
if ($userCoupon) {
$get_status = $userCoupon->status;
}
}
return $get_status;
}
public function getGetStatusTextAttr($value, $data)
{
$list = $this->getStatusList();
return isset($list[$this->get_status]) ? $list[$this->get_status] : '';
}
/**
* 后端发放状态
*
* @return string
*/
public function getGetTimeStatusAttr($value, $data) {
if ($data['get_start_time'] > time()) {
$time_text = 'nostart'; // 未开始
} else if ($data['get_start_time'] <= time() && $data['get_end_time'] >= time()) {
$time_text = 'ing';
} else if ($data['get_end_time'] < time()) {
$time_text = 'ended';
}
return $time_text;
}
/**
* 后端发放状态
*
* @return string
*/
public function getGetTimeTextAttr($value, $data)
{
if ($this->get_time_status == 'nostart') {
$time_text = '未开始'; // 未开始
} else if ($this->get_time_status == 'ing') {
$time_text = '发放中';
} else if ($this->get_time_status == 'ended') {
$time_text = '已结束';
}
return $time_text;
}
public function getGetNumAttr($value, $data)
{
return UserCouponModel::where('coupon_id', $data['id'])->count();
}
public function getUseNumAttr($value, $data)
{
return UserCouponModel::where('coupon_id', $data['id'])->whereNotNull('use_time')->count();
}
public function getUseStartTimeAttr($value, $data)
{
$use_start_time = $value ? date('Y-m-d H:i:s', $value) : null;
$user_coupon_id = request()->param('user_coupon_id', 0);
if ($user_coupon_id && $data['use_time_type'] == 'days') {
// 从我领取的优惠券进详情,覆盖 状态
$user = auth_user();
$userCoupon = UserCouponModel::cache(60)->where('user_id', ($user ? $user->id : 0))->find($user_coupon_id);
if ($userCoupon) {
$use_start_time = date('Y-m-d H:i:s', $userCoupon->getData('createtime') + ($this->start_days * 86400));
}
}
return $use_start_time;
}
public function getUseEndTimeAttr($value, $data)
{
$use_end_time = $value ? date('Y-m-d H:i:s', $value) : null;
$user_coupon_id = request()->param('user_coupon_id', 0);
if ($user_coupon_id && $data['use_time_type'] == 'days') {
// 从我领取的优惠券进详情,覆盖 状态
$user = auth_user();
$userCoupon = UserCouponModel::cache(60)->where('user_id', ($user ? $user->id : 0))->find($user_coupon_id);
if ($userCoupon) {
$use_end_time = date('Y-m-d H:i:s', $userCoupon->getData('createtime') + (($this->start_days + $this->days) * 86400));
}
}
return $use_end_time;
}
public function userCoupons()
{
$user = auth_user();
return $this->hasMany(UserCouponModel::class, 'coupon_id')->where('user_id', ($user ? $user->id : 0));
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User;
class Feedback extends Common
{
protected $name = 'shopro_feedback';
protected $type = [
'images' => 'json'
];
protected $append = [
'status_text'
];
/**
* 类型列表
*
* @return array
*/
public function statusList()
{
return ['0' => '待处理', '1' => '已处理'];
}
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id')->field('id, nickname, avatar, mobile');
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
class Pay extends Common
{
protected $name = 'shopro_pay';
// 追加属性
protected $append = [
'pay_type_text',
'status_text'
];
const PAY_STATUS_UNPAID = 'unpaid';
const PAY_STATUS_PAID = 'paid';
const PAY_STATUS_REFUND = 'refund';
public function statusList()
{
return [
self::PAY_STATUS_UNPAID => '未支付',
self::PAY_STATUS_PAID => '已支付',
self::PAY_STATUS_REFUND => '已退款'
];
}
public function payTypeList()
{
return [
'wechat' => '微信支付',
'alipay' => '支付宝',
'money' => '钱包支付',
'score' => '积分支付',
'offline' => '货到付款',
];
}
public function scopeTypeOrder($query) // scopeOrder 调用时候,和 order 排序方法冲突了
{
return $query->where('order_type', 'order');
}
public function scopeTypeTradeOrder($query)
{
return $query->where('order_type', 'trade_order');
}
public function scopePaid($query)
{
return $query->where('status', self::PAY_STATUS_PAID);
}
public function scopeIsMoney($query)
{
return $query->whereIn('pay_type', ['wechat', 'alipay', 'money']);
}
/**
* 通用类型获取器
*
* @param string $value
* @param array $data
* @return string
*/
public function getPayTypeTextAttr($value, $data)
{
$value = $value ?: ($data['pay_type'] ?? null);
$list = $this->payTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
class PayConfig extends Common
{
use SoftDelete;
protected $name = 'shopro_pay_config';
protected $deleteTime = 'deletetime';
protected $type = [
'params' => 'json',
];
// 追加属性
protected $append = [
'type_text',
'status_text'
];
protected $hidden = [
'params'
];
public function statusList()
{
return [
'normal' => '正常',
'disabled' => '禁用',
];
}
public function typeList()
{
return [
'wechat' => '微信支付',
'alipay' => '支付宝支付',
];
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
class Refund extends Common
{
protected $name = 'shopro_refund';
// 追加属性
protected $append = [
'status_text'
];
const STATUS_ING = 'ing';
const STATUS_COMPLETED = 'completed';
const STATUS_FAIL = 'fail';
public function statusList()
{
return [
self::STATUS_ING => '退款中',
self::STATUS_COMPLETED => '退款完成',
self::STATUS_FAIL => '退款失败'
];
}
public function refundTypeList()
{
return [
'back' => '原路退回',
'money' => '退回到余额'
];
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
class SearchHistory extends Common
{
protected $name = 'shopro_search_history';
protected $type = [
];
// 追加属性
protected $append = [
];
}

View File

@@ -0,0 +1,142 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User as UserModel;
use app\admin\model\shopro\goods\Goods as GoodsModel;
class Share extends Common
{
protected $updateTime = false;
protected $name = 'shopro_share';
protected $type = [
'ext' => 'json'
];
protected $append = [
'platform_text',
'from_text'
];
const FROM = ['forward' => '直接转发', 'poster' => '识别海报', 'link' => '分享链接'];
const PLATFORM = ['H5' => 'H5网页', 'WechatOfficialAccount' => '微信公众号网页', 'WechatMiniProgram' => '微信小程序', 'App' => 'APP'];
public function getPlatformTextAttr($value, $data)
{
$value = $value ?: ($data['platform'] ?? null);
return (self::PLATFORM)[$value] ?? $value;
}
public function getFromTextAttr($value, $data)
{
$value = $value ?: ($data['from'] ?? null);
return (self::FROM)[$value] ?? $value;
}
public static function log(Object $user, $params)
{
// 错误的分享参数
if (empty($params['spm'])) {
return false;
}
$shareId = $params['shareId'];
// 分享用户为空
if ($shareId <= 0) {
return false;
}
// 不能分享给本人
if ($shareId == $user->id) {
return false;
}
// 新用户不能分享给老用户 按需打开
// if($user->id < $shareId) {
// return false;
// }
$shareUser = UserModel::where('id', $shareId)->find();
// 分享人不存在
if (!$shareUser) {
return false;
}
// 5分钟内相同的分享信息不保存防止冗余数据
$lastShareLog = self::where([
'user_id' => $user->id
])->where('createtime', '>', time() - 300)->order('id desc')->find();
if ($lastShareLog && $lastShareLog->spm === $params['spm']) {
return $lastShareLog;
}
$memoText = '通过' . (self::FROM)[$params['from']] . '访问了';
if ($params['page'] == '/pages/index/index') {
$memoText .= '首页';
}
if ($params['page'] === '/pages/goods/index') {
$memoText .= '商品';
$goodsId = $params['query']['id'];
}
if ($params['page'] === '/pages/goods/groupon') {
$memoText .= '拼团商品';
$goodsId = $params['query']['id'];
}
if ($params['page'] === '/pages/goods/seckill') {
$memoText .= '秒杀商品';
$goodsId = $params['query']['id'];
}
if ($params['page'] === '/pages/activity/groupon/detail') {
$memoText .= '拼团活动';
}
if (!empty($goodsId)) {
$goods = GoodsModel::find($goodsId);
if ($goods) {
$memoText .= "[{$goods->title}]";
}
}
$ext = [
'image' => $goods->image ?? "",
'memo' => $memoText
];
$shareInfo = self::create([
'user_id' => $user->id,
'share_id' => $shareId,
'spm' => $params['spm'],
'page' => $params['page'],
'query' => http_build_query($params['query']),
'platform' => $params['platform'],
'from' => $params['from'],
'ext' => $ext
]);
$data = ['shareInfo' => $shareInfo];
\think\Hook::listen('user_share_after', $data);
return $shareInfo;
}
// -- commission code start --
public function agent()
{
return $this->belongsTo(\app\admin\model\shopro\commission\Agent::class, 'share_id', 'user_id');
}
// -- commission code end --
public function user()
{
return $this->belongsTo(UserModel::class, 'user_id', 'id');
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace app\admin\model\shopro;
class ThirdOauth extends Common
{
protected $name = 'shopro_third_oauth';
}

View File

@@ -0,0 +1,83 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User;
class Withdraw extends Common
{
protected $name = 'shopro_withdraw';
protected $type = [
'withdraw_info' => 'json'
];
// 追加属性
protected $append = [
'status_text',
'charge_rate_format',
'withdraw_info_hidden',
'withdraw_type_text'
];
public function statusList()
{
return [
-1 => '已拒绝',
0 => '待审核',
1 => '处理中',
2 => '已处理'
];
}
public function withdrawTypeList()
{
return [
'wechat' => '微信零钱',
'alipay' => '支付包账户',
'back' => '银行卡',
];
}
/**
* 类型获取器
*/
public function getWithdrawTypeTextAttr($value, $data)
{
$value = $value ?: ($data['withdraw_type'] ?? null);
$list = $this->withdrawTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getChargeRateFormatAttr($value, $data)
{
$value = $value ?: ($data['charge_rate'] ?? null);
return bcmul((string)$value, '100', 1) . '%';
}
public function getWithdrawInfoHiddenAttr($value, $data)
{
$withdraw_info = $value ?: ($this->withdraw_info ?? null);
foreach ($withdraw_info as $key => &$info) {
if (in_array($key, ['微信用户', '真实姓名'])) {
$info = string_hide($info, 2);
} elseif (in_array($key, ['银行卡号', '支付宝账户', '微信ID'])) {
$info = account_hide($info);
}
}
return $withdraw_info;
}
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id')->field('id, nickname, avatar, total_consume');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace app\admin\model\shopro;
use app\admin\model\shopro\Common;
class WithdrawLog extends Common
{
protected $name = 'shopro_withdraw_log';
}

View File

@@ -0,0 +1,407 @@
<?php
namespace app\admin\model\shopro\activity;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
use app\admin\model\shopro\goods\Goods;
use addons\shopro\facade\Activity as ActivityFacade;
use app\admin\model\shopro\activity\SkuPrice as ActivitySkuPriceModel;
class Activity extends Common
{
use SoftDelete;
protected $name = 'shopro_activity';
protected $deleteTime = 'deletetime';
protected $type = [
'rules' => 'json',
'prehead_time' => 'timestamp',
'start_time' => 'timestamp',
'end_time' => 'timestamp',
];
// 追加属性
protected $append = [
'status',
'status_text',
'type_text',
// 'end_time_unix' // 不需要了
];
public function classifies()
{
return [
'activity' => [
'groupon' => '拼团',
'groupon_ladder' => '阶梯拼团',
// 'groupon_lucky' => '幸运拼团',
'seckill' => '秒杀',
],
'promo' => [
'full_reduce' => '满减',
'full_discount' => '满折',
'full_gift' => '满赠',
'free_shipping' => '满邮',
],
'app' => [
'signin' => '签到'
]
];
}
public function typeList()
{
return [
'groupon' => '拼团',
'groupon_ladder' => '阶梯拼团',
// 'groupon_lucky' => '幸运拼团',
'seckill' => '秒杀',
'full_reduce' => '满减',
'full_discount' => '满折',
'full_gift' => '满赠',
'free_shipping' => '满邮',
'signin' => '签到',
];
}
/**
* 获取活动的互斥活动
*
* @param string $current_activity_type
* @return array
*/
public function getMutexActivityTypes($current_activity_type)
{
$activityTypes = [];
switch ($current_activity_type) {
case 'groupon':
$activityTypes = ['groupon'];
break;
case 'groupon_ladder':
$activityTypes = ['groupon_ladder'];
break;
case 'groupon_lucky':
$activityTypes = ['groupon_lucky'];
break;
case 'seckill':
$activityTypes = ['seckill'];
break;
case 'full_reduce':
$activityTypes = ['full_reduce', 'full_discount'];
break;
case 'full_discount':
$activityTypes = ['full_reduce', 'full_discount'];
break;
case 'free_shipping':
$activityTypes = ['free_shipping'];
break;
case 'full_gift':
$activityTypes = ['full_gift'];
break;
case 'signin':
$activityTypes = ['signin'];
break;
}
return $activityTypes;
}
/**
* 根据类型获取 classify
*
* @param string $type
* @return string
*/
public function getClassify($type)
{
$classifys = $this->classifies();
$activitys = array_keys($classifys['activity']);
$promos = array_keys($classifys['promo']);
$apps = array_keys($classifys['app']);
$classify = null;
if (in_array($type, $activitys)) {
$classify = 'activity';
} else if (in_array($type, $promos)) {
$classify = 'promo';
} else if (in_array($type, $apps)) {
$classify = 'app';
}
return $classify;
}
/**
* status 组合 (在thinkphp5 where Closure 中,不能直接使用 scope特殊场景下用来代替下面的 scopeNostart scopePrehead 等)
*
* @param [type] $query
* @param [type] $status
* @return void
*/
public function scopeStatusComb($query, $status)
{
return $query->where(function ($query) use ($status) {
foreach ($status as $st) {
$query->whereOr(function ($query) use ($st) {
switch($st) {
case 'nostart':
$query->where('start_time', '>', time());
break;
case 'prehead':
$query->where('prehead_time', '<=', time())->where('start_time', '>', time());
break;
case 'ing':
$query->where('start_time', '<=', time())->where('end_time', '>=', time());
break;
case 'show':
$query->where('prehead_time', '<=', time())->where('end_time', '>=', time());
break;
case 'ended':
$query->where('end_time', '<', time());
break;
default:
error_stop('status 状态错误');
}
});
}
});
}
/**
* 未开始的活动
*
* @param think\query\Query $query
* @return void
*/
public function scopeNostart($query)
{
return $query->where('start_time', '>', time());
}
/**
* 预售的活动
*
* @param think\query\Query $query
* @return void
*/
public function scopePrehead($query)
{
return $query->where('prehead_time', '<=', time())->where('start_time', '>', time());
}
/**
* 进行中的活动
*
* @param think\query\Query $query
* @return void
*/
public function scopeIng($query)
{
return $query->where('start_time', '<=', time())->where('end_time', '>=', time());
}
/**
* 已经开始预售,并且没有结束的活动
*
* @param think\query\Query $query
* @return void
*/
public function scopeShow($query)
{
return $query->where('prehead_time', '<=', time())->where('end_time', '>=', time());
}
/**
* 已经结束的活动
*
* @param think\query\Query $query
* @return void
*/
public function scopeEnded($query)
{
return $query->where('end_time', '<', time());
}
/**
* 修改器 classify
*
* @param string $value
* @param array $data
* @return integer|null
*/
public function setClassifyAttr($value, $data)
{
$classify = $value ?: ($data['classify'] ?? null);
if (!$classify) {
$type = $data['type'] ?? null; // 活动类型
$classify = $this->getClassify($type);
}
return $classify;
}
/**
* 修改器 预热时间
*
* @param string $value
* @param array $data
* @return integer|null
*/
public function setPreheadTimeAttr($value, $data)
{
// promo 类型 prehead_time 永远等于 start_time
$value = (isset($data['classify']) && $data['classify'] == 'promo') ? $data['start_time'] : ($value ?: $data['start_time']);
return $this->attrFormatUnix($value);
}
/**
* 修改器 开始时间
*
* @param string $value
* @return integer|null
*/
public function setStartTimeAttr($value)
{
return $this->attrFormatUnix($value);
}
/**
* 修改器 结束时间
*
* @param string $value
* @return integer|null
*/
public function setEndTimeAttr($value)
{
return $this->attrFormatUnix($value);
}
public function getStatusAttr($value, $data)
{
return $this->getStatusCode($data['prehead_time'], $data['start_time'], $data['end_time']);
}
public function getStatusTextAttr($value, $data)
{
return $this->getStatusText($this->status);
}
public function getGoodsListAttr($value, $data)
{
if ($data['goods_ids']) {
$goods = Goods::field('id,title,price,sales,image,status')->whereIn('id', $data['goods_ids'])->select();
$goods = collection($goods)->toArray(); // 全部转数组
$goodsIds = array_column($goods, 'id');
$activitySkuPrices = ActivitySkuPriceModel::where('activity_id', $data['id'])->whereIn('goods_id', $goodsIds)->order('id', 'asc')->select();
$activitySkuPrices = collection($activitySkuPrices)->toArray();
// 后台编辑活动时,防止不编辑规格无法提交问题
foreach ($goods as &$gd) {
// 处理 $gd['activity_sku_prices']
$gd['activity_sku_prices'] = [];
foreach ($activitySkuPrices as $skuPrice) {
if ($skuPrice['goods_id'] == $gd['id']) {
$gd['activity_sku_prices'][] = $skuPrice;
}
}
// 处理活动规格,数据
foreach ($gd['activity_sku_prices'] as $key => $skuPrice) {
$skuPrice = ActivityFacade::showSkuPrice($data['type'], $skuPrice);
$gd['activity_sku_prices'][$key] = $skuPrice;
}
}
}
return $goods ?? [];
}
public function getRulesAttr($value, $data)
{
$rules = $data['rules'] ? json_decode($data['rules'], true) : [];
$type = $data['type'];
// 获取各个活动规则相关的特殊数据
$rules = ActivityFacade::rulesInfo($type, $rules);
return $rules;
}
/**
* 通过时间判断活动状态
*
* @param integer $prehead_time 预热时间
* @param integer $start_time 开始时间
* @param integer $end_time 结束时间
* @return string
*/
public static function getStatusCode($prehead_time, $start_time, $end_time)
{
// 转为时间戳,(从 redis 中取出来的是 时间格式)
if (($prehead_time && $prehead_time > time()) || (!$prehead_time && $start_time > time())) {
$status = 'nostart'; // 未开始
} else if ($prehead_time && $prehead_time < time() && $start_time > time()) {
$status = 'prehead'; // 预热
} else if ($start_time < time() && $end_time > time()) {
$status = 'ing';
} else if ($end_time < time()) {
$status = 'ended';
}
return $status ?? 'ended';
}
/**
* 判断活动状态中文
*
* @param string $status 活动状态
* @return string
*/
public static function getStatusText($status)
{
if ($status == 'nostart') {
$status_text = '未开始';
} elseif ($status == 'prehead') {
$status_text = '预热中';
} elseif ($status == 'ing') {
$status_text = '进行中';
} elseif ($status == 'ended') {
$status_text = '已结束';
}
return $status_text ?? '已结束';
}
public function getEndTimeUnixAttr($value, $data)
{
return isset($data['end_time']) ? $this->getData('end_time') : 0;
}
public function activitySkuPrices()
{
return $this->hasMany(SkuPrice::class, 'activity_id');
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace app\admin\model\shopro\activity;
use app\admin\model\shopro\Common;
class GiftLog extends Common
{
protected $name = 'shopro_activity_gift_log';
protected $type = [
'rules' => 'json',
'errors' => 'json'
];
// 追加属性
protected $append = [
'type_text',
'status_text'
];
/**
* 默认状态列表
*
* @return array
*/
public function typeList()
{
return [
'coupon' => '优惠券',
'score' => '积分',
'money' => '余额',
'goods' => '商品',
];
}
/**
* 默认状态列表
*
* @return array
*/
public function statusList()
{
return [
'waiting' => '等待赠送',
'finish' => '赠送完成',
'fail' => '赠送失败',
];
}
public function scopeWaiting($query)
{
return $query->where('status', 'waiting');
}
public function scopeOpered($query)
{
return $query->whereIn('status', ['finish', 'fail']);
}
public function scopeFinish($query)
{
return $query->where('status', 'finish');
}
public function scopeFail($query)
{
return $query->where('status', 'fail');
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace app\admin\model\shopro\activity;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User;
use app\admin\model\shopro\goods\Goods;
use app\admin\model\shopro\order\OrderItem;
class Groupon extends Common
{
protected $name = 'shopro_activity_groupon';
protected $type = [
'finish_time' => 'timestamp',
'expire_time' => 'timestamp'
];
// 追加属性
protected $append = [
'status_text',
];
public function statusList()
{
return [
'invalid' => '拼团失败',
'ing' => '进行中',
'finish' => '已成团',
'finish_fictitious' => '虚拟成团',
];
}
/**
* 查询正在进行中的团
*/
public function scopeIng($query)
{
return $query->where('status', 'ing');
}
public function getStatusTextAttr($value, $data)
{
$value = $value ?: ($data['status'] ?? '');
$list = $this->statusList();
$value = ($value == 'finish_fictitious' && strpos(request()->url(), 'addons/shopro') !== false) ? 'finish' : $value;
return isset($list[$value]) ? $list[$value] : '';
}
public function getExpireTimeUnixAttr($value, $data)
{
return isset($data['expire_time']) ? $this->getData('expire_time') : 0;
}
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function goods()
{
return $this->belongsTo(Goods::class, 'goods_id', 'id');
}
public function activity()
{
return $this->belongsTo(Activity::class, 'activity_id', 'id');
}
public function grouponLogs()
{
return $this->hasMany(GrouponLog::class, 'groupon_id', 'id');
}
public function leader()
{
return $this->hasOne(GrouponLog::class, 'groupon_id', 'id')->where('is_leader', 1);
}
/**
* 前端拼团详情用
*
* @return void
*/
public function my()
{
$user = auth_user();
return $this->hasOne(GrouponLog::class, 'groupon_id', 'id')->where('user_id', ($user ? $user->id : 0))->where('is_fictitious', 0);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace app\admin\model\shopro\activity;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User;
use app\admin\model\shopro\goods\Goods;
use app\admin\model\shopro\order\Order;
use app\admin\model\shopro\order\OrderItem;
class GrouponLog extends Common
{
protected $name = 'shopro_activity_groupon_log';
public function getNicknameAttr($value, $data)
{
$value = $value ?: ($data['nickname'] ?? '');
return $value ? string_hide($value, 2) : $value;
}
public function order()
{
return $this->belongsTo(Order::class, 'order_id');
}
public function groupon()
{
return $this->belongsTo(Groupon::class, 'groupon_id');
}
public function goods()
{
return $this->belongsTo(Goods::class, 'goods_id');
}
public function orderItem()
{
return $this->hasOne(OrderItem::class, 'order_id', 'order_id');
}
}

View File

@@ -0,0 +1,93 @@
<?php
namespace app\admin\model\shopro\activity;
use app\admin\model\shopro\Common;
use addons\shopro\facade\Activity as ActivityFacade;
class Order extends Common
{
protected $name = 'shopro_activity_order';
protected $type = [
'ext' => 'json',
];
// 追加属性
protected $append = [
'status_text',
'activity_type_text',
'discount_text'
];
const STATUS_UNPAID = 'unpaid';
const STATUS_PAID = 'paid';
public function statusList()
{
return [
'unpaid' => '未支付',
'paid' => '已支付',
];
}
// 未支付
public function scopeUnpaid($query)
{
return $query->where('status', self::STATUS_UNPAID);
}
// 已支付
public function scopePaid($query)
{
return $query->whereIn('status', [self::STATUS_PAID]);
}
public function getActivityTypeTextAttr($value, $data)
{
$value = $value ?: ($data['activity_type'] ?? null);
$ext = $this->ext;
$list = (new Activity)->typeList();
$text = isset($list[$value]) ? $list[$value] : '';
if (in_array($value, ['groupon', 'groupon_ladder'])) {
if (in_array($data['status'], [self::STATUS_PAID]) && (!isset($ext['groupon_id']) || !$ext['groupon_id'])) {
// 已支付,并且没有团 id,就是单独购买
$text .= '-单独购买';
}
}
return $text;
}
public function getDiscountTextAttr($value, $data)
{
$ext = $this->ext;
$discount_text = '';
if ($ext && isset($ext['rules']) && $ext['rules']) {
$tags = ActivityFacade::formatRuleTags([
'type' => $ext['rules']['rule_type'],
'discounts' => [$ext['rules']['discount_rule']]
], $data['activity_type']);
$discount_text = $tags[0] ?? '';
}
return $discount_text ?: $this->activity_type_text;
}
public function getGoodsIdsAttr($value, $data)
{
return $this->attrFormatComma($value, $data, 'goods_ids', true);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace app\admin\model\shopro\activity;
use app\admin\model\shopro\Common;
class Signin extends Common
{
protected $name = 'shopro_activity_signin';
protected $type = [
'rules' => 'json'
];
// 追加属性
protected $append = [
];
}

View File

@@ -0,0 +1,128 @@
<?php
namespace app\admin\model\shopro\activity;
use app\admin\model\shopro\Common;
class SkuPrice extends Common
{
protected $name = 'shopro_activity_sku_price';
protected $type = [
'ext' => 'json',
];
// 追加属性
protected $append = [
'status_text',
];
/**
* 普通拼团,团长价
*
* @param string $value
* @param array $data
* @return string
*/
public function getLeaderPriceAttr($value, $data)
{
$ext = $data['ext'];
$is_leader_discount = $ext['is_leader_discount'] ?? 0;
$leader_price = $ext['leader_price'] ?? 0;
$leader_price = $is_leader_discount ? $leader_price : $data['price'];
return $leader_price;
}
private function currentLadder($data, $level, $is_leader = false)
{
$ext = $data['ext'];
$is_leader_discount = $ext['is_leader_discount'] ?? 0;
$ladders = $ext['ladders'] ?? [];
$ladders = array_column($ladders, null, 'ladder_level');
$currentLadder = $ladders[$level] ?? []; // 当前阶梯的 价格数据
$key = ($is_leader && $is_leader_discount) ? 'leader_ladder_price' : 'ladder_price';
return $currentLadder[$key] ?? 0;
}
/**
* 阶梯拼团,第一阶梯价
*
* @param string $value
* @param array $data
* @return string
*/
public function getLadderOneAttr($value, $data)
{
return $this->currentLadder($data, 'ladder_one');
}
/**
* 阶梯拼团,第二阶梯价
*
* @param string $value
* @param array $data
* @return string
*/
public function getLadderTwoAttr($value, $data)
{
return $this->currentLadder($data, 'ladder_two');
}
/**
* 阶梯拼团,第二阶梯价
*
* @param string $value
* @param array $data
* @return string
*/
public function getLadderThreeAttr($value, $data)
{
return $this->currentLadder($data, 'ladder_three');
}
/**
* 阶梯拼团,第一阶梯团长价
*
* @param string $value
* @param array $data
* @return string
*/
public function getLadderOneLeaderAttr($value, $data)
{
return $this->currentLadder($data, 'ladder_one', true);
}
/**
* 阶梯拼团,第二阶团长梯价
*
* @param string $value
* @param array $data
* @return string
*/
public function getLadderTwoLeaderAttr($value, $data)
{
return $this->currentLadder($data, 'ladder_two', true);
}
/**
* 阶梯拼团,第二阶团长梯价
*
* @param string $value
* @param array $data
* @return string
*/
public function getLadderThreeLeaderAttr($value, $data)
{
return $this->currentLadder($data, 'ladder_three', true);
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace app\admin\model\shopro\app;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
use app\admin\model\shopro\goods\SkuPrice;
class ScoreSkuPrice extends Common
{
use SoftDelete;
protected $name = 'shopro_score_sku_price';
protected $deleteTime = 'deletetime';
protected $type = [
];
// 追加属性
protected $append = [
];
public function getGoodsSkuIdsAttr($value, $data)
{
$skuPrice = $this->sku_price;
return $skuPrice ? $skuPrice->goods_sku_ids : '';
}
public function getGoodsSkuTextAttr($value, $data)
{
$skuPrice = $this->sku_price;
return $skuPrice ? $skuPrice->goods_sku_text : '';
}
public function getImageAttr($value, $data)
{
$skuPrice = $this->sku_price;
return $skuPrice ? $skuPrice->image : '';
}
/**
* 积分加现金
*
* @param string $value
* @param array $data
* @return string
*/
public function getScorePriceAttr($value, $data)
{
$score = $data['score'] ?? 0;
$price = $data['price'] ?? 0;
return $score . '积分' . ($price ? '+¥' . $price : '');
}
public function skuPrice() {
return $this->belongsTo(SkuPrice::class, 'goods_sku_price_id');
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace app\admin\model\shopro\app\mplive;
use app\admin\model\shopro\Common;
class Goods extends Common
{
protected $name = 'shopro_mplive_goods';
protected $append = [
'audit_status_text',
'type_text',
'price_type_text',
];
/**
* 类型列表
*
* @return array
*/
public function typeList()
{
return [0 => '我的小程序', 1 => '其他小程序'];
}
public function auditStatusList()
{
return [0 => '未审核', 1 => '审核中', 2 => '审核通过', 3 => '审核失败'];
}
public function priceTypeList()
{
return [1 => '一口价', 2 => '价格区间', 3 => '折扣价'];
}
public function getPriceTypeTextAttr($value, $data)
{
$value = $value ?: ($data['price_type'] ?? null);
$list = $this->priceTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getAuditStatusTextAttr($value, $data)
{
$value = $value ?: ($data['audit_status'] ?? null);
$list = $this->auditStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
}

View File

@@ -0,0 +1,99 @@
<?php
namespace app\admin\model\shopro\app\mplive;
use app\admin\model\shopro\Common;
class Room extends Common
{
protected $name = 'shopro_mplive_room';
protected $append = [
'status_text',
'type_text',
];
const ERR_CODE = [
-1 => '系统错误',
1 => '未创建直播间',
1003 => '商品 id 不存在',
47001 => '入参格式不符合规范',
200002 => '入参错误',
300001 => '禁止创建/更新商品 或 禁止编辑/更新房间',
300002 => '名称长度不符合规则',
300003 => '价格输入不合规(如:现价比原价大、传入价格非数字等)',
300004 => '商品名称存在违规违法内容',
300005 => '商品图片存在违规违法内容',
300006 => ' 图片上传失败mediaID过期',
300007 => '线上小程序版本不存在该链接',
300008 => '添加商品失败',
300009 => '商品审核撤回失败',
300010 => '商品审核状态不对(如:商品审核中)',
300011 => '操作非法API不允许操作非 API 创建的商品)',
300012 => '没有提审额度每天500次提审额度',
300013 => '提审失败',
300014 => '审核中,无法删除(非零代表失败)',
300017 => '商品未提审',
300018 => '商品图片尺寸过大',
300021 => '商品添加成功,审核失败',
300022 => '此房间号不存在',
300023 => '房间状态 拦截(当前房间状态不允许此操作)',
300024 => '商品不存在',
300025 => '商品审核未通过',
300026 => '房间商品数量已经满额',
300027 => '导入商品失败',
300028 => '房间名称违规',
300029 => '主播昵称违规',
300030 => '主播微信号不合法',
300031 => '直播间封面图不合规',
300032 => '直播间分享图违规',
300033 => '添加商品超过直播间上限',
300034 => '主播微信昵称长度不符合要求',
300035 => '主播微信号不存在',
300036 => '主播微信号未实名认证',
300037 => '购物直播频道封面图不合规',
300038 => '未在小程序管理后台配置客服',
300039 => '主播副号微信号不合法',
300040 => '名称含有非限定字符(含有特殊字符)',
300041 => '创建者微信号不合法',
300042 => '推流中禁止编辑房间',
300043 => '每天只允许一场直播开启关注',
300044 => '商品没有讲解视频',
300045 => '讲解视频未生成',
300046 => '讲解视频生成失败',
300047 => '已有商品正在推送,请稍后再试',
300048 => '拉取商品列表失败',
300049 => '商品推送过程中不允许上下架',
300050 => '排序商品列表为空',
300051 => '解析 JSON 出错',
300052 => '已下架的商品无法推送',
300053 => '直播间未添加此商品',
500001 => '副号不合规',
500002 => '副号未实名',
500003 => '已经设置过副号了,不能重复设置',
500004 => '不能设置重复的副号',
500005 => '副号不能和主号重复',
600001 => '用户已被添加为小助手',
600002 => '找不到用户',
9410000 => '直播间列表为空',
9410001 => '获取房间失败',
9410002 => '获取商品失败',
9410003 => '获取回放失败',
];
/**
* 类型列表
*
* @return array
*/
public function typeList()
{
return [0 => '手机直播', 1 => '推流'];
}
public function statusList()
{
return [101 => '直播中', 102 => '未开始', 103 => '已结束', 104 => '禁播', 105 => '暂停', 106 => '异常', 107 => '已过期'];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace app\admin\model\shopro\chat;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\chat\traits\ChatCommon;
class CommonWord extends Common
{
use ChatCommon;
protected $name = 'shopro_chat_common_word';
protected $append = [
'status_text',
'room_name'
];
public function scopeRoomId($query, $room_id)
{
return $query->where('room_id', $room_id);
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace app\admin\model\shopro\chat;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\chat\Record;
use app\admin\model\shopro\chat\CustomerServiceUser;
use app\admin\model\shopro\chat\traits\ChatCommon;
class CustomerService extends Common
{
use ChatCommon;
protected $name = 'shopro_chat_customer_service';
protected $append = [
'auth_model',
'auth_text',
'status_text',
'room_name'
];
// 自动数据类型转换
protected $type = [
'last_time' => 'timestamp',
];
public function statusList()
{
return ['offline' => '离线', 'online' => '在线', 'busy' => '忙碌'];
}
public function getAuthModelAttr($value, $data)
{
return $this->customer_service_user['auth_model'] ?? null;
}
public function getAuthTextAttr($value, $data)
{
return $this->customer_service_user['auth_text'] ?? null;
}
public function customerService()
{
return $this->morphMany(Record::class, ['sender_identify', 'sender_id'], 'customer_service');
}
public function customerServiceUser()
{
return $this->HasOne(CustomerServiceUser::class, 'customer_service_id');
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace app\admin\model\shopro\chat;
use app\admin\model\Admin;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\chat\CustomerService;
use app\admin\model\shopro\user\User as ShopUser;
class CustomerServiceUser extends Common
{
protected $name = 'shopro_chat_customer_service_user';
protected $append = [
'auth_model',
'auth_text'
];
public static $authType = [
'admin' => ['name' => '管理员', 'value' => 'admin'],
'user' => ['name' => '用户', 'value' => 'user'],
];
public function scopeAuthAdmin($query, $admin_id)
{
return $query->where('auth', 'admin')->where('auth_id', $admin_id);
}
public function scopeAuthUser($query, $user_id)
{
return $query->where('auth', 'user')->where('auth_id', $user_id);
}
public function getAuthModelAttr($value, $data)
{
return $this->{$data['auth']};
}
public function getAuthTextAttr($value, $data)
{
return self::$authType[$data['auth']]['name'] ?? '';
}
public function admin()
{
return $this->belongsTo(Admin::class, 'auth_id');
}
public function customerService()
{
return $this->belongsTo(CustomerService::class, 'customer_service_id');
}
public function user()
{
return $this->belongsTo(ShopUser::class, 'auth_id');
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace app\admin\model\shopro\chat;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\chat\traits\ChatCommon;
class Question extends Common
{
use ChatCommon;
protected $name = 'shopro_chat_question';
protected $append = [
'status_text',
'room_name'
];
public function scopeRoomId($query, $room_id)
{
return $query->where('room_id', $room_id);
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace app\admin\model\shopro\chat;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\chat\traits\ChatCommon;
class Record extends Common
{
use ChatCommon;
protected $name = 'shopro_chat_record';
protected $append = [
'room_name'
];
// 不格式化创建更新时间
protected $dateFormat = false;
public function scopeCustomer($query)
{
return $query->where('sender_identify', 'customer');
}
public function scopeCustomerService($query)
{
return $query->where('sender_identify', 'customer_service');
}
public function scopeNoRead($query)
{
return $query->whereNull('read_time');
}
public function setMessageAttr($value, $data)
{
switch ($data['message_type']) {
case 'order':
case 'goods':
$value = is_array($value) ? json_encode($value) : $value;
break;
default :
$value = $value;
}
return $value;
}
/**
* 处理消息
*
* @param string $value
* @param array $data
* @return string
*/
public function getMessageAttr($value, $data)
{
switch($data['message_type']) {
case 'order':
case 'goods':
$message = json_decode($value, true);
break;
default :
$message = $value;
break;
}
// if ($data['message_type'] == 'image') {
// $message = Online::cdnurl($value);
// } else if (in_array($data['message_type'], ['order', 'goods'])) {
// $messageArr = json_decode($value, true);
// if (isset($messageArr['image']) && $messageArr['image']) {
// $messageArr['image'] = Online::cdnurl($messageArr['image']);
// }
// $message = json_encode($messageArr);
// } else if ($data['message_type'] == 'text') {
// // 全文匹配图片拼接 cdnurl
// $url = Online::cdnurl('/uploads');
// $message = str_replace("<img src=\"/uploads", "<img style=\"width: 100%;!important\" src=\"" . $url, $value);
// } else {
// $message = $value;
// }
return $message;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace app\admin\model\shopro\chat;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\chat\traits\ChatCommon;
class ServiceLog extends Common
{
use ChatCommon;
protected $name = 'shopro_chat_service_log';
protected $append = [
'room_name'
];
public function chatUser()
{
return $this->belongsTo(User::class, 'chat_user_id');
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace app\admin\model\shopro\chat;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User as ShopUser;
class User extends Common
{
protected $name = 'shopro_chat_user';
// 自动数据类型转换
protected $type = [
'last_time' => 'timestamp',
];
public function customer()
{
return $this->morphMany(Record::class, ['sender_identify', 'sender_id'], 'customer');
}
public function user()
{
return $this->belongsTo(ShopUser::class, 'auth_id');
}
public function customerService()
{
return $this->belongsTo(CustomerService::class, 'customer_service_id');
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace app\admin\model\shopro\chat\traits;
trait ChatCommon
{
/**
* 默认房间
*
* @var array
*/
public static function defaultRooms()
{
return [
['name' => '总后台', 'value' => 'admin'],
// ['name' => '官网', 'value' => 'official'],
// ['name' => '商城', 'value' => 'shop']
];
}
public function getRoomNameAttr($value, $data)
{
$value = $value ?: ($data['room_id'] ?? null);
$list = array_column(self::defaultRooms(), null, 'value');
return isset($list[$value]) ? $list[$value]['name'] : $value;
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace app\admin\model\shopro\commission;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User;
class Agent extends Common
{
protected $pk = 'user_id';
protected $name = 'shopro_commission_agent';
protected $type = [
'become_time' => 'timestamp',
'apply_info' => 'json',
'child_agent_level_1' => 'json',
'child_agent_level_all' => 'json',
];
protected $append = [
'status_text',
'pending_reward'
];
// 分销商状态 AGENT_STATUS
const AGENT_STATUS_NORMAL = 'normal'; // 正常
const AGENT_STATUS_PENDING = 'pending'; // 审核中 不分佣、不打款、没有团队信息
const AGENT_STATUS_FREEZE = 'freeze'; // 冻结 正常记录分佣、不打款,记录业绩和团队信息 冻结解除后立即打款
const AGENT_STATUS_FORBIDDEN = 'forbidden'; // 禁用 不分佣、不记录业绩和团队信息
const AGENT_STATUS_NEEDINFO = 'needinfo'; // 需要完善表单资料 临时状态
const AGENT_STATUS_REJECT = 'reject'; // 审核驳回, 重新修改 临时状态
const AGENT_STATUS_NULL = NULL; // 未满足成为分销商条件
// 分销商升级锁 UPGRADE_LOCK
const UPGRADE_LOCK_OPEN = 1; // 禁止分销商升级
const UPGRADE_LOCK_CLOSE = 0; // 允许分销商升级
public function statusList()
{
return [
'normal' => '正常',
'pending' => '审核中',
'freeze' => '冻结',
'forbidden' => '禁用',
'reject' => '拒绝'
];
}
/**
* 可用分销商
*/
public function scopeAvaliable($query)
{
return $query->where('status', 'in', [self::AGENT_STATUS_NORMAL, self::AGENT_STATUS_FREEZE]);
}
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id')->field('id, nickname, avatar, mobile, total_consume, parent_user_id');
}
public function levelInfo()
{
return $this->belongsTo(Level::class, 'level', 'level')->field(['level', 'name', 'image', 'commission_rules']);
}
public function getPendingRewardAttr($value, $data)
{
$amount = Reward::pending()->where('agent_id', $data['user_id'])->sum('commission');
return number_format($amount, 2, '.', '');
}
public function levelStatusInfo()
{
return $this->belongsTo(Level::class, 'level_status', 'level');
}
public function upgradeLevel()
{
return $this->belongsTo(Level::class, 'level_status', 'level');
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace app\admin\model\shopro\commission;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\goods\Goods as GoodsModel;
class CommissionGoods extends Common
{
protected $pk = 'goods_id';
protected $name = 'shopro_commission_goods';
protected $autoWriteTimestamp = false;
// 分销状态
const GOODS_COMMISSION_STATUS_OFF = 0; // 商品不参与分佣
const GOODS_COMMISSION_STATUS_ON = 1; // 商品参与分佣
const GOODS_COMMISSION_RULES_DEFAULT = 0; // 默认分销规则 只看系统分销商等级规则
const GOODS_COMMISSION_RULES_SELF = 1; // 独立分销规则 等级规则对应多种规格规则
const GOODS_COMMISSION_RULES_BATCH = 2; // 批量分销规则 只看保存的各分销商等级规则
protected $type = [
'commission_rules' => 'json'
];
protected $append = [
'status_text'
];
public function statusList()
{
return [
0 => '不参与',
1 => '参与中'
];
}
public function getCommissionConfigAttr($value, $data)
{
return json_decode($value, true);
}
public function goods()
{
return $this->belongsTo(GoodsModel::class, 'goods_id', 'id');
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace app\admin\model\shopro\commission;
use app\admin\model\shopro\Common;
class Level extends Common
{
protected $pk = 'level';
protected $name = 'shopro_commission_level';
protected $autoWriteTimestamp = false;
protected $type = [
'commission_rules' => 'json',
'upgrade_rules' => 'json'
];
}

View File

@@ -0,0 +1,232 @@
<?php
namespace app\admin\model\shopro\commission;
use app\admin\model\shopro\Common;
use addons\shopro\library\Operator;
use app\admin\model\shopro\user\User as UserModel;
class Log extends Common
{
protected $name = 'shopro_commission_log';
protected $updateTime = false;
protected $append = [
'event_text',
'oper_type_text'
];
/**
* 添加分销记录
*
* @param object $agentId 分销商ID
* @param string $event 事件类型
* @param array $ext 扩展信息
* @param object $oper 操作人
* @param string $remark 自定义备注
*
*/
public static function add($agentId, $event, $ext = [], $oper = NULL, $remark = '')
{
if ($remark === '') {
switch ($event) {
case 'agent':
$remark = self::setAgentEvent($ext);
break;
case 'share':
$remark = self::setShareEvent($ext);
break;
case 'bind':
$remark = self::setBindEvent($ext);
break;
case 'order':
$remark = self::setOrderEvent($ext);
break;
case 'reward':
$remark = self::setRewardEvent($ext);
break;
}
}
if ($remark !== '') {
$oper = Operator::get($oper);
$log = [
'agent_id' => $agentId,
'event' => $event,
'remark' => $remark,
'oper_type' => $oper['type'],
'oper_id' => $oper['id'],
'createtime' => time()
];
return self::create($log);
}
return NULL;
}
public static function setAgentEvent($ext)
{
switch ($ext['type']) {
case 'status': // 变更状态
switch ($ext['value']) {
case Agent::AGENT_STATUS_PENDING:
$remark = "您的资料已提交,等待管理员审核";
break;
case Agent::AGENT_STATUS_FORBIDDEN:
$remark = "您的账户已被禁用";
break;
case Agent::AGENT_STATUS_NORMAL:
$remark = "恭喜您成为分销商";
break;
case Agent::AGENT_STATUS_FREEZE:
$remark = "您的账户已被冻结";
break;
case Agent::AGENT_STATUS_REJECT:
$remark = "您的申请已被拒绝,请重新申请";
break;
}
break;
case 'level': // 变更等级
$remark = "您的等级已变更为[{$ext['level']['name']}]";
break;
case 'apply_info':
$remark = '您的分销商资料信息已更新';
break;
}
return $remark ?? "";
}
public static function setShareEvent($ext)
{
$remark = "您已成为用户[{$ext['user']['nickname']}]的推荐人";
return $remark;
}
public static function setBindEvent($ext)
{
$remark = "";
if ($ext['user']) {
$remark = "用户[{$ext['user']['nickname']}]已绑定为您的推荐人";
}
return $remark;
}
public static function setOrderEvent($ext)
{
switch ($ext['type']) {
case 'paid':
$goodsName = $ext['item']['goods_title'];
if (mb_strlen($goodsName) > 9) {
$goodsName = mb_substr($goodsName, 0, 5) . '...' . mb_substr($goodsName, -3);
}
if ($ext['order']['self_buy'] == 1) {
$remark = "您购买了{$goodsName},为您新增业绩{$ext['order']['amount']}元, +1分销订单";
} else {
$remark = "用户{$ext['buyer']['nickname']}购买了{$goodsName},为您新增业绩{$ext['order']['amount']}元, +1分销订单";
}
break;
case 'refund':
$remark = "用户{$ext['buyer']['nickname']}已退款,扣除业绩{$ext['order']['amount']}元, -1分销订单";
break;
case 'admin':
$remark = "扣除业绩{$ext['order']['amount']}元, -1分销订单";
break;
}
return $remark;
}
public static function setRewardEvent($ext)
{
$actionStr = '';
$remark = '';
switch ($ext['type']) {
case 'paid':
$actionStr = '支付成功';
break;
case 'confirm':
$actionStr = '已确认收货';
break;
case 'finish':
$actionStr = '已完成订单';
break;
}
if ($actionStr !== '') {
$remark = "用户{$actionStr}, ";
}
switch ($ext['reward']['status']) {
case Reward::COMMISSION_REWARD_STATUS_PENDING:
$rewardStatus = '待入账';
break;
case Reward::COMMISSION_REWARD_STATUS_ACCOUNTED:
$rewardStatus = '已入账';
break;
case Reward::COMMISSION_REWARD_STATUS_BACK:
$rewardStatus = '已扣除';
break;
case Reward::COMMISSION_REWARD_STATUS_CANCEL:
$rewardStatus = '已取消';
break;
}
$remark .= "您有{$ext['reward']['commission']}元佣金{$rewardStatus}";
return $remark;
}
public function eventList()
{
return [
'agent' => '分销商',
'order' => '订单',
'reward' => '佣金',
'share' => '推荐',
'bind' => '绑定',
];
}
public function operTypeList()
{
return [
'user' => '用户',
'admin' => '管理员',
'system' => '系统',
];
}
/**
* 事件类型
*
* @param string $value
* @param array $data
* @return string
*/
public function getEventTextAttr($value, $data)
{
$value = $value ?: ($data['event'] ?? null);
$list = $this->eventList();
return isset($list[$value]) ? $list[$value] : '-';
}
/**
* 操作人类型
*
* @param string $value
* @param array $data
* @return string
*/
public function getOperTypeTextAttr($value, $data)
{
$value = $value ?: ($data['oper_type'] ?? null);
$list = $this->operTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function agent()
{
return $this->belongsTo(UserModel::class, 'agent_id', 'id')->field('id, username, nickname, avatar, gender');
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace app\admin\model\shopro\commission;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User as UserModel;
use app\admin\model\shopro\order\Order as OrderModel;
use app\admin\model\shopro\order\OrderItem as OrderItemModel;
class Order extends Common
{
const COMMISSION_ORDER_STATUS_NO = 0; // 不计入
const COMMISSION_ORDER_STATUS_YES = 1; // 已计入
const COMMISSION_ORDER_STATUS_CANCEL = -1; // 已取消
const COMMISSION_ORDER_STATUS_BACK = -2; // 已扣除
protected $name = 'shopro_commission_order';
protected $type = [
'commission_rules' => 'json',
'commission_time' => 'timestamp'
];
protected $append = [
'reward_event_text',
'reward_type_text',
'commission_order_status_text',
'commission_reward_status_text'
];
public function getRewardEventTextAttr($value, $data)
{
$value = $value ?: ($data['reward_event'] ?? '');
$eventMap = [
'paid' => '支付后结算',
'confirm' => '收货后结算',
'finish' => '订单完成结算',
'admin' => '手动结算'
];
return isset($eventMap[$value]) ? $eventMap[$value] : '-';
}
public function getRewardTypeTextAttr($value, $data)
{
$value = $value ?: ($data['reward_type'] ?? '');
$eventMap = [
'goods_price' => '商品价',
'pay_price' => '实际支付价'
];
return isset($eventMap[$value]) ? $eventMap[$value] : '-';
}
public function getCommissionOrderStatusTextAttr($value, $data)
{
$value = $value ?: ($data['commission_order_status'] ?? '');
$eventMap = [
-2 => '已扣除',
-1 => '已取消',
0 => '不计入',
1 => '已计入'
];
return isset($eventMap[$value]) ? $eventMap[$value] : '-';
}
public function getCommissionRewardStatusTextAttr($value, $data)
{
$value = $value ?: ($data['commission_reward_status'] ?? '');
$eventMap = [
-2 => '已退回',
-1 => '已取消',
0 => '未结算',
1 => '已结算'
];
return isset($eventMap[$value]) ? $eventMap[$value] : '-';
}
public function scopeBack($query)
{
return $query->where('commission_order_status', self::COMMISSION_ORDER_STATUS_BACK);
}
public function scopeYes($query)
{
return $query->where('commission_order_status', self::COMMISSION_ORDER_STATUS_YES);
}
public function scopeCancel($query)
{
return $query->where('commission_order_status', self::COMMISSION_ORDER_STATUS_CANCEL);
}
public function buyer()
{
return $this->belongsTo(UserModel::class, 'buyer_id', 'id')->field('id, nickname, avatar, mobile');
}
public function agent()
{
return $this->belongsTo(UserModel::class, 'agent_id', 'id')->field('id, nickname, avatar, mobile');
}
public function order()
{
return $this->belongsTo(OrderModel::class, 'order_id', 'id');
}
public function orderItem()
{
return $this->belongsTo(OrderItemModel::class, 'order_item_id', 'id');
}
public function rewards()
{
return $this->hasMany(Reward::class, 'commission_order_id', 'id');
}
}

View File

@@ -0,0 +1,112 @@
<?php
namespace app\admin\model\shopro\commission;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User as UserModel;
use app\admin\model\shopro\order\Order as OrderModel;
use app\admin\model\shopro\order\OrderItem as OrderItemModel;
class Reward extends Common
{
const COMMISSION_REWARD_STATUS_PENDING = 0; // 未结算、待入账
const COMMISSION_REWARD_STATUS_ACCOUNTED = 1; // 已结算、已入账
const COMMISSION_REWARD_STATUS_CANCEL = -1; // 已取消
const COMMISSION_REWARD_STATUS_BACK = -2; // 已退回
protected $name = 'shopro_commission_reward';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $type = [
'commission_rules' => 'json',
'commission_time' => 'timestamp'
];
protected $append = [
'status_text',
'type_text'
];
public function statusList()
{
return [
-2 => '已退回',
-1 => '已取消',
0 => '未结算',
1 => '已结算'
];
}
public function typeList()
{
return [
'commission' => '佣金钱包',
'money' => '余额钱包',
'score' => '积分钱包',
'bank' => '企业付款到银行卡',
'change' => '企业付款到零钱'
];
}
/**
* 待入账
*/
public function scopePending($query)
{
return $query->where('status', self::COMMISSION_REWARD_STATUS_PENDING);
}
/**
* 已退回
*/
public function scopeBack($query)
{
return $query->where('status', self::COMMISSION_REWARD_STATUS_BACK);
}
/**
* 已入账
*/
public function scopeAccounted($query)
{
return $query->where('status', self::COMMISSION_REWARD_STATUS_ACCOUNTED);
}
/**
* 已取消
*/
public function scopeCancel($query)
{
return $query->where('status', self::COMMISSION_REWARD_STATUS_CANCEL);
}
/**
* 待入账和已入账
*
* @return void
*/
public function scopeIncome($query)
{
return $query->where('status', 'in', [self::COMMISSION_REWARD_STATUS_ACCOUNTED, self::COMMISSION_REWARD_STATUS_PENDING]);
}
public function buyer()
{
return $this->belongsTo(UserModel::class, 'buyer_id', 'id')->field('id, nickname, avatar, mobile');
}
public function agent()
{
return $this->belongsTo(UserModel::class, 'agent_id', 'id')->field('id, nickname, avatar, mobile');
}
public function order()
{
return $this->belongsTo(OrderModel::class, 'order_id', 'id');
}
public function orderItem()
{
return $this->belongsTo(OrderItemModel::class, 'order_item_id', 'id');
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace app\admin\model\shopro\data;
use app\admin\model\shopro\Common;
class Area extends Common
{
protected $autoWriteTimestamp = false;
// 表名
protected $name = 'shopro_data_area';
public function children()
{
return $this->hasMany(self::class, 'pid', 'id');
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace app\admin\model\shopro\data;
use app\admin\model\shopro\Common;
class Express extends Common
{
protected $autoWriteTimestamp = false;
// 表名
protected $name = 'shopro_data_express';
}

View File

@@ -0,0 +1,54 @@
<?php
namespace app\admin\model\shopro\data;
use app\admin\model\shopro\Common;
class FakeUser extends Common
{
// 表名
protected $name = 'shopro_data_fake_user';
// 追加属性
protected $append = [
'gender_text'
];
/**
* 设置密码
* @param mixed $value
* @return string
*/
public function setPasswordAttr($value)
{
$value = md5(md5($value) . mt_rand(1000, 9999));
return $value;
}
public function getNicknameHideAttr($value, $data)
{
$value = $value ?: ($data['nickname'] ?? '');
return $value ? string_hide($value, 2) : $value;
}
/**
* 获取性别文字
* @param string $value
* @param array $data
* @return object
*/
public function getGenderTextAttr($value, $data)
{
$value = $value ?: ($data['gender'] ?? 0);
$list = ['1' => __('Male'), '0' => __('Female')];
return isset($list[$value]) ? $list[$value] : '';
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace app\admin\model\shopro\data;
use app\admin\model\shopro\Common;
class Faq extends Common
{
// 表名
protected $name = 'shopro_data_faq';
// 追加属性
protected $append = [
'status_text'
];
}

View File

@@ -0,0 +1,21 @@
<?php
namespace app\admin\model\shopro\data;
use app\admin\model\shopro\Common;
class Page extends Common
{
// 表名
protected $name = 'shopro_data_page';
// 追加属性
protected $append = [
];
public function children()
{
return $this->hasMany(self::class, 'group', 'group')->order('id asc');
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace app\admin\model\shopro\data;
use app\admin\model\shopro\Common;
class Richtext extends Common
{
// 表名
protected $name = 'shopro_data_richtext';
// 追加属性
protected $append = [
];
}

View File

@@ -0,0 +1,15 @@
<?php
namespace app\admin\model\shopro\data;
use app\admin\model\shopro\Common;
class WechatExpress extends Common
{
protected $autoWriteTimestamp = false;
// 表名
protected $name = 'shopro_data_wechat_express';
}

View File

@@ -0,0 +1,75 @@
<?php
namespace app\admin\model\shopro\decorate;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
class Decorate extends Common
{
use SoftDelete;
protected $deleteTime = 'deletetime';
protected $name = 'shopro_decorate';
protected $type = [
];
protected $append = [
'status_text',
'type_text'
];
public function typeList()
{
return [
'template' => '店铺模板',
'diypage' => '自定义页面'
];
}
public function scopeTemplate($query)
{
return $query->where('type', 'template');
}
public function scopeTypeDiypage($query)
{
return $query->where('type', 'diypage');
}
public function scopeDesigner($query)
{
return $query->where('type', 'designer');
}
public function page()
{
return $this->hasMany(Page::class, 'decorate_id', 'id');
}
public function diypage()
{
return $this->hasOne(Page::class, 'decorate_id', 'id')->where('type', 'diypage');
}
public function getPlatformAttr($value, $data)
{
if($value) {
return explode(',', $value);
}else {
return [];
}
}
public function setPlatformAttr($value, $data)
{
if($value) {
return implode(',', $value);
}else {
return "";
}
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace app\admin\model\shopro\decorate;
use app\admin\model\shopro\Common;
class Page extends Common
{
protected $autoWriteTimestamp = false;
protected $name = 'shopro_decorate_page';
protected $append = [
// 'type_text'
];
public function getPageAttr($value, $data)
{
// 图片默认存本地,使用接口域名
// $value = str_replace("\"/storage/", "\"" . request()->domain() . "/storage/", $value);
// $value = str_replace("\"\/storage\/", "\"" . request()->domain() . "/storage/", $value);
return json_decode($value, true);
}
public static function buildData($template)
{
foreach ($template['home']['data'] as $data) {
switch ($data['type']) {
case 'goodsCard':
break;
}
}
// exit();
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace app\admin\model\shopro\dispatch;
use app\admin\model\shopro\Common;
class Dispatch extends Common
{
protected $name = 'shopro_dispatch';
protected $append = [
'status_text'
];
public function scopeShow($query)
{
return $query->where('status', 'normal');
}
public function express()
{
return $this->hasMany(DispatchExpress::class, 'dispatch_id')->order('weigh', 'desc')->order('id', 'asc');
}
public function autosend()
{
return $this->hasOne(DispatchAutosend::class, 'dispatch_id');
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace app\admin\model\shopro\dispatch;
use app\admin\model\shopro\Common;
class DispatchAutosend extends Common
{
protected $name = 'shopro_dispatch_autosend';
protected $append = [
];
public function getContentAttr($value, $data)
{
$value = $value ?: ($data['content'] ?? '');
$type = $data['type'] ?? 'text';
if ($type === 'params') {
$value = json_decode($value, true);
}
return $value;
}
public function setContentAttr($value, $data)
{
$type = $data['type'] ?? 'text';
if ($type == 'params') {
$value = json_encode($value);
}
return $value;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace app\admin\model\shopro\dispatch;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\data\Area;
class DispatchExpress extends Common
{
protected $name = 'shopro_dispatch_express';
protected $append = [
'district_text'
];
public function getDistrictTextAttr($value, $data)
{
$province_ids = $data['province_ids'] ? explode(',', $data['province_ids']) : [];
$city_ids = $data['city_ids'] ? explode(',', $data['city_ids']) : [];
$district_ids = $data['district_ids'] ? explode(',', $data['district_ids']) : [];
$ids = array_merge($province_ids, $city_ids, $district_ids);
$districtText = Area::where('id', 'in', $ids)->field('name')->select();
$districtText = collection($districtText)->column('name');
return implode(',', $districtText);
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace app\admin\model\shopro\goods;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
class Comment extends Common
{
use SoftDelete;
protected $deleteTime = 'deletetime';
// 表名
protected $name = 'shopro_goods_comment';
protected $type = [
'images' => 'json',
'reply_time' => 'timestamp',
];
protected $append = [
'status_text'
];
protected $hidden = [
'user_type'
];
public static $typeAll = [
'all' => ['code' => 'all', 'name' => '全部'],
'images' => ['code' => 'images', 'name' => '有图'],
'good' => ['code' => 'good', 'name' => '好评'],
'moderate' => ['code' => 'moderate', 'name' => '中评'],
'bad' => ['code' => 'bad', 'name' => '差评'],
];
public function scopeImages($query)
{
return $query->whereNotNull('images')->where('images', '<>', '')->where('images', '<>', '[]');
}
public function scopeGood($query)
{
return $query->where('level', 'in', [5, 4]);
}
public function scopeModerate($query)
{
return $query->where('level', 'in', [3, 2]);
}
public function scopeBad($query)
{
return $query->where('level', 1);
}
public function scopeNoReply($query)
{
return $query->whereNull('reply_time');
}
public function getUserNicknameAttr($value, $data)
{
$value = $value ?: ($data['user_nickname'] ?? '');
return $value ? string_hide($value, 2) : $value;
}
public function admin()
{
return $this->belongsTo(\app\admin\model\Admin::class, 'admin_id', 'id')->field('id,username,nickname,avatar');
}
public function goods()
{
return $this->belongsTo(\app\admin\model\shopro\goods\Goods::class, 'goods_id', 'id');
}
public function order()
{
return $this->belongsTo(\app\admin\model\shopro\order\Order::class, 'order_id', 'id');
}
public function orderItem()
{
return $this->belongsTo(\app\admin\model\shopro\order\OrderItem::class, 'order_item_id', 'id');
}
}

View File

@@ -0,0 +1,535 @@
<?php
namespace app\admin\model\shopro\goods;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
use addons\shopro\library\Tree;
use app\admin\model\shopro\Category;
use app\admin\model\shopro\activity\Activity as ActivityModel;
use app\admin\model\shopro\activity\SkuPrice as ActivitySkuPriceModel;
use app\admin\model\shopro\app\ScoreSkuPrice;
use app\admin\model\shopro\user\GoodsLog;
use app\admin\model\shopro\order\Order;
use app\admin\model\shopro\order\OrderItem;
use addons\shopro\facade\Activity as ActivityFacade;
class Goods extends Common
{
use SoftDelete;
protected $deleteTime = 'deletetime';
// 表名
protected $name = 'shopro_goods';
protected $type = [
'images' => 'json',
'image_wh' => 'json',
'params' => 'json',
];
// 追加属性
protected $append = [
'status_text',
'type_text',
'dispatch_type_text'
];
protected $hidden = [
'content',
'max_sku_price',
'score_sku_prices',
'activity_sku_prices',
'total_sales' // 商品列表,销量排序会用到
];
/**
* type 中文
*/
public function typeList()
{
return [
'normal' => '实体商品',
'virtual' => '虚拟商品',
'card' => '电子卡密',
];
}
/**
* status 中文
*/
public function statusList()
{
return [
'up' => '上架中',
'down' => '已下架',
'hidden' => '已隐藏',
];
}
/**
* status 中文
*/
public function dispatchTypeList()
{
return [
'express' => '快递物流',
'autosend' => '自动发货',
'custom' => '商家发货'
];
}
/**
* 修改器 service_ids
*
* @param array|string $value
* @param array $data
* @return string
*/
public function setServiceIdsAttr($value, $data)
{
$service_ids = is_array($value) ? join(',', $value) : $value;
return $service_ids;
}
public function setIsOfflineAttr($value, $data)
{
// 除了实体商品,其他都是 0
return $data['type'] == 'normal' ? $value : 0;
}
public function scopeShow($query)
{
return $query->whereIn('status', ['up', 'hidden']);
}
public function getDispatchTypeTextAttr($value, $data)
{
$value = $value ?: ($data['dispatch_type'] ?? null);
$list = $this->dispatchTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getPriceAttr($value, $data)
{
// 前端传入的 session_id
$activity_id = session('goods-activity_id:' . $data['id']);
if ($activity_id && $this->activity) {
// 活动商品的价格
$skuPrices = $data['new_sku_prices'] ?? [];
$prices = $skuPrices instanceof \think\Collection ? $skuPrices->column('min_price') : array_column($skuPrices, 'min_price');
$maxPrices = $skuPrices instanceof \think\Collection ? $skuPrices->column('max_price') : array_column($skuPrices, 'max_price');
$min_price = $prices ? min($prices) : $data['price'];
$max_price = $maxPrices ? max($maxPrices) : $data['price'];
$priceArr[] = $min_price;
if ($min_price < $max_price) {
$priceArr[] = $max_price;
}
} else if (isset($data['show_score_shop'])) {
// 积分商品价格
$skuPrices = $data['new_sku_prices'] ?? [];
$skuPrices = $skuPrices instanceof \think\Collection ? $skuPrices->column(null, 'score') : array_column($skuPrices, null, 'score');
ksort($skuPrices);
$skuPrice = current($skuPrices); // 需要积分最少的规格
if ($skuPrice) {
// 不自动拼接积分
// $price = $skuPrice['score'] . '积分';
// if ($skuPrice['price'] > 0) {
// $price .= '+¥' . $skuPrice['price'];
// }
// $priceArr[] = $price;
$priceArr[] = $skuPrice['price'];
} else {
// 防止没有规格
$priceArr[] = $data['price'];
}
} else {
// 普通商品的价格区间
$price = $value ? $value : ($data['price'] ?? 0);
$priceArr = [$price];
if ($price && isset($data['is_sku']) && $data['is_sku']) {
$max_price = $this->max_sku_price->price;
if ($price < $max_price) {
$priceArr[] = $max_price;
}
}
}
return $priceArr;
}
/**
* 这个目前只有拼团单独购买要使用
*
* @return void
*/
public function getOriginalGoodsPriceAttr($value, $data)
{
$activity_id = session('goods-activity_id:' . $data['id']);
$priceArr = [];
if ($activity_id && $this->activity) {
// 活动商品的价格
$skuPrices = $data['new_sku_prices'] ?? [];
$prices = $skuPrices instanceof \think\Collection ? $skuPrices->column('old_price') : array_column($skuPrices, 'old_price');
$min_price = $prices ? min($prices) : $data['price'];
$max_price = $prices ? max($prices) : $data['price'];
$priceArr[] = $min_price;
if ($min_price < $max_price) {
$priceArr[] = $max_price;
}
}
return $priceArr;
}
/**
* 前端积分商城列表,获取默认所需积分(价格不自动拼接积分了,所以这里单独设置一个属性)
*/
public function getScoreAttr($value, $data)
{
// 积分商品价格
$skuPrices = $data['new_sku_prices'] ?? [];
$skuPrices = $skuPrices instanceof \think\Collection ? $skuPrices->column(null, 'score') : array_column($skuPrices, null, 'score');
ksort($skuPrices);
$skuPrice = current($skuPrices); // 需要积分最少的规格
if ($skuPrice) {
$scoreAmount = $skuPrice['score'] ?? 0;
} else {
// 防止没有规格
$scoreAmount = 0;
}
return $scoreAmount;
}
public function getSalesAttr($value, $data)
{
// 前端传入的 session_id
$activity_id = session('goods-activity_id:' . $data['id']);
$sales = $data['sales'] ?? 0;
$sales += ($data['show_sales'] ?? 0);
if ($activity_id && $this->activity) {
if ($this->activity['rules'] && isset($this->activity['rules']['sales_show_type']) && $this->activity['rules']['sales_show_type'] == 'real') {
// 活动设置显示真实销量
$skuPrices = $data['new_sku_prices'] ?? [];
$sales = array_sum($skuPrices instanceof \think\Collection ? $skuPrices->column('sales') : array_column($skuPrices, 'sales'));
}
} else if (isset($data['show_score_shop'])) {
// 积分商城显示真实销量
$skuPrices = $data['new_sku_prices'] ?? [];
$sales = array_sum($skuPrices instanceof \think\Collection ? $skuPrices->column('sales') : array_column($skuPrices, 'sales'));
}
return $sales;
}
/**
* 真实销量
*/
public function getRealSalesAttr($value, $data)
{
$sales = $data['sales'] ?? 0;
return $sales;
}
/**
* 相关商品(包含活动)购买用户,只查三个
*
* @param [type] $value
* @param [type] $data
* @return void
*/
public function getBuyersAttr($value, $data)
{
// 查询活动正在购买的人Goods
$activity_id = session('goods-activity_id:' . $data['id']);
$orderItems = OrderItem::with(['user' => function ($query) {
return $query->field('id,nickname,avatar');
}])->whereExists(function ($query) {
$order_name = (new Order())->getQuery()->getTable();
$order_item_name = (new OrderItem())->getQuery()->getTable();
$query->table($order_name)->where($order_item_name . '.order_id=' . $order_name . '.id')->whereIn('status', [Order::STATUS_PAID, Order::STATUS_COMPLETED, Order::STATUS_PENDING]);
});
if ($activity_id) {
$orderItems = $orderItems->where('activity_id', $activity_id);
}
$orderItems = $orderItems->fieldRaw('max(id),user_id')->where('goods_id', $data['id'])->group('user_id')->limit(3)->select();
$user = [];
foreach ($orderItems as $item) {
if ($item['user']) {
$user[] = $item['user'];
}
}
return $user;
}
public function getIsScoreShopAttr($value, $data)
{
$scoreGoodsIds = ScoreSkuPrice::group('goods_id')->cache(20)->column('goods_id');
return in_array($data['id'], $scoreGoodsIds) ? 1 : 0;
}
/**
* 获取当前商品所属分类的所有上级
*
* @param string $value
* @param array $data
* @return array
*/
public function getCategoryIdsArrAttr($value, $data)
{
$categoryIds = $data['category_ids'] ? explode(',', $data['category_ids']) : [];
$categoryIdsArr = [];
$category = new Category();
foreach ($categoryIds as $key => $category_id) {
$currentCategoryIds = (new Tree($category))->getParentFields($category_id);
if ($currentCategoryIds) {
$categoryIdsArr[] = $currentCategoryIds;
}
}
return $categoryIdsArr;
}
/**
* 获取服务ids数组
*
* @param [type] $value
* @param [type] $data
* @return void
*/
public function getServiceIdsAttr($value, $data)
{
$serviceIds = $this->attrFormatComma($value, $data, 'service_ids', true);
return $serviceIds ? array_values(array_filter(array_map("intval", $serviceIds))) : $serviceIds;
}
/**
* 获取所有服务列表
*
* @param string $value
* @param array $data
* @return array
*/
public function getServiceAttr($value, $data)
{
$serviceIds = $this->attrFormatComma($value, $data, 'service_ids');
$serviceData = [];
if ($serviceIds) {
$serviceData = Service::whereIn('id', $serviceIds)->select();
}
return $serviceData;
}
/**
* 获取规格列表
*
* @param string $value
* @param array $data
* @return array
*/
public function getSkusAttr($value, $data)
{
$sku = Sku::with('children')->where('goods_id', $data['id'])->where('parent_id', 0)->select();
return $sku;
}
/**
* 获取规格项列表
*
* @param string $value
* @param array $data
* @return array
*/
public function getSkuPricesAttr($value, $data)
{
$skuPrices = collection(SkuPrice::where('goods_id', $data['id'])->cache(100 + mt_rand(0, 100))->select());
return $skuPrices;
}
/**
* 获取器获取所有活动
*
* @param string $value
* @param array $data
* @return array
*/
public function getActivitiesAttr($value, $data)
{
$activities = ActivityFacade::getGoodsActivitys($data['id']);
return $activities;
}
/**
* 获取器获取指定活动
*
* @param string $value
* @param array $data
* @return array
*/
public function getActivityAttr($value, $data)
{
$activity_id = session('goods-activity_id:' . $data['id']);
$activities = ActivityFacade::getGoodsActivityByActivity($data['id'], $activity_id);
return $activities;
}
public function getPromosAttr($value, $data)
{
$promos = ActivityFacade::getGoodsPromos($data['id']);
foreach ($promos as $key => $promo) {
$rules = $promo['rules'];
$rules['simple'] = true;
$tags = ActivityFacade::formatRuleTags($rules, $promo['type']);
$promo['tag'] = $tags[0] ?? '';
$promo['tags'] = $tags;
$texts = ActivityFacade::formatRuleTexts($rules, $promo['type']);
$promo['texts'] = $texts;
$promos[$key] = $promo;
}
return $promos ?? [];
}
/**
* 积分商城价格,积分商城的属性
*
* @param string $value
* @param array $data
* @return string
*/
public function getScorePriceAttr($value, $data)
{
$scoreSkuPrices = collection($this->score_sku_prices)->column(null, 'score');
ksort($scoreSkuPrices);
$scoreSkuPrice = current($scoreSkuPrices); // 需要积分最少的规格
// print_r($scoreSkuPrices);exit;
if ($scoreSkuPrice) {
$price['score'] = $scoreSkuPrice['score'] ?? 0;
$price['price'] = $scoreSkuPrice['price'] ?? 0;
return $price;
} else {
return null;
}
// return $score . '积分' . ($price > 0 ? '+¥' . $price : '');
}
/**
* 积分商城销量
*
* @param string $value
* @param array $data
* @return string
*/
public function getScoreSalesAttr($value, $data)
{
$scoreSkuPrices = $this->score_sku_prices;
return array_sum(collection($scoreSkuPrices)->column('sales'));
}
/**
* 积分商城库存
*
* @param string $value
* @param array $data
* @return string
*/
public function getScoreStockAttr($value, $data)
{
$scoreSkuPrices = $this->score_sku_prices;
return array_sum(collection($scoreSkuPrices)->column('stock'));
}
public function maxSkuPrice()
{
return $this->hasOne(SkuPrice::class, 'goods_id')->order('price', 'desc');
}
public function favorite()
{
$user = auth_user();
$user_id = empty($user) ? 0 : $user->id;
return $this->hasOne(GoodsLog::class, 'goods_id', 'id')->where('user_id', $user_id)->favorite();
}
public function activitySkuPrices()
{
return $this->hasMany(ActivitySkuPriceModel::class, 'goods_id');
}
public function scoreSkuPrices()
{
return $this->hasMany(ScoreSkuPrice::class, 'goods_id')->up();
}
/**
* 包含下架的积分规格
*/
public function allScoreSkuPrices()
{
return $this->hasMany(ScoreSkuPrice::class, 'goods_id');
}
public function delScoreSkuPrices()
{
return $this->hasMany(ScoreSkuPrice::class, 'goods_id')->removeOption('soft_delete')->whereNotNull('deletetime'); // 只查被删除的记录,这里使用 onlyTrashed 报错
}
// -- commission code start --
public function commissionGoods()
{
return $this->hasOne(\app\admin\model\shopro\commission\CommissionGoods::class, 'goods_id');
}
// -- commission code end --
}

View File

@@ -0,0 +1,13 @@
<?php
namespace app\admin\model\shopro\goods;
use app\admin\model\shopro\Common;
class Service extends Common
{
protected $name = 'shopro_goods_service';
protected $append = [
];
}

View File

@@ -0,0 +1,21 @@
<?php
namespace app\admin\model\shopro\goods;
use app\admin\model\shopro\Common;
class Sku extends Common
{
protected $name = 'shopro_goods_sku';
// 自动写入时间戳字段
protected $autoWriteTimestamp = false;
protected $append = [
];
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace app\admin\model\shopro\goods;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\activity\SkuPrice as ActivitySkuPriceModel;
use app\admin\model\shopro\app\ScoreSkuPrice;
class SkuPrice extends Common
{
protected $name = 'shopro_goods_sku_price';
// 追加属性
protected $append = [
'goods_sku_text',
'status_text'
];
public function getGoodsSkuTextAttr($value, $data)
{
$arr = $this->attrFormatComma($value, $data, 'goods_sku_text', true);
return $arr ? array_values(array_filter($arr)) : $arr;
}
public function activitySkuPrice()
{
return $this->hasOne(ActivitySkuPriceModel::class, 'goods_sku_price_id', 'id');
}
public function scoreSkuPrice()
{
return $this->hasOne(ScoreSkuPrice::class, 'goods_sku_price_id', 'id');
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace app\admin\model\shopro\goods;
use app\admin\model\shopro\Common;
use app\admin\model\Admin;
class StockLog extends Common
{
protected $name = 'shopro_goods_stock_log';
protected $append = [
];
public function goods()
{
return $this->belongsTo(Goods::class, 'goods_id', 'id')->field('id,title,image,is_sku');
}
public function skuPrice()
{
return $this->belongsTo(SkuPrice::class, 'goods_sku_price_id', 'id');
}
public function oper()
{
return $this->belongsTo(Admin::class, 'admin_id', 'id');
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace app\admin\model\shopro\goods;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
class StockWarning extends Common
{
use SoftDelete;
protected $name = 'shopro_goods_stock_warning';
protected $deleteTime = 'deletetime';
protected $type = [
];
protected $append = [
];
public function goods()
{
return $this->belongsTo(Goods::class, 'goods_id', 'id');
}
public function skuPrice()
{
return $this->belongsTo(SkuPrice::class, 'goods_sku_price_id', 'id');
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace app\admin\model\shopro\notification;
use app\admin\model\shopro\Common;
class Config extends Common
{
protected $name = 'shopro_notification_config';
protected $type = [
'content' => 'json',
];
protected $append = [
'status_text',
];
}

View File

@@ -0,0 +1,66 @@
<?php
namespace app\admin\model\shopro\notification;
use app\admin\model\shopro\Common;
use think\Collection;
class Notification extends Common
{
protected $pk = 'id';
protected $name = 'shopro_notification';
protected $type = [
'read_time' => 'timestamp',
'data' => 'array',
];
public static $notificationType = [
'system' => '系统消息',
'shop' => '商城消息',
// 'site' => '网站消息'
];
public function scopeNotificationType($query, $type)
{
if ($type) {
$query = $query->where('notification_type', $type);
}
return $query;
}
/**
* 将数据转换成可以显示成键值对的格式
*
* @param string $value
* @param array $data
* @return array
*/
public function getDataAttr($value, $data)
{
$data = json_decode($data['data'], true);
if (isset($data['message_type']) && $data['message_type'] == 'notification') {
$messageData = $data['data'];
$class = new $data['class_name']();
$fields = $class->returnField['fields'] ?? [];
$fields = array_column($fields, null, 'field');
$newData = [];
foreach ($messageData as $k => $d) {
$da = $fields[$k] ?? [];
if ($da) {
$da['value'] = $d;
$newData[] = $da;
}
}
$data['data'] = $newData;
}
return $data;
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
use app\admin\model\Admin;
use app\admin\model\shopro\user\User;
class Action extends Common
{
protected $name = 'shopro_order_action';
protected $type = [
];
// 追加属性
protected $append = [
'oper'
];
public static function add($order, $item = null, $oper = null, $type = 'user', $remark = '')
{
$oper_id = $oper ? $oper['id'] : 0;
$self = new self();
$self->order_id = $order->id;
$self->order_item_id = is_null($item) ? 0 : $item->id;
$self->oper_type = $type;
$self->oper_id = $oper_id;
$self->order_status = $order->status;
$self->dispatch_status = is_null($item) ? 0 : $item->dispatch_status;
$self->comment_status = is_null($item) ? 0 : $item->comment_status;
$self->aftersale_status = is_null($item) ? 0 : $item->aftersale_status;
$self->refund_status = is_null($item) ? 0 : $item->refund_status;
$self->remark = $remark;
$self->save();
return $self;
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
class Address extends Common
{
protected $name = 'shopro_order_address';
protected $type = [
];
// 追加属性
protected $append = [
];
}

View File

@@ -0,0 +1,286 @@
<?php
namespace app\admin\model\shopro\order;
use traits\model\SoftDelete;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User;
class Aftersale extends Common
{
use SoftDelete;
protected $name = 'shopro_order_aftersale';
protected $deleteTime = 'deletetime';
// 追加属性
protected $append = [
'type_text',
'btns',
'dispatch_status_text',
'aftersale_status_text',
'aftersale_status_desc',
'refund_status_text'
];
// 发货状态
const DISPATCH_STATUS_REFUSE = -1; // 拒收
const DISPATCH_STATUS_NOSEND = 0; // 未发货
const DISPATCH_STATUS_SENDED = 1; // 已发货
const DISPATCH_STATUS_GETED = 2; // 已收货
// 售后状态
const AFTERSALE_STATUS_CANCEL = -2; // 已取消
const AFTERSALE_STATUS_REFUSE = -1; // 拒绝
const AFTERSALE_STATUS_NOOPER = 0; // 未处理
const AFTERSALE_STATUS_ING = 1; // 申请售后
const AFTERSALE_STATUS_COMPLETED = 2; // 售后完成
// 退款状态
const REFUND_STATUS_NOREFUND = 0; // 未退款
const REFUND_STATUS_AGREE = 1; // 已同意
public function typeList()
{
return [
'refund' => '仅退款',
'return' => '退货退款',
'other' => '其他'
];
}
public function dispatchStatusList()
{
return [
self::DISPATCH_STATUS_REFUSE => '已拒收',
self::DISPATCH_STATUS_NOSEND => '未发货',
self::DISPATCH_STATUS_SENDED => '已发货',
self::DISPATCH_STATUS_GETED => '已收货'
];
}
public function aftersaleStatusList()
{
return [
self::AFTERSALE_STATUS_CANCEL => '已取消',
self::AFTERSALE_STATUS_REFUSE => '拒绝',
self::AFTERSALE_STATUS_NOOPER => '未处理',
self::AFTERSALE_STATUS_ING => '申请售后',
self::AFTERSALE_STATUS_COMPLETED => '售后完成'
];
}
public function aftersaleStatusDescList()
{
return [
self::AFTERSALE_STATUS_CANCEL => '买家取消了售后申请',
self::AFTERSALE_STATUS_REFUSE => '卖家拒绝了售后申请',
self::AFTERSALE_STATUS_NOOPER => '买家申请了售后,请及时处理',
self::AFTERSALE_STATUS_ING => '售后正在处理中',
self::AFTERSALE_STATUS_COMPLETED => '售后已完成'
];
}
public function refundStatusList()
{
return [
self::REFUND_STATUS_NOREFUND => '未退款',
self::REFUND_STATUS_AGREE => '同意退款',
];
}
// 已取消
public function scopeCancel($query)
{
return $query->where('aftersale_status', self::AFTERSALE_STATUS_CANCEL);
}
// 已拒绝
public function scopeRefuse($query)
{
return $query->where('aftersale_status', self::AFTERSALE_STATUS_REFUSE);
}
public function scopeNoOper($query)
{
return $query->where('aftersale_status', self::AFTERSALE_STATUS_NOOPER);
}
// 处理中
public function scopeIng($query)
{
return $query->where('aftersale_status', self::AFTERSALE_STATUS_ING);
}
// 处理完成
public function scopeCompleted($query)
{
return $query->where('aftersale_status', self::AFTERSALE_STATUS_COMPLETED);
}
// 需要处理的,包含未处理,和处理中的,个人中心显示售后数量
public function scopeNeedOper($query)
{
return $query->whereIn('aftersale_status', [self::AFTERSALE_STATUS_NOOPER, self::AFTERSALE_STATUS_ING]);
}
/**
* 后台售后列表,主表是 order 表时不用用 scope 了
*
* @param [type] $scope
* @return void
*/
public static function getScopeWhere($scope)
{
$where = [];
switch ($scope) {
case 'cancel':
$where['aftersale_status'] = self::AFTERSALE_STATUS_CANCEL;
break;
case 'refuse':
$where['aftersale_status'] = self::AFTERSALE_STATUS_REFUSE;
break;
case 'nooper':
$where['aftersale_status'] = self::AFTERSALE_STATUS_NOOPER;
break;
case 'ing':
$where['aftersale_status'] = self::AFTERSALE_STATUS_ING;
break;
case 'completed':
$where['aftersale_status'] = self::AFTERSALE_STATUS_COMPLETED;
break;
}
return $where;
}
// 可以取消
public function scopeCanCancel($query)
{
// 未处理,处理中,可以取消
return $query->where('aftersale_status', 'in', [
self::AFTERSALE_STATUS_NOOPER,
self::AFTERSALE_STATUS_ING
]);
}
// 可以操作
public function scopeCanOper($query)
{
// 未处理,处理中,可以 操作退款,拒绝,完成
return $query->where('aftersale_status', 'in', [
self::AFTERSALE_STATUS_NOOPER,
self::AFTERSALE_STATUS_ING
]);
}
// 可以删除
public function scopeCanDelete($query)
{
// 取消,拒绝,完成可以删除
return $query->where('aftersale_status', 'in', [
self::AFTERSALE_STATUS_CANCEL,
self::AFTERSALE_STATUS_REFUSE,
self::AFTERSALE_STATUS_COMPLETED
]);
}
public function getDispatchStatusTextAttr($value, $data)
{
$value = $value ?: ($data['dispatch_status'] ?? null);
$list = $this->dispatchStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getBtnsAttr($value, $data)
{
$btns = [];
switch ($data['aftersale_status']) {
case self::AFTERSALE_STATUS_NOOPER:
case self::AFTERSALE_STATUS_ING:
$btns[] = 'cancel';
break;
case self::AFTERSALE_STATUS_CANCEL:
case self::AFTERSALE_STATUS_REFUSE:
case self::AFTERSALE_STATUS_COMPLETED:
$btns[] = 'delete';
break;
}
return $btns;
}
public function getAftersaleStatusTextAttr($value, $data)
{
$value = $value ?: ($data['aftersale_status'] ?? null);
$list = $this->aftersaleStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getAftersaleStatusDescAttr($value, $data)
{
$value = $value ?: ($data['aftersale_status'] ?? null);
$list = $this->aftersaleStatusDescList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getRefundStatusTextAttr($value, $data)
{
$value = $value ?: ($data['refund_status'] ?? null);
$list = $this->refundStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 获取建议退款金额,不考虑剩余可退款金额是否够退
*
* @param string $value
* @param array $data
* @return string
*/
public function getSuggestRefundFeeAttr($value, $data)
{
$current_goods_amount = bcmul($data['goods_price'], (string)$data['goods_num'], 2);
$total_amount = bcadd($current_goods_amount, $data['dispatch_fee'], 2);
$suggest_refund_fee = bcsub($total_amount, $data['discount_fee'], 2); // (商品金额 + 运费金额) - 总优惠(活动,优惠券,包邮优惠)
return $suggest_refund_fee;
}
public function logs()
{
return $this->hasMany(AftersaleLog::class, 'order_aftersale_id', 'id')->order('id', 'desc');
}
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function order()
{
return $this->belongsTo(Order::class, 'order_id');
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
use app\admin\model\Admin;
use app\admin\model\shopro\user\User;
class AftersaleLog extends Common
{
protected $name = 'shopro_order_aftersale_log';
protected $type = [
'images' => 'json',
];
protected $append = [
'log_type_text'
];
public function logTypeList()
{
return [
'apply_aftersale' => '售后服务单申请成功,等待售后处理',
'cancel' => '用户取消申请售后',
'delete' => '用户删除售后单',
'completed' => '售后订单已完成',
'refuse' => '卖家拒绝售后',
'refund' => '卖家同意退款',
'add_log' => '卖家留言'
];
}
public static function add($order = null, $aftersale = null, $oper = null, $type = 'user', $data = [])
{
$oper_id = $oper ? $oper['id'] : 0;
$images = $data['images'] ?? [];
$self = new self();
$self->order_id = $order ? $order->id : ($aftersale ? $aftersale->id : 0);
$self->order_aftersale_id = $aftersale ? $aftersale->id : 0;
$self->oper_type = $type;
$self->oper_id = $oper_id;
$self->dispatch_status = $aftersale ? $aftersale->dispatch_status : 0;
$self->aftersale_status = $aftersale ? $aftersale->aftersale_status : 0;
$self->refund_status = $aftersale ? $aftersale->refund_status : 0;
$self->log_type = $data['log_type'];
$self->content = $data['content'] ?? '';
$self->images = $images;
$self->save();
// 售后单变动行为
$data = ['aftersale' => $aftersale, 'order' => $order, 'aftersaleLog' => $self];
\think\Hook::listen('order_aftersale_change', $data);
return $self;
}
/**
* log 类型获取器
*
* @param string $value
* @param array $data
* @return string
*/
public function getLogTypeTextAttr($value, $data)
{
$value = $value ?: ($data['log_type'] ?? null);
$list = $this->logTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
class Express extends Common
{
protected $name = 'shopro_order_express';
protected $type = [
'ext' => 'json'
];
// 追加属性
protected $append = [
'status_text'
];
public function statusList()
{
return [
'noinfo' => '暂无信息',
'collect' => '已揽件',
'transport' => '运输中',
'delivery' => '派送中',
'signfor' => '已签收',
'refuse' => '用户拒收',
'difficulty' => '问题件',
'invalid' => '无效件',
'timeout' => '超时单',
'fail' => '签收失败',
'back' => '退回',
];
}
public function items()
{
return $this->hasMany(OrderItem::class, 'order_express_id', 'id');
}
public function logs()
{
return $this->hasMany(ExpressLog::class, 'order_express_id', 'id')->order('id', 'desc');
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
class ExpressLog extends Common
{
protected $name = 'shopro_order_express_log';
protected $type = [
];
// 追加属性
protected $append = [
'status_text'
];
public function statusList()
{
return [
'noinfo' => '',
'collect' => '已揽件',
'transport' => '运输中',
'delivery' => '派送中',
'signfor' => '已签收',
'refuse' => '用户拒收',
'difficulty' => '问题件',
'invalid' => '无效件',
'timeout' => '超时单',
'fail' => '签收失败',
'back' => '退回',
];
}
}

View File

@@ -0,0 +1,184 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User;
use app\admin\model\shopro\user\Invoice as UserInvoiceModel;
class Invoice extends Common
{
protected $name = 'shopro_order_invoice';
protected $type = [
'download_urls' => 'array',
'finish_time' => 'timestamp'
];
protected $hidden = [
'order_items'
];
// 追加属性
protected $append = [
'type_text',
'status_text'
];
public function typeList()
{
return (new UserInvoiceModel)->typeList();
}
/**
* 状态
*
* @return array
*/
public function statusList()
{
return [
'cancel' => '已取消',
'unpaid' => '未支付',
'waiting' => '等待开票',
'finish' => '已开具',
];
}
public function getOrderStatusAttr($value, $data)
{
$order = $this->order;
$order_status = 'normal';
if (!$order) {
$order_status = 'order_deleted';
} else if (in_array($order->status, [Order::STATUS_PAID, Order::STATUS_COMPLETED])) {
$items = $this->order_items;
$refund_num = 0;
$aftersale_num = 0;
foreach ($items as $item) {
if (in_array($item->refund_status, [
OrderItem::REFUND_STATUS_AGREE,
OrderItem::REFUND_STATUS_COMPLETED
])) {
$refund_num += 1;
}
if (in_array($item->aftersale_status, [
OrderItem::AFTERSALE_STATUS_REFUSE,
OrderItem::AFTERSALE_STATUS_ING,
OrderItem::AFTERSALE_STATUS_COMPLETED
])) {
$aftersale_num += 1;
}
}
if ($refund_num) {
$order_status = 'refund';
if ($refund_num == count($items)) {
$order_status = 'refund_all';
}
} else if ($aftersale_num) {
$order_status = 'aftersale';
}
} else if ($order->isOffline($order)) {
$order_status = 'offline_unpaid';
}
return $order_status;
}
public function getOrderStatusTextAttr($value, $data)
{
$order_status = $this->order_status;
switch($order_status) {
case 'order_deleted':
$order_status_text = '该订单已被删除';
break;
case 'refund_all':
$order_status_text = '该订单已全部退款';
break;
case 'refund':
$order_status_text = '该订单已部分退款';
break;
case 'aftersale':
$order_status_text = '该订单已申请售后';
break;
case 'offline_unpaid':
$order_status_text = '该订单货到付款-未付款';
break;
default :
$order_status_text = '';
}
return $order_status_text;
}
public function getOrderFeeAttr($value, $data)
{
$order = $this->order;
if ($order && $order->pay_fee != $order->original_pay_fee) {
return [
'pay_fee' => $order->pay_fee,
'original_pay_fee' => $order->original_pay_fee,
];
}
return null;
}
public function scopeCancel($query)
{
return $query->where('status', 'cancel');
}
public function scopeWaiting($query)
{
return $query->where('status', 'waiting');
}
public function scopeFinish($query)
{
return $query->where('status', 'finish');
}
/**
* 不展示 未支付的
*/
public function scopeShow($query)
{
return $query->whereIn('status', ['cancel', 'waiting', 'finish']);
}
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function order()
{
return $this->belongsTo(Order::class, 'order_id', 'id');
}
public function orderItems()
{
return $this->hasMany(OrderItem::class, 'order_id', 'order_id');
}
}

View File

@@ -0,0 +1,361 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
use app\admin\model\shopro\user\User;
use app\admin\model\shopro\Pay as PayModel;
use app\admin\model\shopro\activity\Activity;
use app\admin\model\shopro\order\traits\OrderScope;
use app\admin\model\shopro\order\traits\OrderStatus;
use app\admin\model\shopro\activity\Order as ActivityOrder;
class Order extends Common
{
use SoftDelete, OrderScope, OrderStatus;
protected $name = 'shopro_order';
protected $deleteTime = 'deletetime';
protected $type = [
'ext' => 'json',
'paid_time' => 'timestamp',
];
// 追加属性
protected $append = [
'type_text',
'status_code',
'status_text',
'status_desc',
'apply_refund_status_text',
'btns',
'platform_text',
'activity_type_text',
'promo_types_text',
'wechat_extra_data'
];
// 订单状态
const STATUS_CLOSED = 'closed';
const STATUS_CANCEL = 'cancel';
const STATUS_UNPAID = 'unpaid';
const STATUS_PAID = 'paid';
const STATUS_COMPLETED = 'completed';
const STATUS_PENDING = 'pending'; // 待定 后付款
const APPLY_REFUND_STATUS_NOAPPLY = 0;
const APPLY_REFUND_STATUS_APPLY = 1;
const APPLY_REFUND_STATUS_FINISH = 2;
const APPLY_REFUND_STATUS_REFUSE = -1;
public function statusList()
{
return [
'closed' => '交易关闭',
'cancel' => '已取消',
'unpaid' => '未支付',
'pending' => '待定', // 货到付款未付款状态
'paid' => '已支付',
'completed' => '已完成'
];
}
public function applyRefundStatusList()
{
return [
self::APPLY_REFUND_STATUS_NOAPPLY => '未申请',
self::APPLY_REFUND_STATUS_APPLY => '申请退款',
self::APPLY_REFUND_STATUS_FINISH => '退款完成',
self::APPLY_REFUND_STATUS_REFUSE => '拒绝申请'
];
}
/**
* 订单列表状态搜索
*/
public function searchStatusList()
{
return [
'unpaid' => '待付款',
'paid' => '已支付', // 包括刚支付的,发货中,和已退款的,以及已完成的所有付过款的订单,不包含货到付款还未真实付款的订单
'nosend' => '待发货',
'noget' => '待收货',
'refuse' => '已拒收',
'nocomment' => '待评价',
'completed' => '已完成',
'aftersale' => '售后',
'applyRefundIng' => '申请退款',
'refund' => '已退款',
'cancel' => '已取消',
'closed' => '交易关闭', // 包含货到付款,拒收的商品
];
}
public function typeList()
{
return [
'goods' => '商城订单',
'score' => '积分订单'
];
}
public function platformList()
{
return [
'H5' => 'H5',
'WechatOfficialAccount' => '微信公众号',
'WechatMiniProgram' => '微信小程序',
'App' => 'App',
];
}
public function getExtAttr($value, $data)
{
$ext = (isset($data['ext']) && $data['ext']) ? json_decode($data['ext'], true) : [];
// 每类活动优惠金额聚合(可能订单购买多个商品,然后同时参与了两种满减,金额累加)
$ext['promo_discounts'] = [
'full_reduce' => 0,
'full_discount' => 0,
'free_shipping' => 0,
'full_gift' => 0
];
if ($ext && isset($ext['promo_infos']) && $ext['promo_infos']) {
foreach ($ext['promo_infos'] as $key => $info) {
if ($info['activity_type'] == 'full_gift') {
$ext['promo_discounts']['full_gift'] = 1;
continue;
}
$ext['promo_discounts'][$info['activity_type']] = bcadd((string)$ext['promo_discounts'][$info['activity_type']], (string)$info['promo_discount_money'], 2);
}
}
// 格式化
$ext['promo_discounts'] = array_map(function ($value) {
return number_format(floatval($value), 2, '.', '');
}, $ext['promo_discounts']);
// 处理时间
if (isset($ext['closed_time']) && $ext['closed_time']) {
$ext['closed_date'] = date('Y-m-d H:i:s', $ext['closed_time']);
}
if (isset($ext['cancel_time']) && $ext['cancel_time']) {
$ext['cancel_date'] = date('Y-m-d H:i:s', $ext['cancel_time']);
}
if (isset($ext['pending_time']) && $ext['pending_time']) {
$ext['pending_date'] = date('Y-m-d H:i:s', $ext['pending_time']);
}
if (isset($ext['apply_refund_time']) && $ext['apply_refund_time']) {
$ext['apply_refund_date'] = date('Y-m-d H:i:s', $ext['apply_refund_time']);
}
if (isset($ext['send_time']) && $ext['send_time']) {
$ext['send_date'] = date('Y-m-d H:i:s', $ext['send_time']);
}
if (isset($ext['confirm_time']) && $ext['confirm_time']) {
$ext['confirm_date'] = date('Y-m-d H:i:s', $ext['confirm_time']);
}
if (isset($ext['comment_time']) && $ext['comment_time']) {
$ext['comment_date'] = date('Y-m-d H:i:s', $ext['comment_time']);
}
if (isset($ext['completed_time']) && $ext['completed_time']) {
$ext['completed_date'] = date('Y-m-d H:i:s', $ext['completed_time']);
}
if (isset($ext['refund_time']) && $ext['refund_time']) {
$ext['refund_date'] = date('Y-m-d H:i:s', $ext['refund_time']);
}
return $ext;
}
public function getPlatformTextAttr($value, $data)
{
$value = $value ?: ($data['platform'] ?? null);
$list = $this->platformList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 微信小程序发货信息管理所需参数
*
* @param string|null $value
* @param array $data
* @return array
*/
public function getWechatExtraDataAttr($value, $data)
{
$extraData = [];
if (strpos(request()->url(), 'addons/shopro') !== false && $data['platform'] == 'WechatMiniProgram') {
// 前端接口,并且是 微信小程序订单,才返这个参数
$pays = $this->pays;
foreach ($pays as $pay) {
if ($pay->status != PayModel::PAY_STATUS_UNPAID && $pay->pay_type == 'wechat') {
$extraData['merchant_trade_no'] = $pay->pay_sn;
$extraData['transaction_id'] = $pay->transaction_id;
}
}
}
return $extraData;
}
/**
* 申请退款状态
*
* @param string $value
* @param array $data
* @return string
*/
public function getApplyRefundStatusTextAttr($value, $data)
{
$value = $value ?: ($data['apply_refund_status'] ?? null);
$list = $this->applyRefundStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getActivityTypeTextAttr($value, $data)
{
$value = $value ?: ($data['activity_type'] ?? null);
$ext = $this->ext;
$list = (new Activity)->typeList();
$text = isset($list[$value]) ? $list[$value] : '';
if (in_array($value, ['groupon', 'groupon_ladder'])) {
// 订单已支付的,或者线下支付(货到付款)的
if ((in_array($data['status'], [self::STATUS_PAID, self::STATUS_COMPLETED]) || $this->isOffline($data))
&& (!isset($ext['groupon_id']) || !$ext['groupon_id']))
{
// 已支付,并且没有团 id,就是单独购买
$text .= '-单独购买';
}
}
return $text;
}
public function getPromoTypesTextAttr($value, $data)
{
$value = $value ?: ($data['promo_types'] ?? null);
$promoTypes = array_filter(explode(',', $value));
$texts = [];
$list = (new Activity)->typeList();
foreach ($promoTypes as $type) {
$text = isset($list[$type]) ? $list[$type] : '';
if ($text) {
$texts[] = $text;
}
}
return $texts;
}
/**
* 已支付订单,支付类型
*
* @param string $value
* @param array $data
* @return void
*/
public function getPayTypesAttr($value, $data)
{
$status = $data['status'] ?? '';
$payTypes = [];
// 订单已支付的,或者线下支付(货到付款)的
if (in_array($status, [self::STATUS_PAID, self::STATUS_COMPLETED]) || $this->isOffline($data)) {
$payTypes = PayModel::typeOrder()->where('order_id', $data['id'])->where('status', '<>', PayModel::PAY_STATUS_UNPAID)->group('pay_type')->column('pay_type');
}
return $payTypes;
}
/**
* 已支付订单,支付类型文字
*
* @param string $value
* @param array $data
* @return void
*/
public function getPayTypesTextAttr($value, $data)
{
$payTypes = $this->pay_types;
$list = (new PayModel)->payTypeList();
$texts = [];
foreach ($payTypes as $pay_type) {
$text = isset($list[$pay_type]) ? $list[$pay_type] : '';
if ($text) {
$texts[] = $text;
}
}
return $texts;
}
public function getExpressAttr($value, $data)
{
return Express::with(['items', 'logs'])->where('order_id', $data['id'])->select();
}
public function items()
{
return $this->hasMany(OrderItem::class, 'order_id', 'id');
}
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function aftersales()
{
return $this->hasMany(Aftersale::class, 'order_id')->order('id', 'desc');
}
public function address()
{
return $this->hasOne(Address::class, 'order_id', 'id');
}
public function invoice()
{
return $this->hasOne(Invoice::class, 'order_id', 'id');
}
public function pays()
{
return $this->hasMany(PayModel::class, 'order_id', 'id')->typeOrder()->order('id', 'desc');
}
public function activityOrders()
{
return $this->hasMany(ActivityOrder::class, 'order_id');
}
}

View File

@@ -0,0 +1,227 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\order\traits\OrderItemStatus;
use app\admin\model\shopro\activity\Activity;
use app\admin\model\shopro\user\User;
class OrderItem extends Common
{
use OrderItemStatus;
protected $name = 'shopro_order_item';
protected $type = [
'ext' => 'json'
];
// 追加属性
protected $append = [
'dispatch_status_text',
'dispatch_type_text',
'aftersale_status_text',
'refund_status_text',
'comment_status_text',
'status_code',
'status_text',
'status_desc',
'btns',
'activity_type_text',
'promo_types_text'
];
// 发货状态
const DISPATCH_STATUS_REFUSE = -1; // 已拒收
const DISPATCH_STATUS_NOSEND = 0; // 未发货
const DISPATCH_STATUS_SENDED = 1; // 已发货
const DISPATCH_STATUS_GETED = 2; // 已收货
// 售后状态
const AFTERSALE_STATUS_REFUSE = -1; // 拒绝
const AFTERSALE_STATUS_NOAFTER = 0; // 未申请
const AFTERSALE_STATUS_ING = 1; // 申请售后
const AFTERSALE_STATUS_COMPLETED = 2; // 售后完成
// 退款状态
const REFUND_STATUS_NOREFUND = 0; // 退款状态 未申请
const REFUND_STATUS_AGREE = 1; // 已同意
const REFUND_STATUS_COMPLETED = 2; // 退款完成
// 评价状态
const COMMENT_STATUS_NO = 0; // 待评价
const COMMENT_STATUS_OK = 1; // 已评价
public function dispatchStatusList()
{
return [
self::DISPATCH_STATUS_REFUSE => '已拒收',
self::DISPATCH_STATUS_NOSEND => '待发货',
self::DISPATCH_STATUS_SENDED => '待收货',
self::DISPATCH_STATUS_GETED => '已收货'
];
}
public function dispatchTypeList()
{
return [
'express' => '快递物流',
'autosend' => '自动发货',
'custom' => '手动发货'
];
}
public function aftersaleStatusList()
{
return [
self::AFTERSALE_STATUS_REFUSE => '售后驳回',
self::AFTERSALE_STATUS_NOAFTER => '未申请',
self::AFTERSALE_STATUS_ING => '申请售后',
self::AFTERSALE_STATUS_COMPLETED => '已完成'
];
}
public function refundStatusList()
{
return [
self::REFUND_STATUS_NOREFUND => '未退款',
self::REFUND_STATUS_AGREE => '退款完成',
self::REFUND_STATUS_COMPLETED => '退款完成',
];
}
public function commentStatusList()
{
return [
self::COMMENT_STATUS_NO => '待评价',
self::COMMENT_STATUS_OK => '已评价',
];
}
public function getActivityTypeTextAttr($value, $data)
{
$value = $value ?: ($data['activity_type'] ?? null);
$list = (new Activity)->typeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getDispatchTypeTextAttr($value, $data)
{
$value = $value ?: ($data['dispatch_type'] ?? null);
$list = $this->dispatchTypeList();
if (strpos(request()->url(), 'addons/shopro') !== false) {
$list['custom'] = '商家发货';
}
return isset($list[$value]) ? $list[$value] : '';
}
public function getPromoTypesTextAttr($value, $data)
{
$value = $value ?: ($data['promo_types'] ?? null);
$promoTypes = array_filter(explode(',', $value));
$texts = [];
$list = (new Activity)->typeList();
foreach ($promoTypes as $type) {
$text = isset($list[$type]) ? $list[$type] : '';
if ($text) {
$texts[] = $text;
}
}
return $texts;
}
public function getDispatchStatusTextAttr($value, $data)
{
$value = $value ?: ($data['dispatch_status'] ?? null);
$list = $this->dispatchStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getAftersaleStatusTextAttr($value, $data)
{
$value = $value ?: ($data['aftersale_status'] ?? null);
$list = $this->aftersaleStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getRefundStatusTextAttr($value, $data)
{
$value = $value ?: ($data['refund_status'] ?? null);
$list = $this->refundStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getCommentStatusTextAttr($value, $data)
{
$value = $value ?: ($data['comment_status'] ?? null);
$list = $this->commentStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 获取建议退款金额,不考虑剩余可退款金额是否够退
*
* @param string $value
* @param array $data
* @return string
*/
public function getSuggestRefundFeeAttr($value, $data)
{
$current_goods_amount = bcmul($data['goods_price'], (string)$data['goods_num'], 2);
$total_amount = bcadd($current_goods_amount, $data['dispatch_fee'], 2);
$suggest_refund_fee = bcsub($total_amount, $data['discount_fee'], 2); // (商品金额 + 运费金额) - 总优惠(活动,优惠券,包邮优惠)
return $suggest_refund_fee;
}
/**
* 可以确认收货
*
* @param \think\db\Query $query
* @return void
*/
public function scopeCanConfirm($query)
{
return $query->where('dispatch_status', OrderItem::DISPATCH_STATUS_SENDED) // 已发货
->whereNotIn('refund_status', [OrderItem::REFUND_STATUS_AGREE, OrderItem::REFUND_STATUS_COMPLETED]); // 没有退款完成
}
/**
* 可以评价
*
* @param \think\db\Query $query
* @return void
*/
public function scopeCanComment($query)
{
return $query->where('dispatch_status', OrderItem::DISPATCH_STATUS_GETED) // 已收货
->where('comment_status', OrderItem::COMMENT_STATUS_NO) // 未评价
->whereNotIn('refund_status', [OrderItem::REFUND_STATUS_AGREE, OrderItem::REFUND_STATUS_COMPLETED]); // 没有退款完成
}
public function express()
{
return $this->belongsTo(Express::class, 'order_express_id');
}
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
}

View File

@@ -0,0 +1,268 @@
<?php
namespace app\admin\model\shopro\order\traits;
use app\admin\model\shopro\order\OrderItem;
trait OrderItemStatus
{
public function getStatus($data, $type)
{
$btns = [];
$backendBtns = [];
$status_text = '';
$status_desc = '';
$ext = $this->ext;
$aftersale_id = (isset($ext['aftersale_id']) && !empty($ext['aftersale_id'])) ? $ext['aftersale_id'] : 0;
$status_code = $this->status_code;
$item_code = 'null'; // 有售后的时候,第二状态
if (strpos($status_code, '|') !== false) {
$codes = explode('|', $status_code);
$status_code = $codes[0] ?? 'null';
$item_code = $codes[1] ?? 'null';
}
switch ($status_code) {
case 'null':
case 'cancel':
case 'closed':
case 'unpaid':
// 未支付的返回空
break;
case 'refuse': // 拒收
$status_text = '已拒收';
$status_desc = '用户拒绝收货';
break;
case 'nosend':
$status_text = '待发货';
$status_desc = '等待卖家发货';
$backendBtns[] = 'send';
$backendBtns[] = 'refund'; // 退款
// $btns[] = $aftersale_id ? 're_aftersale' : 'aftersale'; // 售后,售后取消会有 aftersale_id , 待发货商品,不用申请售后,直接用订单退款
break;
case 'noget':
$status_text = '待收货';
$status_desc = '等待买家收货';
// $btns[] = 'get'; // 确认收货,总订单上才有
$btns[] = $aftersale_id ? 're_aftersale' : 'aftersale'; // 售后,售后取消会有 aftersale_id
$backendBtns[] = 'send_cancel'; // 取消发货
$backendBtns[] = 'refund';
break;
case 'nocomment':
$status_text = '待评价';
$status_desc = '等待买家评价';
$btns[] = 'comment'; // 评价,总订单上才有(前端通过这个判断待评价商品)
$btns[] = $aftersale_id ? 're_aftersale' : 'aftersale'; // 售后,售后取消会有 aftersale_id
$backendBtns[] = 'refund'; // 退款
break;
case 'commented':
$status_text = '已评价';
$status_desc = '订单已评价';
$btns[] = 'buy_again';
$backendBtns[] = 'refund'; // 退款
$backendBtns[] = 'comment_view'; // 查看评价
break;
case 'refund_completed':
$status_text = '退款完成';
$status_desc = '订单退款完成';
break;
case 'refund_agree': // 不需要申请退款(状态不会出现)
$status_text = '退款完成';
$status_desc = '卖家已同意退款';
break;
case 'aftersale_ing':
$status_text = '售后中';
$status_desc = '售后处理中';
if ($item_code == 'noget') {
if (in_array($data['dispatch_type'], ['express'])) { // 除了 自提扫码核销外,都可确认收货
$backendBtns[] = 'send_cancel'; // 取消发货
}
} else if ($item_code == 'nocomment') {
// 售后中也可以评价订单
$btns[] = 'comment'; // 评价,总订单上才有(前端通过这个判断待评价商品)
}
break;
case 'aftersale_refuse':
case 'aftersale_completed':
switch ($status_code) {
case 'aftersale_refuse':
$status_text = '售后拒绝';
$status_desc = '售后申请拒绝';
if ($item_code != 'commented') {
$btns[] = 're_aftersale'; // 售后
}
break;
case 'aftersale_completed':
$status_text = '售后完成';
$status_desc = '售后完成';
break;
}
// 售后拒绝,或者完成的时候,还可以继续操作订单
switch ($item_code) {
case 'nosend':
if (in_array($data['dispatch_type'], ['express'])) { // 除了 自提扫码核销外,都可确认收货
$backendBtns[] = 'send'; // 发货
}
break;
case 'noget':
if (in_array($data['dispatch_type'], ['express'])) { // 除了 自提扫码核销外,都可确认收货
// $btns[] = 'get'; // 确认收货,总订单上才有
$backendBtns[] = 'send_cancel'; // 取消发货
}
break;
case 'nocomment':
$btns[] = 'comment'; // 评价,总订单上才有(前端通过这个判断待评价商品)
break;
case 'commented':
$btns[] = 'buy_again';
$backendBtns[] = 'comment_view'; // 查看评价
break;
}
break;
}
// 如果有售后id 就显示售后详情按钮,退款中可能是售后退的款
if ($aftersale_id) {
$btns[] = 'aftersale_info';
$backendBtns[] = 'aftersale_info';
}
$return = null;
switch($type) {
case 'status_text':
$return = $status_text;
break;
case 'btns':
$return = $btns;
break;
case 'status_desc':
$return = $status_desc;
break;
case 'backend_btns':
$return = $backendBtns;
break;
}
return $return;
}
public function getStatusTextAttr($value, $data)
{
return $this->getStatus($data, 'status_text');
}
public function getStatusDescAttr($value, $data)
{
return $this->getStatus($data, 'status_desc');
}
public function getBtnsAttr($value, $data)
{
$btn_name = strpos(request()->url(), 'addons/shopro') !== false ? 'btns' : 'backend_btns';
return $this->getStatus($data, $btn_name);
}
// 获取订单 item status_code 状态,不进行订单是否支付判断,在这里查询数据库特别慢,
// 需要处理情况订单列表要正确显示item 状态,直接获取 item 的状态
public function getStatusCodeAttr($value, $data)
{
// $status_code = 'null';
// $order = Order::withTrashed()->where('id', $data['order_id'])->find();
// if (!$order) {
// return $status_code;
// }
// // 判断是否支付
// if (!in_array($order->status, [Order::STATUS_PAYED, Order::STATUS_FINISH])) {
// return $order->status_code;
// }
// 获取 item status_code
return $this->getBaseStatusCode($data);
}
/**
* $data 当前 item 数据
* $from 当前 model 调用,还是 order 调用
*/
public function getBaseStatusCode($data, $from = 'item')
{
$status_code = 'null';
if ($data['refund_status'] == OrderItem::REFUND_STATUS_AGREE) {
// 退款已同意
return 'refund_agree';
}
if ($data['refund_status'] == OrderItem::REFUND_STATUS_COMPLETED) {
// 退款完成
return 'refund_completed';
}
if ($data['aftersale_status']) {
// 只申请了售后,没有退款
// status_code
$status_code = $this->getNormalStatusCode($data);
// item 要原始状态,总订单还要原来的未退款状态
if ($from == 'item') {
switch ($data['aftersale_status']) {
case OrderItem::AFTERSALE_STATUS_REFUSE:
$status_code = 'aftersale_refuse' . '|' . $status_code;
break;
case OrderItem::AFTERSALE_STATUS_ING:
$status_code = 'aftersale_ing' . '|' . $status_code;
break;
case OrderItem::AFTERSALE_STATUS_COMPLETED:
$status_code = 'aftersale_completed' . '|' . $status_code;
break;
}
}
} else {
// status_code
$status_code = $this->getNormalStatusCode($data);
}
return $status_code;
}
public function getNormalStatusCode($data)
{
// 获取未申请售后和退款时候的 status_code
$status_code = 'null';
switch ($data['dispatch_status']) {
case OrderItem::DISPATCH_STATUS_REFUSE:
$status_code = 'refuse';
break;
case OrderItem::DISPATCH_STATUS_NOSEND:
$status_code = 'nosend';
break;
case OrderItem::DISPATCH_STATUS_SENDED:
$status_code = 'noget';
break;
case OrderItem::DISPATCH_STATUS_GETED:
if ($data['comment_status'] == OrderItem::COMMENT_STATUS_NO) {
$status_code = 'nocomment';
} else {
$status_code = 'commented';
}
break;
}
return $status_code; // status_code
}
}

View File

@@ -0,0 +1,211 @@
<?php
namespace app\admin\model\shopro\order\traits;
use app\admin\model\shopro\order\Order;
use app\admin\model\shopro\order\OrderItem;
trait OrderScope
{
// 已关闭
public function scopeClosed($query)
{
return $query->where('status', Order::STATUS_CLOSED);
}
// 已取消
public function scopeCancel($query)
{
return $query->where('status', Order::STATUS_CANCEL);
}
// 未支付
public function scopeUnpaid($query)
{
return $query->where('status', Order::STATUS_UNPAID);
}
// 可以取消,未支付&货到付款未发货的订单
public function scopeCanCancel($query)
{
return $query->where(function ($query) {
$query->where('status', Order::STATUS_UNPAID)->whereOr(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->where('pay_mode', 'offline')->where('status', Order::STATUS_PENDING)->whereExists(function ($query) use ($self_name, $item_name) {
// 货到付款订单,未发货未退款,可以申请售后
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('dispatch_status', OrderItem::DISPATCH_STATUS_NOSEND) // 未发货
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND); // 没有退款完成;
});
});
});
}
// 已支付
public function scopePaid($query)
{
return $query->whereIn('status', [Order::STATUS_PAID, Order::STATUS_COMPLETED]);
}
// 线下支付(货到付款) pending 时
public function scopeOffline($query)
{
return $query->where('pay_mode', 'offline')->where('status', Order::STATUS_PENDING);
}
/**
* 是否线下支付(货到付款),暂未付款
*
* @param object|array $order
* @return boolean
*/
public function isOffline($order)
{
return ($order['status'] == Order::STATUS_PENDING && $order['pay_mode'] == 'offline') ? true : false;
}
// 已支付的,或者是线下付款的未支付订单,后续可以,发货,收货,评价
public function scopePretendPaid($query)
{
return $query->where(function ($query) {
$query->whereIn('status', [Order::STATUS_PAID, Order::STATUS_COMPLETED])->whereOr(function($query) {
$query->where('pay_mode', 'offline')->where('status', Order::STATUS_PENDING);
});
});
}
// 已完成
public function scopeCompleted($query)
{
return $query->where('status', Order::STATUS_COMPLETED);
}
// 未申请全额退款,或者已拒绝
public function scopeNoApplyRefund($query)
{
return $query->whereIn('apply_refund_status', [
Order::APPLY_REFUND_STATUS_NOAPPLY,
Order::APPLY_REFUND_STATUS_REFUSE
]);
}
// 申请全额退款中
public function scopeApplyRefundIng($query)
{
return $query->where('apply_refund_status', Order::APPLY_REFUND_STATUS_APPLY);
}
// 未发货
public function scopeNosend($query)
{
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$is_express = (request()->action() == 'exportdelivery') ? 1 : 0; // 是否是 express将只查快递物流的代发货
return $query->noApplyRefund()->whereExists(function ($query) use ($self_name, $item_name, $is_express) {
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('dispatch_status', OrderItem::DISPATCH_STATUS_NOSEND) // 未发货
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND); // 没有退款完成
if ($is_express) { // 只查快递物流的代发货
$query->where('dispatch_type', 'express');
}
})->whereNotExists(function ($query) use ($self_name, $item_name, $is_express) {
// 不是 正在售后的商品
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('aftersale_status', OrderItem::AFTERSALE_STATUS_ING) // 但是售后中
->where('dispatch_status', OrderItem::DISPATCH_STATUS_NOSEND) // 未发货
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND); // 没有退款完成;
if ($is_express) { // 只查快递物流的代发货
$query->where('dispatch_type', 'express');
}
});
}
// 待收货
public function scopeNoget($query)
{
return $query->whereExists(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('dispatch_status', OrderItem::DISPATCH_STATUS_SENDED) // 已发货
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND); // 没有退款完成
});
}
// 已拒收
public function scopeRefuse($query)
{
return $query->whereExists(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('dispatch_status', OrderItem::DISPATCH_STATUS_REFUSE) // 已拒收
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND); // 没有退款完成
});
}
// 待评价
public function scopeNocomment($query)
{
return $query->whereExists(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('dispatch_status', OrderItem::DISPATCH_STATUS_GETED) // 已收货
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND) // 没有退款完成
->where('comment_status', OrderItem::COMMENT_STATUS_NO); // 未评价
});
}
// 售后 (后台要用,虽然有专门的售后单列表)
public function scopeAftersale($query)
{
return $query->whereExists(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('aftersale_status', '<>', OrderItem::AFTERSALE_STATUS_NOAFTER);
});
}
// 退款
public function scopeRefund($query)
{
return $query->whereExists(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('refund_status', '<>', OrderItem::REFUND_STATUS_NOREFUND);
});
}
public function scopeCanAftersale($query)
{
return $query->where('status', 'in', [Order::STATUS_PAID, Order::STATUS_COMPLETED]);
}
public function scopeCanDelete($query)
{
return $query->where('status', 'in', [
Order::STATUS_CANCEL,
Order::STATUS_CLOSED,
Order::STATUS_COMPLETED
]);
}
}

View File

@@ -0,0 +1,417 @@
<?php
namespace app\admin\model\shopro\order\traits;
use app\admin\model\shopro\order\Order;
use app\admin\model\shopro\order\OrderItem;
use app\admin\model\shopro\activity\Groupon;
use app\admin\model\shopro\Config;
trait OrderStatus
{
protected function getStatus($data, $type)
{
$btns = []; // 前端订单操作按钮
$backendBtns = [];
$status_text = '';
$status_desc = '';
$ext = $this->ext;
switch ($this->status_code) {
case 'cancel':
$status_text = '已取消';
$status_desc = '买家已取消';
$btns[] = 'delete'; // 删除订单
break;
case 'closed':
$status_text = '交易关闭';
if (isset($ext['closed_type']) && $ext['closed_type'] == 'refuse') {
$status_desc = '买家拒绝收货';
} else {
$status_desc = '买家未在规定时间内付款';
}
$btns[] = 'delete'; // 删除订单
break;
case 'unpaid':
$status_text = '待付款';
$status_desc = '等待买家付款';
$btns[] = 'cancel'; // 取消订单
$btns[] = 'pay'; // 支付
$backendBtns[] = 'change_fee'; // 订单改价
break;
// 已支付的
case 'apply_refund':
$status_text = '申请退款中';
$status_desc = '等待卖家处理退款';
$backendBtns[] = 'apply_refund_oper'; // 处理申请退款按钮
$backendBtns[] = 'refund'; // 只能退款,或者在列表上拒绝申请退款
break;
case 'commented':
$status_text = '已评价';
$status_desc = '订单已评价';
$dispatchType = $this->getItemDispatchTypes();
if (in_array('express', $dispatchType)) {
$btns[] = 'express'; // 查看物流
}
$backendBtns[] = 'refund';
break;
case 'nocomment':
$status_text = '待评价';
$status_desc = '等待买家评价';
$dispatchType = $this->getItemDispatchTypes();
if (in_array('express', $dispatchType)) {
$btns[] = 'express'; // 查看物流
}
$btns[] = 'comment';
$backendBtns[] = 'refund';
break;
case 'noget':
$status_text = '待收货';
$status_desc = '等待买家收货';
$dispatchType = $this->getItemDispatchTypes();
if (in_array('express', $dispatchType)) {
$btns[] = 'express'; // 查看物流
}
if ($this->isOffline($data)) {
$status_desc = '卖家已发货,等待包裹运达';
// 用户可以拒收,后台确认收货
$btns[] = 'refuse'; // 用户拒收
$backendBtns[] = 'confirm';
}else {
// 计算自动确认收货时间
$send_time = $ext['send_time'] ?? 0;
$auto_confirm = Config::getConfigField('shop.order.auto_confirm');
$auto_confirm_unix = $auto_confirm * 86400;
if ($send_time && $auto_confirm_unix) {
$auto_confirm_time = $send_time + $auto_confirm_unix;
if ($auto_confirm_time > time()) {
$status_desc .= ',还剩' . diff_in_time($auto_confirm_time, null, true, true) . '自动确认';
}
}
$btns[] = 'confirm'; // 确认收货
$backendBtns[] = 'refund';
}
break;
case 'nosend':
$status_text = '待发货';
$status_desc = '等待卖家发货';
$statusCodes = $this->getItemStatusCode();
if (in_array('noget', $statusCodes)) { // 只要存在待收货的item
$btns[] = 'confirm'; // 确认收货 (部分发货时也可以收货)
}
if ($this->isOffline($data)) {
// 发货之前用户可以取消
$btns[] = 'cancel'; // 用户取消订单
} else {
$backendBtns[] = 'refund';
}
$backendBtns[] = 'send';
if (!isset($ext['need_address']) || $ext['need_address']) { // 自动发货这些不需要收货地址的,没有 edit_consignee
$backendBtns[] = 'edit_consignee'; //修改收货地址
}
break;
case 'refund_completed':
$status_text = '退款完成';
$status_desc = '订单退款完成';
break;
case 'refund_agree':
$status_text = '退款完成';
$status_desc = '订单退款完成';
break;
case 'groupon_ing':
$status_text = '等待成团';
$status_desc = '等待拼团成功';
if ($this->isOffline($data)) {
// 货到付款未付款,不能退款,等待拼团时还未发货,用户可取消订单
$btns[] = 'cancel'; // 用户取消订单
} else {
$backendBtns[] = 'refund'; // 全部退款 直接不申请退款
}
break;
case 'groupon_invalid':
$status_text = '拼团失败';
$status_desc = '拼团失败';
break;
// 已支付的结束
case 'completed':
$status_text = '交易完成';
$status_desc = '交易已完成';
$btns[] = 'delete'; // 删除订单
break;
}
// 有活动
if (in_array($data['activity_type'], ['groupon', 'groupon_ladder', 'groupon_lucky'])) {
// 是拼团订单
if (isset($ext['groupon_id']) && $ext['groupon_id']) {
$btns[] = 'groupon'; // 拼团详情
}
}
if (in_array($this->status_code, ['nosend', 'groupon_ing']) && !$this->isOffline($data)) { // 线下付款订单,不可申请全额退款
if (in_array($data['apply_refund_status'], [Order::APPLY_REFUND_STATUS_NOAPPLY, Order::APPLY_REFUND_STATUS_REFUSE])) {
// 获取所有的 item 状态
$statusCodes = $this->getItemStatusCode();
if (count($statusCodes) == 1 && current($statusCodes) == 'nosend') {
// items 只有 未发货,就显示 申请退款按钮
if ($data['apply_refund_status'] == Order::APPLY_REFUND_STATUS_REFUSE) {
$btns[] = 're_apply_refund'; // 重新申请退款
} else {
$btns[] = 'apply_refund'; // 申请退款
}
}
}
}
if ($data['invoice_status'] == 1) {
$btns[] = 'invoice'; // 查看发票
} else if ($data['invoice_status'] == 0) {
if (in_array($this->status_code, ['commented', 'nocomment', 'noget', 'nosend', 'completed'])) {
$btns[] = 'apply_invoice'; // 申请发票
}
}
$return = null;
switch ($type) {
case 'status_text':
$return = $status_text;
break;
case 'btns':
$return = $btns;
break;
case 'status_desc':
$return = $status_desc;
break;
case 'backend_btns':
if (in_array('refund', $backendBtns)) {
// 判断是否有退款,如果存在退款就移除 refund 按钮
$refundCount = OrderItem::where('order_id', $data['id'])->where('refund_status', '<>', OrderItem::REFUND_STATUS_NOREFUND)->count();
if ($refundCount && ($key = array_search('refund', $backendBtns))) {
unset($backendBtns[$key]);
}
$backendBtns = array_values($backendBtns);
}
$return = $backendBtns;
break;
}
return $return;
}
/**
* 获取支付成功之后的子状态
*/
public function getPayedStatusCode($data)
{
$status_code = '';
// 获取所有的 item 状态
$statusCodes = $this->getItemStatusCode();
if (in_array('nosend', $statusCodes)) {
// 存在待发货就是待发货
$status_code = 'nosend';
} else if (in_array('noget', $statusCodes)) {
// 存在待收货,就是待收货
$status_code = 'noget';
} else if (in_array('nocomment', $statusCodes)) {
// 存在待评价,就是待评价
$status_code = 'nocomment';
} else if (in_array('commented', $statusCodes)) {
// 存在已评价,就是已评价
$status_code = 'commented';
} else if (in_array('refund_completed', $statusCodes)) {
// 所有商品退款完成,或者退款中(不可能存在待发货或者收货的商品,上面已判断过)
$status_code = 'refund_completed';
} else if (in_array('refund_agree', $statusCodes)) {
// 所有商品都同意退款了 (不可能存在待发货或者收货的商品,上面已判断过)
$status_code = 'refund_agree';
} // 售后都不在总状态显示
if ($data['apply_refund_status'] == Order::APPLY_REFUND_STATUS_APPLY && !in_array($status_code, ['refund_completed', 'refund_agree'])) {
return $status_code = 'apply_refund'; // 申请退款中,并且还没退款
}
$ext = $this->ext;
// 是拼团订单
if (
in_array($data['activity_type'], ['groupon', 'groupon_ladder', 'groupon_lucky']) &&
isset($ext['groupon_id']) && $ext['groupon_id']
) {
$groupon = Groupon::where('id', $ext['groupon_id'])->find();
if ($groupon) {
if ($groupon['status'] == 'ing') {
// 尚未成团
$status_code = $statusCodes[0] ?? ''; // 拼团订单只能有一个商品
$status_code = in_array($status_code, ['refund_agree', 'refund_completed']) ? $status_code : 'groupon_ing'; // 如果订单已退款,则是退款状态,不显示拼团中
} else if ($groupon['status'] == 'invalid') {
$status_code = 'groupon_invalid';
}
}
}
return $status_code;
}
/**
* 获取订单items状态
*
* @param string $type
* @return array
*/
private function getItemStatusCode($type = 'order')
{
// 循环判断 item 状态
$itemStatusCode = [];
foreach ($this->items as $key => $item) {
// 获取 item status
$itemStatusCode[] = (new OrderItem)->getBaseStatusCode($item, $type);
}
// 取出不重复不为空的 status_code
$statusCodes = array_values(array_unique(array_filter($itemStatusCode)));
return $statusCodes;
}
private function getItemDispatchTypes()
{
$dispatchType = [];
foreach ($this->items as $key => $item) {
// 获取 item status
$dispatchType[] = $item['dispatch_type'];
}
$dispatchType = array_unique(array_filter($dispatchType)); // 过滤重复,过滤空值
return $dispatchType;
}
public function getStatusTextAttr($value, $data)
{
return $this->getStatus($data, 'status_text');
}
public function getStatusDescAttr($value, $data)
{
return $this->getStatus($data, 'status_desc');
}
public function getBtnsAttr($value, $data)
{
$btn_name = strpos(request()->url(), 'addons/shopro') !== false ? 'btns' : 'backend_btns';
return $this->getStatus($data, $btn_name);
}
// 获取订单状态
public function getStatusCodeAttr($value, $data)
{
$status_code = '';
switch ($data['status']) {
case Order::STATUS_CLOSED:
$status_code = 'closed'; // 订单交易关闭
break;
case Order::STATUS_CANCEL:
$status_code = 'cancel'; // 订单已取消
break;
case Order::STATUS_UNPAID:
$status_code = 'unpaid'; // 订单等待支付
break;
case Order::STATUS_PENDING:
$status_code = $this->getPayedStatusCode($data); // 订单线下付款
break;
case Order::STATUS_PAID:
// 根据 item 获取支付后的状态信息
$status_code = $this->getPayedStatusCode($data);
break;
case Order::STATUS_COMPLETED:
$status_code = 'completed';
break;
}
return $status_code;
}
/**
* 处理未支付 item status_code
* 查询列表 item status_code 不关联订单表,使用这个方法进行处理
*/
public function setOrderItemStatusByOrder($order)
{
$order = $order instanceof \think\Model ? $order->toArray() : $order;
foreach ($order['items'] as $key => &$item) {
if ((!in_array($order['status'], [Order::STATUS_PAID, Order::STATUS_COMPLETED]) && !$this->isOffline($order)) // 没有支付,并且也不是货到付款
|| $order['apply_refund_status'] == Order::APPLY_REFUND_STATUS_APPLY) {
// 未支付status_code = 订单的 status_code
$item['status_code'] = $order['status_code'];
$item['status_text'] = '';
$item['status_desc'] = '';
$item['btns'] = [];
} else {
if (strpos(request()->url(), 'addons/shopro') !== false) {
// 前端
if (strpos($item['status_code'], 'nosend') !== false) {
if (!$this->isOffline($order) && !array_intersect(['re_apply_refund', 'apply_refund'], $order['btns'])) {
// 不能申请全额退款了(有部分发货,或者退款)的待发货的 item 要显示申请售后的按钮
$aftersale_id = (isset($item['ext']['aftersale_id']) && !empty($item['ext']['aftersale_id'])) ? $item['ext']['aftersale_id'] : 0;
if (strpos($item['status_code'], 'aftersale_ing') === false && strpos($item['status_code'], 'aftersale_completed') === false) {
// 不是售后中,也不是售后完成
if (strpos($item['status_code'], 'aftersale_refuse') !== false && $aftersale_id) {
// 如果申请过退款,被拒绝了,则为重新申请售后
$item['btns'][] = 're_aftersale';
} else {
// 取消售后是 re_aftersale ,未申请过是 aftersale
$item['btns'][] = $aftersale_id ? 're_aftersale' : 'aftersale'; // 售后,售后取消会有 aftersale_id
}
}
}
} else if (strpos($item['status_code'], 'noget') !== false) {
// 如果是货到付款的 待收货
if ($this->isOffline($order)) {
foreach($item['btns'] as $btnk => $btn) {
if (in_array($btn, ['re_aftersale', 'aftersale'])) {
unset($item['btns'][$btnk]);
}
}
}
}
} else {
// 后端,如果是货到付款, 并且还没收货,不显示退款按钮
if ($this->isOffline($order) && (strpos($item['status_code'], 'nosend') !== false || strpos($item['status_code'], 'noget') !== false)) {
$refund_key = array_search('refund', $item['btns']);
if ($refund_key !== false) {
unset($item['btns'][$refund_key]);
}
}
}
}
}
return $order;
}
}

View File

@@ -0,0 +1,176 @@
<?php
namespace app\admin\model\shopro\trade;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
use app\admin\model\shopro\user\User;
use app\admin\model\shopro\Pay as PayModel;
class Order extends Common
{
use SoftDelete;
protected $name = 'shopro_trade_order';
protected $deleteTime = 'deletetime';
protected $type = [
'ext' => 'json',
'paid_time' => 'timestamp',
];
// 追加属性
protected $append = [
'type_text',
'status_text',
'platform_text',
];
// 订单状态
const STATUS_CLOSED = 'closed';
const STATUS_CANCEL = 'cancel';
const STATUS_UNPAID = 'unpaid';
const STATUS_PAID = 'paid';
const STATUS_COMPLETED = 'completed';
public function statusList()
{
return [
'closed' => '交易关闭',
'cancel' => '已取消',
'unpaid' => '未支付',
'paid' => '已支付',
'completed' => '已完成'
];
}
/**
* 订单列表状态搜索
*/
public function searchStatusList()
{
return [
'unpaid' => '待付款',
'paid' => '已支付', // 包括刚支付的,以及已完成的所有付过款的订单
'completed' => '已完成',
'cancel' => '已取消',
'closed' => '交易关闭',
];
}
public function typeList()
{
return [
'recharge' => '充值订单',
];
}
public function platformList()
{
return [
'H5' => 'H5',
'WechatOfficialAccount' => '微信公众号',
'WechatMiniProgram' => '微信小程序',
'App' => 'App',
];
}
public function getPlatformTextAttr($value, $data)
{
$value = $value ?: ($data['platform'] ?? null);
$list = $this->platformList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 已支付订单,支付类型
*
* @param string $value
* @param array $data
* @return void
*/
public function getPayTypeAttr($value, $data)
{
$status = $data['status'] ?? '';
$payTypes = [];
if (in_array($status, [self::STATUS_PAID, self::STATUS_COMPLETED])) {
$payTypes = PayModel::typeTradeOrder()->where('order_id', $data['id'])->where('status', '<>', PayModel::PAY_STATUS_UNPAID)->group('pay_type')->column('pay_type');
}
return $payTypes[0] ?? '';
}
/**
* 已支付订单,支付类型文字
*
* @param string $value
* @param array $data
* @return void
*/
public function getPayTypeTextAttr($value, $data)
{
$pay_types = $this->pay_type;
$list = (new PayModel)->payTypeList();
return isset($list[$pay_types]) ? $list[$pay_types] : '';
}
// 已关闭
public function scopeClosed($query)
{
return $query->where('status', Order::STATUS_CLOSED);
}
// 已取消
public function scopeCancel($query)
{
return $query->where('status', Order::STATUS_CANCEL);
}
// 未支付
public function scopeUnpaid($query)
{
return $query->where('status', Order::STATUS_UNPAID);
}
// 已支付
public function scopePaid($query)
{
return $query->whereIn('status', [Order::STATUS_PAID, Order::STATUS_COMPLETED]);
}
// 已完成
public function scopeCompleted($query)
{
return $query->where('status', Order::STATUS_COMPLETED);
}
public function scopeRecharge($query)
{
return $query->where('type', 'recharge');
}
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function pays()
{
return $this->hasMany(PayModel::class, 'order_id', 'id')->typeTradeOrder();
}
}

View File

@@ -0,0 +1,222 @@
<?php
namespace app\admin\model\shopro\traits;
trait ModelAttr
{
/**
* 默认类型列表,子类重写
*
* @return array
*/
public function typeList()
{
return [];
}
/**
* 默认状态列表,子类可重写
*
* @return array
*/
public function statusList()
{
return [
'normal' => '正常',
'hidden' => '隐藏',
'enable' => '启用中',
'disabled' => '已禁用',
'up' => '上架',
'down' => '下架',
];
}
/**
* (查询范围)正常
*/
public function scopeNormal($query)
{
return $query->where('status', 'normal');
}
/**
* (查询范围)启用
*/
public function scopeEnable($query)
{
return $query->where('status', 'enable');
}
/**
* (查询范围)禁用
*/
public function scopeDisabled($query)
{
return $query->where('status', 'disabled');
}
/**
* (查询范围)隐藏 hidden 和框架底层 hidden 冲突了
*/
public function scopeStatusHidden($query)
{
return $query->where('status', 'hidden');
}
/**
* (查询范围)上架
*/
public function scopeUp($query)
{
return $query->where('status', 'up');
}
/**
* (查询范围)下架
*/
public function scopeDown($query)
{
return $query->where('status', 'down');
}
// /**
// * 创建时间格式化
// *
// * @param string $value
// * @param array $data
// * @return string
// */
// public function getCreatetimeAttr($value, $data)
// {
// return $this->attrTimeFormat($value, $data, 'createtime');
// }
// /**
// * 更新时间格式化
// *
// * @param string $value
// * @param array $data
// * @return string
// */
// public function getUpdatetimeAttr($value, $data)
// {
// return $this->attrTimeFormat($value, $data, 'updatetime');
// }
/**
* 更新时间格式化
*
* @param string $value
* @param array $data
* @return string
*/
public function getDeletetimeAttr($value, $data)
{
return $this->attrTimeFormat($value, $data, 'deletetime');
}
/**
* 通用类型获取器
*
* @param string $value
* @param array $data
* @return string
*/
public function getTypeTextAttr($value, $data)
{
$value = $value ?: ($data['type'] ?? null);
$list = $this->typeList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 通用状态获取器
*
* @param string $value
* @param array $data
* @return string
*/
public function getStatusTextAttr($value, $data)
{
$value = $value ?: ($data['status'] ?? '');
$list = $this->statusList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 时间格式化
*
* @param mix $value
* @param array $data
* @param string $field
* @return string
*/
protected function attrTimeFormat($value, $data, $field)
{
$value = $value ?: ($data[$field] ?? null);
return $value ? (is_string($value) ? $value : date('Y-m-d H:i:s', $value)) : null;
}
/**
* 获取器格式化 json
*
* @param mix $value
* @param array $data
* @param string $field
* @param bool $return_array
* @return array|null
*/
protected function attrFormatJson($value, $data, $field, $return_array = false)
{
$value = $value ?: ($data[$field] ?? null);
$value = $value ? json_decode($value, true) : ($return_array ? [] : $value);
return $value === false ? $data[$field] : $value;
}
/**
* 获取器格式化 , 隔开的数据
*
* @param mix $value
* @param array $data
* @param string $field
* @param bool $return_array
* @return array|null
*/
protected function attrFormatComma($value, $data, $field, $return_array = false)
{
$value = $value ?: ($data[$field] ?? null);
$value = $value ? explode(',', $value) : ($return_array ? [] : $value);
return $value === false ? $data[$field] : $value;
}
/**
* 将时间格式化为时间戳
*
* @param [type] $time
* @return void
*/
protected function attrFormatUnix($time)
{
return $time ? (!is_numeric($time) ? strtotime($time) : $time) : null;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace app\admin\model\shopro\user;
use app\admin\model\shopro\Common;
class Account extends Common
{
protected $name = 'shopro_user_account';
protected $type = [];
// 追加属性
protected $append = [
'type_text'
];
protected $typeMap = [
'wechat' => '微信零钱',
'alipay' => '支付宝账户',
'bank' => '银行卡转账'
];
public function getTypeTextAttr($value, $data)
{
return $this->typeMap[$data['type']];
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace app\admin\model\shopro\user;
use app\admin\model\shopro\Common;
class Address extends Common
{
protected $name = 'shopro_user_address';
protected $type = [
'is_default' => 'boolean'
];
// 追加属性
protected $append = [];
public function scopeDefault($query)
{
return $query->where('is_default', 1);
}
}

View File

@@ -0,0 +1,308 @@
<?php
namespace app\admin\model\shopro\user;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\Coupon as CouponModel;
use app\admin\model\shopro\user\User as UserModel;
use app\admin\model\shopro\order\Order as OrderModel;
class Coupon extends Common
{
protected $name = 'shopro_user_coupon';
protected $type = [
'use_time' => 'timestamp'
];
// 追加属性
protected $append = [
'name',
'type',
'type_text',
'use_scope',
'use_scope_text',
'items',
'amount',
'amount_text',
'enough',
'limit_num',
'use_start_time',
'use_end_time',
'max_amount',
'is_double_discount',
'description',
'status',
'status_text',
];
public function statusList()
{
return [
'used' => '已使用',
'can_use' => '立即使用',
'expired' => '已过期',
'cannot_use' => '暂不可用',
'geted' => '未使用' // 包括 can_use 和 cannot_use
];
}
public function scopeGeted($query)
{
return $query->whereNull('use_time')->whereExists(function ($query) {
$table_name = (new CouponModel)->getQuery()->getTable();
$user_coupon_name = (new self)->getQuery()->getTable();
$query->table($table_name)->whereNull('deletetime')->whereIn('status', ['normal', 'hidden'])
->where($user_coupon_name . '.coupon_id=' . $table_name . '.id')
->where(function ($query) use ($user_coupon_name) {
$query->where(function ($query) {
$query->where('use_time_type', 'range')->where('use_end_time', '>=', time()); // 可用结束时间,大于当前时间,已经可用,或者暂不可用都算
})->whereOr(function ($query) use ($user_coupon_name) {
$query->where('use_time_type', 'days')
->whereRaw($user_coupon_name . '.createtime + ((start_days + days) * 86400) >= ' . time()); // 可用结束结束时间大于当前时间
});
});
});
}
// 可以使用
public function scopeCanUse($query)
{
return $query->whereNull('use_time')->whereExists(function ($query) {
$table_name = (new CouponModel)->getQuery()->getTable();
$user_coupon_name = (new self)->getQuery()->getTable();
$query->table($table_name)->whereNull('deletetime')->whereIn('status', ['normal', 'hidden'])
->where($user_coupon_name . '.coupon_id=' . $table_name . '.id')
->where(function ($query) use ($user_coupon_name) {
$query->where(function ($query) {
$query->where('use_time_type', 'range')->where('use_start_time', '<=', time())->where('use_end_time', '>=', time());
})->whereOr(function ($query) use ($user_coupon_name) {
$query->where('use_time_type', 'days')
->whereRaw($user_coupon_name . '.createtime + (start_days * 86400) <= ' . time())
->whereRaw($user_coupon_name . '.createtime + ((start_days + days) * 86400) >= ' . time());
});
});
});
}
// 暂不可用,还没到可使用日期
public function scopeCannotUse($query)
{
return $query->whereNull('use_time')->whereExists(function ($query) {
$table_name = (new CouponModel)->getQuery()->getTable();
$user_coupon_name = (new self)->getQuery()->getTable();
$query->table($table_name)->whereNull('deletetime')->whereIn('status', ['normal', 'hidden'])
->where($user_coupon_name . '.coupon_id=' . $table_name . '.id')
->where(function ($query) use ($user_coupon_name) {
$query->where(function ($query) {
$query->where('use_time_type', 'range')->where('use_start_time', '>', time());
})->whereOr(function ($query) use ($user_coupon_name) {
$query->where('use_time_type', 'days')
->whereRaw($user_coupon_name . '.createtime + (start_days * 86400) > ' . time());
});
});
});
}
// 已使用
public function scopeUsed($query)
{
return $query->whereNotNull('use_time');
}
// 未使用,但已过期
public function scopeExpired($query)
{
return $query->whereNull('use_time')->whereExists(function ($query) {
$table_name = (new CouponModel)->getQuery()->getTable();
$user_coupon_name = (new self)->getQuery()->getTable();
$query->table($table_name)->whereNull('deletetime')->whereIn('status', ['normal', 'hidden'])
->where($user_coupon_name . '.coupon_id=' . $table_name . '.id')
->where(function ($query) use ($user_coupon_name) {
$query->where(function ($query) {
$query->where('use_time_type', 'range')->where('use_end_time', '<', time());
})->whereOr(function ($query) use ($user_coupon_name) {
$query->where('use_time_type', 'days')
->whereRaw($user_coupon_name . '.createtime + ((start_days + days) * 86400) < ' . time());
});
});
});
}
// 未使用,但已过期,或者已使用
public function scopeInvalid($query)
{
return $query->where(function ($query) {
$query->whereNotNull('use_time')->whereOr(function ($query) {
$query->whereNull('use_time')->whereExists(function ($query) {
$table_name = (new CouponModel)->getQuery()->getTable();
$user_coupon_name = (new self)->getQuery()->getTable();
$query->table($table_name)->whereNull('deletetime')->whereIn('status', ['normal', 'hidden'])
->where($user_coupon_name . '.coupon_id=' . $table_name . '.id')
->where(function ($query) use ($user_coupon_name) {
$query->where(function ($query) {
$query->where('use_time_type', 'range')->where('use_end_time', '<', time());
})->whereOr(function ($query) use ($user_coupon_name) {
$query->where('use_time_type', 'days')
->whereRaw($user_coupon_name . '.createtime + ((start_days + days) * 86400) < ' . time());
});
});
});
});
});
}
public function getNameAttr($value, $data)
{
return $this->coupon ? $this->coupon->name : '';
}
public function getTypeAttr($value, $data)
{
return $this->coupon ? $this->coupon->type : '';
}
public function getUseScopeAttr($value, $data)
{
return $this->coupon ? $this->coupon->use_scope : '';
}
public function getItemsAttr($value, $data)
{
return $this->coupon ? $this->coupon->items : '';
}
public function getAmountAttr($value, $data)
{
return $this->coupon ? $this->coupon->amount : '';
}
public function getEnoughAttr($value, $data)
{
return $this->coupon ? $this->coupon->enough : '';
}
public function getLimitNumAttr($value, $data)
{
return $this->coupon ? $this->coupon->limit_num : '';
}
public function getUseStartTimeAttr($value, $data)
{
if ($this->coupon) {
if ($this->coupon->use_time_type == 'days') {
return date('Y-m-d H:i:s', $data['createtime'] + ($this->coupon->start_days * 86400));
}
return $this->coupon->use_start_time;
}
}
public function getUseEndTimeAttr($value, $data)
{
if ($this->coupon) {
if ($this->coupon->use_time_type == 'days') {
return date('Y-m-d H:i:s', $data['createtime'] + (($this->coupon->start_days + $this->coupon->days) * 86400));
}
return $this->coupon->use_end_time;
}
}
public function getMaxAmountAttr($value, $data)
{
return $this->coupon ? $this->coupon->max_amount : 0;
}
public function getIsDoubleDiscountAttr($value, $data)
{
return $this->coupon ? $this->coupon->is_double_discount : 0;
}
public function getDescriptionAttr($value, $data)
{
return $this->coupon ? $this->coupon->description : '';
}
public function getUseScopeTextAttr($value, $data)
{
return $this->coupon ? $this->coupon->use_scope : 0;
}
public function getAmountTextAttr($value, $data)
{
return $this->coupon ? $this->coupon->amount_text : 0;
}
public function getItemsValueAttr($value, $data)
{
return $this->coupon ? $this->coupon->items_value : 0;
}
public function getTypeTextAttr($value, $data)
{
return $this->coupon ? $this->coupon->type_text : 0;
}
// 我的优惠券使用状态
public function getStatusAttr($value, $data)
{
if ($data['use_time']) {
$status = 'used';
} else {
if ($this->use_start_time <= date('Y-m-d H:i:s') && $this->use_end_time >= date('Y-m-d H:i:s')) {
$status = 'can_use';
} else if ($this->use_end_time <= date('Y-m-d H:i:s')) {
$status = 'expired';
} else {
// 未到使用日期
$status = 'cannot_use';
}
}
return $status;
}
public function getStatusTextAttr($value, $data)
{
$value = $value ?: ($this->status ?? '');
if (strpos(request()->url(), 'addons/shopro') === false) {
$value = in_array($value, ['can_use', 'cannot_use']) ? 'geted' : $value; // 后台,可以使用和咱不可用 合并
}
$list = $this->statusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function coupon()
{
return $this->belongsTo(CouponModel::class, 'coupon_id');
}
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function order()
{
return $this->belongsTo(OrderModel::class, 'use_order_id');
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace app\admin\model\shopro\user;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\goods\Goods;
class GoodsLog extends Common
{
protected $name = 'shopro_user_goods_log';
// 追加属性
protected $append = [
];
/**
* 添加浏览记录
*
* @param object $user
* @param object $goods
* @return void
*/
public static function addView($user, $goods)
{
if ($user) {
$view = self::views()->where('user_id', $user->id)->where('goods_id', $goods->id)->find();
if ($view) {
$view->updatetime = time();
$view->save();
} else {
$view = new self();
$data = [
'goods_id' => $goods->id,
'user_id' => $user->id,
'type' => 'views'
];
$view->save($data);
}
}
// 增加商品浏览量
Goods::where('id', $goods['id'])->update(['views' => \think\Db::raw('views+1')]);
}
public function scopeFavorite($query)
{
return $query->where('type', 'favorite');
}
public function scopeViews($query) // view 和底层方法冲突了
{
return $query->where('type', 'views');
}
public function goods()
{
return $this->belongsTo(Goods::class, 'goods_id');
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace app\admin\model\shopro\user;
use app\admin\model\shopro\Common;
class Invoice extends Common
{
protected $name = 'shopro_user_invoice';
// 追加属性
protected $append = [
'type_text',
];
public function typeList()
{
return [
'person' => '个人',
'company' => '企/事业单位',
];
}
}

View File

@@ -0,0 +1,136 @@
<?php
namespace app\admin\model\shopro\user;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\Coupon as CouponModel;
use app\admin\model\shopro\ThirdOauth;
use addons\shopro\library\notify\traits\Notifiable;
use fast\Random;
class User extends Common
{
use Notifiable;
protected $name = 'user';
protected $type = [
'logintime' => 'timestamp',
'jointime' => 'timestamp',
'prevtime' => 'timestamp',
];
protected $hidden = ['password', 'salt'];
protected $append = [
'status_text',
'gender_text'
];
public function getGenderList()
{
return ['1' => __('Male'), '0' => __('Female')];
}
/**
* 获取性别文字
* @param string $value
* @param array $data
* @return object
*/
public function getGenderTextAttr($value, $data)
{
$value = $value ?: ($data['gender'] ?? 0);
$list = $this->getGenderList();
return isset($list[$value]) ? $list[$value] : '';
}
public function setMobileAttr($value, $data)
{
if ($value !== "") {
return $value;
}
return null;
}
public function setUsernameAttr($value, $data)
{
if ($value !== "") {
return $value;
}
return null;
}
public function getAvatarAttr($value, $data)
{
if (empty($value)) {
$config = sheep_config('shop.user');
$value = $config['avatar'];
}
return $value;
}
public function setEmailAttr($value, $data)
{
if ($value !== "") {
return $value;
}
return null;
}
public function setPasswordAttr($value, $data)
{
$salt = Random::alnum();
$this->salt = $salt;
return \app\common\library\Auth::instance()->getEncryptPassword($value, $salt);
}
public function getNicknameHideAttr($value, $data)
{
$value = $value ?: ($data['nickname'] ?? '');
return $value ? string_hide($value, 2) : $value;
}
public function getMobileAttr($value, $data)
{
$value = $value ?: ($data['mobile'] ?? '');
return $value ? (operate_filter(false) ? $value : account_hide($value, 3, 3)) : $value;
}
/**
* 获取验证字段数组值
* @param string $value
* @param array $data
* @return object
*/
public function getVerificationAttr($value, $data)
{
$value = array_filter((array)json_decode($value, true));
$value = array_merge(['username' => 0, 'password' => 0, 'mobile' => 0], $value);
return (object)$value;
}
public function parentUser()
{
return $this->hasOne(User::class, 'id', 'parent_user_id')->field(['id', 'avatar', 'nickname', 'gender']);
}
public function thirdOauth()
{
return $this->hasMany(ThirdOauth::class, 'user_id', 'id');
}
// -- commission code start --
public function agent()
{
return $this->hasOne(\app\admin\model\shopro\commission\Agent::class, 'user_id', 'id');
}
// -- commission code end --
}

View File

@@ -0,0 +1,79 @@
<?php
namespace app\admin\model\shopro\user;
use app\admin\model\shopro\Common;
class WalletLog extends Common
{
protected $name = 'shopro_user_wallet_log';
protected $updateTime = false;
protected $type = [
'ext' => 'json'
];
// 追加属性
protected $append = [
'event_text'
];
const TYPE_MAP = [
'money' => '余额',
'score' => '积分',
'commission' => '佣金'
];
protected $eventMap = [
'score' => [
'signin' => '签到-赠送积分',
'replenish_signin' => '签到-补签',
'activity_gift' => '活动-赠送积分',
'score_shop_pay' => '积分商城-积分支付',
'order_pay' => '商城订单-积分抵扣',
'order_refund' => '订单退款-退还积分',
'admin_recharge' => '后台-积分充值',
'recharge_gift' => '线上充值-赠送积分'
],
'money' => [
'order_pay' => '商城订单-余额支付',
'order_recharge' => '线上充值',
'admin_recharge' => '后台-余额充值',
'recharge_gift' => '线上充值-赠送余额',
'activity_gift' => '活动-赠送余额',
'order_refund' => '订单退款-退还余额',
'transfer_by_commission' => '佣金-转入到余额'
],
'commission' => [
'withdraw' => '提现',
'withdraw_error' => '提现失败-返还佣金',
'reward_income' => '佣金-收益',
'reward_back' => '佣金-退还',
'transfer_to_money' => '佣金-转出到余额'
]
];
public function getEventMap() {
return $this->eventMap;
}
public function scopeMoney($query)
{
return $query->where('type', 'money');
}
public function scopeCommission($query)
{
return $query->where('type', 'commission');
}
public function scopeScore($query)
{
return $query->where('type', 'score');
}
public function getEventTextAttr($value, $data)
{
return $this->eventMap[$data['type']][$data['event']] ?? '';
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace app\admin\model\shopro\wechat;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
class Material extends Common
{
use SoftDelete;
protected $deleteTime = 'deletetime';
protected $name = 'shopro_wechat_material';
protected $type = [
'content' => 'json',
];
// 追加属性
protected $append = [
'type_text'
];
public function typeList()
{
return ['text' => '文字', 'link' => '链接'];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace app\admin\model\shopro\wechat;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
class Menu extends Common
{
protected $name = 'shopro_wechat_menu';
protected $type = [
'rules' => 'json',
'publishtime' => 'timestamp',
];
// 追加属性
protected $append = [
'status_text'
];
/**
* 状态列表
*
* @return array
*/
public function statusList()
{
return [0 => '未发布', 1 => '已发布'];
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace app\admin\model\shopro\wechat;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
class Reply extends Common
{
use SoftDelete;
protected $deleteTime = 'deletetime';
protected $name = 'shopro_wechat_reply';
// 追加属性
protected $append = [
'type_text',
'group_text',
'status_text',
];
public function getKeywordsAttr($value, $data)
{
if (!empty($value)) {
return explode(',', $value);
}
return [];
}
public function setKeywordsAttr($value, $data)
{
if (!empty($value)) {
return implode(',', $value);
}
return null;
}
/**
* 状态列表
*
* @return array
*/
public function typeList()
{
return ['text' => '文字', 'link' => '链接', 'image' => '图片', 'voice' => '语音', 'video' => '视频', 'news' => '图文消息'];
}
/**
* 通用类型获取器
*
* @param string $value
* @param array $data
* @return string
*/
public function getGroupTextAttr($value, $data)
{
$list = ['keywords' => '关键词回复', 'subscribe' => '关注回复', 'default' => '默认回复'];
$value = $value ?: ($data['group'] ?? null);
return isset($list[$value]) ? $list[$value] : '';
}
}