chore: 添加静态资源文件和版本配置文件

添加大量图片、字体、音频等静态资源文件,包括用户界面图片、模板文件和安装界面素材
添加系统版本配置文件(.version)和常量定义文件(.constant)
更新供应商依赖文件,包括Symfony VarDumper组件和相关许可证文件
添加验证码配置文件(captcha.php)和.gitignore规则
This commit is contained in:
2026-03-06 20:14:23 +08:00
commit c9a98f342c
4485 changed files with 490986 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\kefu;
use app\Request;
use crmeb\basic\BaseController;
/**
* Class AuthController
* @package app\kefuapi\controller
* @property Request $request
*/
abstract class AuthController extends BaseController
{
/**
* @var int
*/
protected $kefuId;
/**
* @var array
*/
protected $kefuInfo;
/**
* 初始化
*/
protected function initialize()
{
$this->kefuId = $this->request->kefuId();
$this->kefuInfo = $this->request->kefuInfo();
}
}

View File

@@ -0,0 +1,288 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\kefu;
use app\Request;
use app\services\kefu\KefuServices;
use app\services\kefu\ProductServices;
use app\services\message\service\StoreServiceRecordServices;
use app\services\order\StoreOrderServices;
use app\services\system\attachment\SystemAttachmentServices;
use app\services\user\UserAuthServices;
use crmeb\basic\BaseController;
use app\services\user\UserServices;
use app\services\other\CacheServices;
use app\services\message\service\StoreServiceServices;
use app\validate\api\user\StoreServiceFeedbackValidate;
use app\services\message\service\StoreServiceFeedbackServices;
use crmeb\exceptions\AuthException;
use crmeb\services\UploadService;
use crmeb\utils\Arr;
use crmeb\utils\JwtAuth;
use crmeb\services\CacheService;
use Psr\SimpleCache\InvalidArgumentException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
class Common extends BaseController
{
protected function initialize()
{
}
/**
* 获取erp开关
* @return mixed
*/
public function getErpConfig()
{
return $this->success(['open_erp' => !!sys_config('erp_open')]);
}
/**
* 获取客服页面广告内容
* @return mixed
*/
public function getKfAdv()
{
/** @var CacheServices $cache */
$cache = app()->make(CacheServices::class);
$content = $cache->getDbCache('kf_adv', '');
return $this->success(compact('content'));
}
/**
* 游客模式下获取客服
* @param StoreServiceServices $services
* @param UserServices $userServices
* @param StoreServiceRecordServices $recordServices
* @param string $token
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getServiceUser(StoreServiceServices $services, UserServices $userServices, StoreServiceRecordServices $recordServices, $token = '')
{
$serviceInfoList = $services->getServiceList(['status' => 1, 'online' => 1]);
if (!count($serviceInfoList['list'])) {
return $this->fail('暂无客服人员在线');
}
$uids = array_column($serviceInfoList['list'], 'uid');
$toUid = $tourist_uid = $uid = 0;
if ($token) {
try {
/** @var UserAuthServices $service */
$service = app()->make(UserAuthServices::class);
$authInfo = $service->parseToken($token);
$uid = $authInfo['user']['uid'];
$toUid = $recordServices->value(['user_id' => $uid], 'to_uid');
if (!in_array($toUid, $uids)) {
$toUid = 0;
}
} catch (AuthException $e) {
}
} else {
mt_srand();
$tourist_uid = rand(100000000, 999999999);
}
if (!$toUid) {
$toUid = Arr::getArrayRandKey($uids);
}
$userInfo = $userServices->get($toUid, ['nickname', 'avatar', 'real_name', 'uid']);
if ($userInfo) {
$infoList = array_column($serviceInfoList['list'], null, 'uid');
if (isset($infoList[$toUid])) {
if ($infoList[$toUid]['wx_name']) {
$userInfo['nickname'] = $infoList[$toUid]['wx_name'];
}
if ($infoList[$toUid]['avatar']) {
$userInfo['avatar'] = $infoList[$toUid]['avatar'];
}
}
$userInfo['tourist_uid'] = $uid ? $uid : $tourist_uid;
$tourist_avatar = sys_config('tourist_avatar');
$avatar = Arr::getArrayRandKey(is_array($tourist_avatar) ? $tourist_avatar : []);
$userInfo['tourist_avatar'] = $uid ? '' : $avatar;
$userInfo['is_tourist'] = (bool)$tourist_uid;
return $this->success($userInfo->toArray());
} else {
return $this->fail('暂无客服人员');
}
}
/**
* 保存反馈信息
* @param Request $request
* @param StoreServiceFeedbackServices $services
* @return mixed
*/
public function saveFeedback(Request $request, StoreServiceFeedbackServices $services)
{
$data = $request->postMore([
['rela_name', ''],
['phone', ''],
['content', ''],
]);
validate(StoreServiceFeedbackValidate::class)->check($data);
$data['content'] = htmlspecialchars($data['content']);
$data['add_time'] = time();
$services->save($data);
return $this->success('保存成功');
}
/**
* 客服反馈页面头部文字
* @return mixed
*/
public function getFeedbackInfo()
{
return $this->success(['feedback' => sys_config('service_feedback')]);
}
/**
* 聊天记录
* @param Request $request
* @param KefuServices $services
* @param string $token
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getChatList(Request $request, KefuServices $services, $token = '')
{
[$uid, $upperId] = $request->postMore([
['uid', 0],
['upperId', 0],
], true);
if (!$uid) {
return $this->fail('缺少参数');
}
if (!$token) {
return $this->fail('缺少登录token');
}
try {
/** @var UserAuthServices $service */
$service = app()->make(UserAuthServices::class);
$authInfo = $service->parseToken($token);
} catch (AuthException $e) {
return $this->fail('无效的token不能查找到用户聊天记录');
}
return $this->success($services->getChatList($authInfo['user']['uid'], $uid, (int)$upperId));
}
/**
* 商品详情
* @param ProductServices $services
* @param $id
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getProductInfo(ProductServices $services, $id)
{
return $this->success($services->getProductInfo((int)$id));
}
/**
* 获取订单信息
* @param StoreOrderServices $services
* @param $token
* @param $order_id
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getOrderInfo(StoreOrderServices $services, $token, $order_id)
{
try {
/** @var UserAuthServices $service */
$service = app()->make(UserAuthServices::class);
$authInfo = $service->parseToken($token);
if (!isset($authInfo['user']['uid'])) {
return $this->fail('非法操作');
}
} catch (AuthException $e) {
return $this->fail('无效的token不能查找到用户聊天记录');
}
return $this->success($services->tidyOrder($services->getUserOrderDetail($order_id, $authInfo['user']['uid'])->toArray(), true));
}
/**
* 图片上传
* @param Request $request
* @param SystemAttachmentServices $services
* @return mixed
* @throws InvalidArgumentException
*/
public function upload(Request $request, SystemAttachmentServices $services)
{
$data = $request->postMore([
['filename', 'file'],
]);
try {
/** @var UserAuthServices $service */
$service = app()->make(UserAuthServices::class);
$authInfo = $service->parseToken($this->request->post('token'));
if (!isset($authInfo['user']['uid'])) {
return $this->fail('非法操作');
}
} catch (AuthException $e) {
return $this->fail('无效的token不能使用上传图片功能');
}
$uid = $authInfo['user']['uid'];
if (!$data['filename']) return $this->fail('参数有误');
if (CacheService::has('start_uploads_' . $uid) && CacheService::get('start_uploads_' . $uid) >= 100) return $this->fail('非法操作');
$upload = UploadService::init();
$info = $upload->to('store/comment')->validate()->move($data['filename']);
if ($info === false) {
return $this->fail($upload->getError());
}
$res = $upload->getUploadInfo();
$services->attachmentAdd($res['name'], $res['size'], $res['type'], $res['dir'], $res['thumb_path'], 1, (int)sys_config('upload_type', 1), $res['time'], 2);
if (CacheService::has('start_uploads_' . $uid))
$start_uploads = (int)CacheService::get('start_uploads_' . $uid);
else
$start_uploads = 0;
$start_uploads++;
CacheService::set('start_uploads_' . $uid, $start_uploads, 86400);
$res['dir'] = path_to_url($res['dir']);
if (strpos($res['dir'], 'http') === false) $res['dir'] = $request->domain() . $res['dir'];
return $this->success('图片上传成功!', ['name' => $res['name'], 'url' => $res['dir']]);
}
/**
* 获取版权
* @return mixed
*/
public function getCopyright()
{
$res = false;
try {
$copyright = $this->__z6uxyJQ4xYa5ee1mx5();
$res = true;
} catch (\Throwable $e) {
$copyright = ['copyrightContext' => '', 'copyrightImage' => ''];
}
$copyright['is_copyright'] = $res;
return $this->success($copyright);
}
}

View File

@@ -0,0 +1,111 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\kefu;
use app\Request;
use crmeb\basic\BaseController;
use crmeb\services\CacheService;
use app\services\kefu\LoginServices;
use app\validate\kefu\LoginValidate;
use Psr\SimpleCache\InvalidArgumentException;
use think\annotation\Inject;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* Class Login
* @package app\kefu\controller
*/
class Login extends BaseController
{
/**
* @var LoginServices
*/
#[Inject]
protected LoginServices $services;
/**
* 客服登录
* @param Request $request
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function login(Request $request)
{
[$account, $password] = $request->postMore([
['account', ''],
['password', ''],
], true);
$this->validate(['account' => $account, 'password' => $password], LoginValidate::class);
$token = $this->services->authLogin($account, $password);
return $this->success('登录成功', $token);
}
/**
* 开放平台扫码登录
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function wechatAuth()
{
return $this->success($this->services->wechatAuth());
}
/**
* 获取公众平台id
* @return mixed
*/
public function getAppid()
{
return $this->success([
'appid' => sys_config('wechat_open_app_id', 'wxc736972a4ca1e2a1'),
'version' => get_crmeb_version(),
'site_name' => sys_config('site_name')
]);
}
/**
* 获取登录唯一code
* @return mixed
*/
public function getLoginKey()
{
$key = md5(time() . uniqid());
$time = time() + 600;
CacheService::set($key, 1, 600);
return $this->success(['key' => $key, 'time' => $time]);
}
/**
* 验证登录
* @param string $key
* @return mixed
* @throws InvalidArgumentException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function scanLogin(string $key)
{
return $this->success($this->services->scanLogin($key));
}
}

View File

@@ -0,0 +1,440 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\kefu;
use app\Request;
use app\services\activity\coupon\StoreCouponIssueServices;
use app\services\activity\combination\StorePinkServices;
use app\services\order\StoreOrderWriteOffServices;
use FormBuilder\Exception\FormBuilderException;
use think\annotation\Inject;
use app\services\store\DeliveryServiceServices;
use app\services\order\StoreOrderPromotionsServices;
use app\services\product\product\StoreProductServices;
use app\services\serve\ServeServices;
use app\services\other\ExpressServices;
use app\services\user\UserServices;
use app\services\order\StoreOrderServices;
use app\services\order\StoreOrderRefundServices;
use app\services\order\StoreOrderDeliveryServices;
use app\services\store\SystemStoreServices;
use app\validate\admin\order\StoreOrderValidate;
use app\services\message\service\StoreServiceRecordServices;
use \app\common\controller\Order as CommonOrder;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\response\Json;
/**
* Class Order
* @package app\kefuapi\controller
*/
class Order extends AuthController
{
use CommonOrder;
/**
* @var StoreOrderServices
*/
#[Inject]
protected StoreOrderServices $services;
/**
* 获取订单列表
* @param Request $request
* @param StoreServiceRecordServices $services
* @param StoreOrderRefundServices $storeOrderRefundServices
* @param $uid
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getUserOrderList(Request $request, StoreServiceRecordServices $services, StoreOrderRefundServices $storeOrderRefundServices, $uid)
{
$where = $request->getMore([
['type', '', '', 'status'],
['search', '', '', 'real_name'],
]);
$where['uid'] = $uid;
$where['is_del'] = 0;
$where['is_system_del'] = 0;
$where['refund_type'] = [0, 1, 3, 6];
if (!$services->count(['to_uid' => $uid])) {
return $this->fail('用户uid不再当前聊天用户范围内');
}
if ($where['status'] == -1) {
$list = $storeOrderRefundServices->refundList(['uid' => $where['uid'], 'real_name' => $where['real_name'], 'refund_type' => [0, 1, 2, 4, 5]])['list'] ?? [];
} else {
$where['store_id'] = 0;
$list = $this->services->getOrderApiList($where + ['pid' => 0], ['*'], ['pink', 'invoice']);
}
return $this->success($list);
}
/**
* 订单发货
* @return mixed
* @throws DataNotFoundException
* @throws ModelNotFoundException
* @throws DbException
*/
public function delivery_keep(StoreOrderDeliveryServices $services, $id)
{
$data = $this->request->postMore([
['type', 1],
['delivery_name', ''],//快递公司名称
['delivery_id', ''],//快递单号
['delivery_code', ''],//快递公司编码
['express_record_type', 2],//发货记录类型
['express_temp_id', ""],//电子面单模板
['to_name', ''],//寄件人姓名
['to_tel', ''],//寄件人电话
['to_addr', ''],//寄件人地址
['sh_delivery_name', ''],//送货人姓名
['sh_delivery_id', ''],//送货人电话
['sh_delivery_uid', ''],//送货人ID
['fictitious_content', '']//虚拟发货内容
]);
$services->delivery((int)$id, $data);
return $this->success('发货成功!');
}
/**
* 修改支付金额等
* @param $id
* @return mixed|Json|void
* @throws FormBuilderException
*/
public function edit($id)
{
if (!$id) {
return $this->fail('Data does not exist!');
}
return $this->success($this->services->updateForm($id));
}
/**
* 修改订单
* @param $id
* @return mixed
* @throws \Exception
*/
public function update($id)
{
if (!$id) {
return $this->fail('Missing order ID');
}
$data = $this->request->postMore([
['order_id', ''],
['total_price', 0],
['total_postage', 0],
['pay_price', 0],
['pay_postage', 0],
['gain_integral', 0],
]);
validate(StoreOrderValidate::class)->check($data);
if ($data['total_price'] < 0) {
return $this->fail('Please enter the total price');
}
if ($data['pay_price'] < 0) {
return $this->fail('Please enter the actual payment amount');
}
$this->services->updateOrder((int)$id, $data);
return $this->success('Modified success');
}
/**
* 订单备注
* @param Request $request
* @return mixed
*/
public function remark(Request $request)
{
[$order_id, $remark] = $request->postMore([
['order_id', ''],
['remark', '']
], true);
$order = $this->services->getOne(['order_id' => $order_id], 'id,remark');
/** @var StoreOrderRefundServices $refundServices */
$refundServices = app()->make(StoreOrderRefundServices::class);
$order = $order ?: $refundServices->get(['order_id' => $order_id]);
if (!$order) {
return $this->fail('订单不存在');
}
if (!strlen(trim($remark))) {
return $this->fail('请填写备注内容');
}
$order->remark = $remark;
if (!$order->save()) {
return $this->fail('备注失败');
}
return $this->success('备注成功');
}
/**
* 退款表单生成
* @param StoreOrderRefundServices $services
* @param $id 订单id
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function refundForm(StoreOrderRefundServices $services, $id)
{
if (!$id) {
return $this->fail('Data does not exist!');
}
return $this->success($services->refundOrderForm((int)$id));
}
/**
* 订单退款
* @param Request $request
* @param StoreOrderRefundServices $services
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function refundOld(Request $request, StoreOrderRefundServices $services)
{
[$orderId, $price, $type] = $request->postMore([
['order_id', ''],
['price', '0'],
['type', 1],
], true);
if (!strlen(trim($orderId))) return $this->fail('参数错误');
$orderRefund = $services->getOne(['order_id' => $orderId]);
if (!$orderRefund) {
return app('json')->fail('数据不存在!');
}
if ($orderRefund['is_cancel'] == 1) {
return app('json')->fail('用户已取消申请');
}
$orderInfo = $this->services->get((int)$orderRefund['store_order_id']);
if (!$orderInfo) {
return app('json')->fail('数据不存在');
}
if (!in_array($orderRefund['refund_type'], [0, 1, 2, 5]) && !($orderRefund['refund_type'] == 4 && $orderRefund['apply_type'] == 3)) {
return app('json')->fail('售后订单状态不支持该操作');
}
if ($type == 1) {
$data['refund_type'] = 6;
} else if ($type == 2) {
$data['refund_type'] = 3;
} else {
return app('json')->fail('退款修改状态错误');
}
$data['refunded_time'] = time();
//拒绝退款
if ($type == 2) {
$services->refuseRefund((int)$orderRefund['id'], $data, $orderRefund);
return $this->success('修改退款状态成功!');
} else {
if ($orderRefund['refund_price'] == $orderRefund['refunded_price']) return $this->fail('已退完支付金额!不能再退款了');
if (!$price) {
return $this->fail('请输入退款金额');
}
$data['refunded_price'] = bcadd($price, $orderRefund['refunded_price'], 2);
$bj = bccomp((float)$orderRefund['refund_price'], (float)$data['refunded_price'], 2);
if ($bj < 0) {
return $this->fail('退款金额大于支付金额,请修改退款金额');
}
$refundData['pay_price'] = $orderInfo['pay_price'];
$refundData['refund_price'] = $price;
//修改订单退款状态
if ($services->agreeRefund((int)$orderRefund['id'], $refundData)) {
$services->update((int)$orderRefund['id'], $data);
return $this->success('退款成功');
}
// else {
// $services->storeProductOrderRefundYFasle((int)$orderInfo['id'], $price);
// return $this->fail('退款失败');
// }
}
}
/**
* 订单详情
* @param StoreProductServices $productServices
* @param StoreOrderPromotionsServices $storeOrderPromotiosServices
* @param $id 订单id
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function orderInfo(StoreProductServices $productServices, StoreOrderPromotionsServices $storeOrderPromotiosServices, $id)
{
if (!$id || !($orderInfo = $this->services->get($id))) {
return $this->fail('订单不存在');
}
/** @var UserServices $services */
$services = app()->make(UserServices::class);
$userInfo = $services->get($orderInfo['uid']);
if (!$userInfo) {
return $this->fail('用户信息不存在');
}
$userInfo = $userInfo->hidden(['pwd', 'add_ip', 'last_ip', 'login_type']);
$userInfo['spread_name'] = '';
if ($userInfo['spread_uid'])
$userInfo['spread_name'] = $services->value(['uid' => $userInfo['spread_uid']], 'nickname');
$orderInfo = $this->services->tidyOrder($orderInfo->toArray(), true);
/** @var StorePinkServices $pinkService */
$pinkService = app()->make(StorePinkServices::class);
$orderInfo['pinkStatus'] = $pinkService->value(['order_id' => $orderInfo['order_id']], 'status');
$productId = array_column($orderInfo['cartInfo'], 'product_id');
$cateData = $productServices->productIdByProductCateName($productId);
foreach ($orderInfo['cartInfo'] as &$item) {
$item['class_name'] = $cateData[$item['product_id']] ?? '';
}
if ($orderInfo['store_id'] && $orderInfo['shipping_type'] == 2) {
/** @var $storeServices */
$storeServices = app()->make(SystemStoreServices::class);
$orderInfo['_store_name'] = $storeServices->value(['id' => $orderInfo['store_id']], 'name');
} else {
$orderInfo['_store_name'] = '';
}
//核算优惠金额
$vipTruePrice = 0;
foreach ($orderInfo['cartInfo'] ?? [] as $cart) {
$vipTruePrice = bcadd((string)$vipTruePrice, (string)$cart['vip_sum_truePrice'], 2);
}
$orderInfo['vip_true_price'] = $vipTruePrice;
$orderInfo['total_price'] = bcadd((string)$orderInfo['total_price'], (string)$orderInfo['vip_true_price'], 2);
//优惠活动优惠详情
$orderInfo['promotions_detail'] = $storeOrderPromotiosServices->getOrderPromotionsDetail((int)$orderInfo['id']);
if ($orderInfo['give_coupon']) {
$couponIds = is_string($orderInfo['give_coupon']) ? explode(',', $orderInfo['give_coupon']) : $orderInfo['give_coupon'];
/** @var StoreCouponIssueServices $couponIssueService */
$couponIssueService = app()->make(StoreCouponIssueServices::class);
$orderInfo['give_coupon'] = $couponIssueService->getColumn([['id', 'IN', $couponIds]], 'id,coupon_title');
}
$userInfo = $userInfo->toArray();
return $this->success(compact('orderInfo', 'userInfo'));
}
/**
* 获取物流
* @param ExpressServices $services
* @return mixed
*/
public function export(ExpressServices $services)
{
[$status] = $this->request->getMore([
['status', ''],
], true);
if ($status != '') $data['status'] = $status;
$data['is_show'] = 1;
return $this->success($services->express($data));
}
/**
*
* 获取面单信息
* @param ServeServices $services
* @return mixed
*/
public function getExportTemp(ServeServices $services)
{
[$com] = $this->request->getMore([
['com', ''],
], true);
return $this->success($services->express()->temp($com));
}
/**
* 获取所有配送员列表
* @param DeliveryServiceServices $services
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getDeliveryAll(DeliveryServiceServices $services)
{
$list = $services->getDeliveryList();
return $this->success($list['list']);
}
/**
* 获取配置信息
* @return mixed
*/
public function getDeliveryInfo()
{
return $this->success([
'express_temp_id' => sys_config('config_export_temp_id'),
'to_name' => sys_config('config_export_to_name'),
'id' => sys_config('config_export_id'),
'to_tel' => sys_config('config_export_to_tel'),
'to_add' => sys_config('config_export_to_address')
]);
}
/**
* 门店核销
* @param StoreOrderWriteOffServices $services
* @param $id
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function order_verific(StoreOrderWriteOffServices $services, $id)
{
$orderInfo = $this->services->get(['id' => $id], ['verify_code', 'uid']);
if (!$orderInfo) {
return $this->fail('核销订单未查到');
}
if (!$orderInfo->verify_code) {
return $this->fail('Lack of write-off code');
}
$services->writeOffOrder($orderInfo->verify_code, 1, $orderInfo->uid);
return $this->success('Write off successfully');
}
/**
* 退款订单详情
* @param StoreOrderRefundServices $services
* @param UserServices $userServices
* @param $id
* @return mixed
*/
public function refundDetail(StoreOrderRefundServices $services, UserServices $userServices, $id)
{
$order = $services->get(['id' => $id], ['id', 'order_id', 'uid']);
$uni = $order['order_id'];
$data['orderInfo'] = $services->refundDetail($uni);
$userInfo = $userServices->get((int)$order['uid']);
if (!$userInfo) return app('json')->fail('用户信息不存在');
$userInfo = $userInfo->hidden(['pwd', 'add_ip', 'last_ip', 'login_type']);
$data['userInfo'] = $userInfo;
return app('json')->success($data);
}
}

View File

@@ -0,0 +1,85 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\kefu;
use think\annotation\Inject;
use app\services\kefu\ProductServices;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* Class Product
* @package app\kefuapi\controller
*/
class Product extends AuthController
{
/**
* @var ProductServices
*/
#[Inject]
protected ProductServices $services;
/**
* 获取用户购买记录
* @param $uid
* @param string $store_name
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getCartProductList($uid, string $store_name = '')
{
return $this->success(get_thumb_water($this->services->getProductCartList((int)$uid, $store_name)));
}
/**
* 用户浏览记录
* @param $uid
* @param string $store_name
* @return mixed
*/
public function getVisitProductList($uid, string $store_name = '')
{
return $this->success(get_thumb_water($this->services->getVisitProductList((int)$uid, $store_name)));
}
/**
* 获取用户购买的热销商品
* @param $uid
* @param string $store_name
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getProductHotSale($uid, string $store_name = '')
{
return $this->success(get_thumb_water($this->services->getProductHotSale((int)$uid, $store_name)));
}
/**
* 商品详情
* @param $id
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getProductInfo($id)
{
return $this->success($this->services->getProductInfo((int)$id));
}
}

View File

@@ -0,0 +1,176 @@
<?php
namespace app\controller\kefu;
use app\Request;
use app\services\order\StoreOrderRefundServices;
use app\services\order\StoreOrderServices;
use think\annotation\Inject;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
class RefundOrder extends AuthController
{
/**
* @var StoreOrderRefundServices
*/
#[Inject]
protected StoreOrderRefundServices $services;
/**
* 退款订单列表
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getRefundList()
{
$where = $this->request->getMore([
['order_id', ''],
['time', ''],
['refund_type', '']
]);
return $this->success($this->services->refundList($where));
}
/**
* 退款表单生成
* @param $id
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function refund($id)
{
if (!$id) {
return app('json')->fail('Data does not exist!');
}
return app('json')->success($this->services->refundOrderForm((int)$id));
}
/**
* 订单退款
* @param Request $request
* @param StoreOrderServices $services
* @param $id
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function update_refund(Request $request, StoreOrderServices $services, $id)
{
$data = $request->postMore([
['refund_price', 0],
['type', 1]
]);
if (!$id) {
return app('json')->fail('Data does not exist!');
}
$data['refund_price'] = sprintf("%.2f", $data['refund_price']);
$orderRefund = $this->services->get($id);
if (!$orderRefund) {
return app('json')->fail('Data does not exist!');
}
if ($orderRefund['is_cancel'] == 1) {
return app('json')->fail('用户已取消申请');
}
$order = $services->get((int)$orderRefund['store_order_id']);
if (!$order) {
return app('json')->fail('Data does not exist!');
}
if (!in_array($orderRefund['refund_type'], [0, 1, 2, 5]) && !($orderRefund['refund_type'] == 4 && $orderRefund['apply_type'] == 3)) {
return app('json')->fail('售后订单状态不支持该操作');
}
if ($data['type'] == 1) {
$data['refund_type'] = 6;
} else if ($data['type'] == 2) {
$data['refund_type'] = 3;
}
$data['refunded_time'] = time();
$type = $data['type'];
//拒绝退款
if ($type == 2) {
$this->services->refuseRefund((int)$id, $data, $orderRefund);
return app('json')->successful('修改退款状态成功!');
} else {
//0元退款
if ($orderRefund['refund_price'] == 0) {
$refund_price = 0;
} else {
if (!$data['refund_price']) {
return app('json')->fail('请输入退款金额');
}
if ($orderRefund['refund_price'] == $orderRefund['refunded_price']) {
return app('json')->fail('已退完支付金额!不能再退款了');
}
$refund_price = $data['refund_price'];
$data['refunded_price'] = bcadd($data['refund_price'], $orderRefund['refunded_price'], 2);
$bj = bccomp((string)$orderRefund['refund_price'], (string)$data['refunded_price'], 2);
if ($bj < 0) {
return app('json')->fail('退款金额大于支付金额,请修改退款金额');
}
}
unset($data['type']);
$refund_data['pay_price'] = $order['pay_price'];
$refund_data['refund_price'] = $refund_price;
//修改订单退款状态
unset($data['refund_price']);
if ($this->services->agreeRefund($id, $refund_data)) {
$this->services->update($id, $data);
return app('json')->success('退款成功');
}
// else {
// $this->services->storeProductOrderRefundYFasle((int)$id, $refund_price);
// return app('json')->fail('退款失败');
// }
}
}
/**
* 商家同意退货退款
* @return mixed
*/
public function agreeRefund()
{
[$order_id] = $this->request->getMore([
['order_id', '']
], true);
$this->services->agreeRefundProdcut((int)$order_id);
return app('json')->success('操作成功');
}
/**
* 修改备注
* @param $id
* @return mixed
*/
public function remark($id)
{
$data = $this->request->postMore([['remark', '']]);
if (!$data['remark'])
return app('json')->fail('请输入要备注的内容');
if (!$id)
return app('json')->fail('缺少参数');
if (!$order = $this->services->get($id)) {
return app('json')->fail('修改的订单不存在!');
}
$order->remark = $data['remark'];
if ($order->save()) {
return app('json')->success('备注成功');
} else
return app('json')->fail('备注失败');
}
}

View File

@@ -0,0 +1,314 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\kefu;
use app\Request;
use think\annotation\Inject;
use app\services\kefu\KefuServices;
use app\services\other\CategoryServices;
use app\validate\kefu\SpeechcraftValidate;
use app\services\message\service\StoreServiceSpeechcraftServices;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* Class Service
* @package app\kefuapi\controller
*/
class Service extends AuthController
{
/**
* @var KefuServices
*/
#[Inject]
protected KefuServices $services;
/**
* 转接客服列表
* @param Request $request
* @param int $uid
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getServiceList(Request $request, $uid = 0)
{
$where = $request->getMore([
['nickname', ''],
]);
return $this->success($this->services->getServiceList($where, [$this->kefuInfo['uid'], $uid]));
}
/**
* 话术列表
* @param Request $request
* @param StoreServiceSpeechcraftServices $services
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getSpeechcraftList(Request $request, StoreServiceSpeechcraftServices $services)
{
$where = $request->getMore([
['title', ''],
['cate_id', ''],
['type', 0]
]);
if ($where['type']) {
$where['kefu_id'] = $this->kefuId;
} else {
$where['kefu_id'] = 0;
}
$data = $services->getSpeechcraftList($where);
return $this->success($data['list']);
}
/**
* 添加分类
* @param Request $request
* @param CategoryServices $services
* @return mixed
*/
public function saveCate(Request $request, CategoryServices $services)
{
$data = $request->postMore([
['name', ''],
[['sort', 'd'], 0],
]);
if (!$data['name']) {
return $this->fail('分类名称不能为空');
}
$data['add_time'] = time();
$data['owner_id'] = $this->kefuId;
$data['type'] = 0;
$data['group'] = 1;
$services->save($data);
return $this->success('添加成功');
}
/**
* 修改分类
* @param Request $request
* @param CategoryServices $services
* @param $id
* @return mixed
*/
public function editCate(Request $request, CategoryServices $services, $id)
{
$data = $request->postMore([
['name', ''],
[['sort', 'd'], 0],
]);
if (!$data['name']) {
return $this->fail('分类不能为空');
}
$cateInfo = $services->get($id);
if (!$cateInfo) {
return $this->fail('分类没有查到无法删除');
}
$cateInfo->name = $data['name'];
$cateInfo->sort = $data['sort'];
if ($cateInfo->save()) {
return $this->success('分类修改成功');
} else {
return $this->fail('分类没有查到无法删除');
}
}
/**
* 删除分类
* @param CategoryServices $services
* @param $id
* @return mixed
*/
public function deleteCate(CategoryServices $services, $id)
{
$cateInfo = $services->get($id);
if (!$cateInfo) {
return $this->fail('分类不存在');
}
if ($cateInfo->delete()) {
return $this->success('删除成功');
} else {
return $this->fail('删除失败');
}
}
/**
* 获取当前客服分类
* @param CategoryServices $services
* @param $type
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getCateList(CategoryServices $services, $type)
{
return $this->success($services->getCateList(['owner_id' => $type ? $this->kefuId : 0, 'type' => 0, 'group' => 1], ['id', 'name', 'sort']));
}
/**
* 添加话术
* @param Request $request
* @param StoreServiceSpeechcraftServices $services
* @param CategoryServices $categoryServices
* @return mixed
*/
public function saveSpeechcraft(Request $request, StoreServiceSpeechcraftServices $services, CategoryServices $categoryServices)
{
$data = $request->postMore([
['title', ''],
['cate_id', 0],
['message', ''],
['sort', 0]
]);
validate(SpeechcraftValidate::class)->check($data);
if (!$categoryServices->count(['owner_id' => $this->kefuId, 'type' => 0, 'id' => $data['cate_id']])) {
return $this->fail('您选择的分类不存在');
}
if ($services->count(['message' => $data['message']])) {
return $this->fail('添加的内容重复');
}
$data['add_time'] = time();
$data['kefu_id'] = $this->kefuId;
$res = $services->save($data);
if ($res) {
return $this->success('添加话术成功', $res->toArray());
} else {
return $this->fail('添加话术失败');
}
}
/**
* 修改话术
* @param Request $request
* @param StoreServiceSpeechcraftServices $services
* @param CategoryServices $categoryServices
* @param $id
* @return mixed
*/
public function editSpeechcraft(Request $request, StoreServiceSpeechcraftServices $services, CategoryServices $categoryServices, $id)
{
$data = $request->postMore([
['title', ''],
['cate_id', 0],
['message', ''],
]);
if (!$data['message']) {
return $this->fail('话术标题内容不能为空');
}
if (!$categoryServices->count(['owner_id' => $this->kefuId, 'type' => 0, 'id' => $data['cate_id']])) {
return $this->fail('您选择的分类不存在');
}
$speechcraft = $services->get($id);
if (!$speechcraft) {
return $this->fail('话术没有被查到');
}
if (!$speechcraft->kefu_id) {
return $this->fail('公共话术不能修改');
}
$speechcraft->title = $data['title'];
if ($data['cate_id']) {
$speechcraft->cate_id = $data['cate_id'];
}
$speechcraft->message = $data['message'];
if ($speechcraft->save()) {
return $this->success('修改成功');
} else {
return $this->fail('修改失败');
}
}
/**
* 删除话术
* @param StoreServiceSpeechcraftServices $services
* @param $id
* @return mixed
*/
public function deleteSpeechcraft(StoreServiceSpeechcraftServices $services, $id)
{
$speechcraft = $services->get($id);
if (!$speechcraft) {
return $this->fail('话术没有被查到');
}
if ($speechcraft->delete()) {
return $this->success('删除成功');
} else {
return $this->fail('删除失败');
}
}
/**
* 聊天记录
* @param Request $request
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getChatList(Request $request)
{
[$uid, $upperId, $is_tourist] = $request->postMore([
['uid', 0],
['upperId', 0],
['is_tourist', 0],
], true);
if (!$uid) {
return $this->fail('缺少参数');
}
return $this->success($this->services->getChatList($this->kefuInfo['uid'], $uid, (int)$upperId, $is_tourist));
}
/**
* 当前客服详细信息
* @return mixed
*/
public function getServiceInfo()
{
$this->kefuInfo['site_name'] = sys_config('site_name');
$this->kefuInfo['config_export_open'] = sys_config('config_export_open');
return $this->success($this->kefuInfo->toArray());
}
/**
* 客服转接
* @return mixed
*/
public function transfer()
{
[$kefuToUid, $uid] = $this->request->postMore([
['kefuToUid', 0],
['uid', 0]
], true);
if (!$kefuToUid || !$uid) {
return $this->fail('缺少转接人id');
}
$this->services->setTransfer($this->kefuInfo['uid'], (int)$uid, (int)$kefuToUid);
return $this->success('转接成功');
}
}

View File

@@ -0,0 +1,190 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\kefu;
use app\Request;
use app\services\system\attachment\SystemAttachmentServices;
use app\services\user\group\UserGroupServices;
use crmeb\services\CacheService;
use crmeb\services\UploadService;
use Psr\SimpleCache\InvalidArgumentException;
use think\annotation\Inject;
use app\services\kefu\UserServices;
use app\services\user\label\UserLabelCateServices;
use app\services\user\label\UserLabelRelationServices;
use app\services\message\service\StoreServiceRecordServices;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Config;
/**
* Class User
* @package app\kefuapi\controller
*/
class User extends AuthController
{
/**
* @var StoreServiceRecordServices
*/
#[Inject]
protected StoreServiceRecordServices $services;
/**
* 获取当前客服和用户的聊天记录
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function recordList(string $nickname = '', $is_tourist = 0)
{
return $this->success($this->services->getServiceList($this->kefuInfo['uid'], $nickname, (int)$is_tourist));
}
/**
* 获取用户信息
* @param UserServices $services
* @param $uid
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function userInfo(UserServices $services, $uid)
{
return $this->success($services->getUserInfo((int)$uid));
}
/**
* 标签分类
* @param UserLabelCateServices $services
* @param $uid
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getUserLabel(UserLabelCateServices $services, $uid)
{
return $this->success($services->getUserLabel((int)$uid));
}
/**
* 获取用户分组
* @param UserGroupServices $services
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getUserGroup(UserGroupServices $services)
{
return $this->success($services->getGroupList());
}
/**
* 设置分组
* @param UserGroupServices $services
* @param UserServices $userServices
* @param $uid
* @param $id
* @return mixed
*/
public function setUserGroup(UserGroupServices $services, UserServices $userServices, $uid, $id)
{
if (!$services->count(['id' => $id])) {
return $this->fail('添加的会员标签不存在');
}
if (!($userInfo = $userServices->get($uid))) {
return $this->fail('用户不存在');
}
if ($userInfo->group_id == $id) {
return $this->fail('已拥有此分组');
}
$userInfo->group_id = $id;
if ($userInfo->save()) {
return $this->success('设置成功');
} else {
return $this->fail('设置失败');
}
}
/**
* 设置用户标签
* @param UserLabelRelationServices $services
* @param $uid
* @return mixed
*/
public function setUserLabel(UserLabelRelationServices $services, $uid)
{
[$labels, $unLabelIds] = $this->request->postMore([
['label_ids', []],
['un_label_ids', []]
], true);
if (!count($labels) && !count($unLabelIds)) {
return $this->fail('请选择标签');
}
if ($services->setUserLable($uid, $labels) && $services->unUserLabel($uid, $unLabelIds)) {
return $this->success('设置成功');
} else {
return $this->fail('设置失败');
}
}
/**
* 退出登陆
* @return mixed
*/
public function logout()
{
$key = trim(ltrim($this->request->header(Config::get('cookie.token_name')), 'Bearer'));
CacheService::redisHandler()->delete(md5($key));
return $this->success();
}
/**
* 图片上传
* @param Request $request
* @param SystemAttachmentServices $services
* @return mixed
* @throws InvalidArgumentException
*/
public function upload(Request $request, SystemAttachmentServices $services)
{
$data = $request->postMore([
['filename', 'file'],
]);
if (!$data['filename']) return $this->fail('参数有误');
if (CacheService::has('start_uploads_' . $request->kefuId()) && CacheService::get('start_uploads_' . $request->kefuId()) >= 100) return $this->fail('非法操作');
$upload = UploadService::init();
$info = $upload->to('store/comment')->validate()->move($data['filename']);
if ($info === false) {
return $this->fail($upload->getError());
}
$res = $upload->getUploadInfo();
$services->attachmentAdd($res['name'], $res['size'], $res['type'], $res['dir'], $res['thumb_path'], 1, (int)sys_config('upload_type', 1), $res['time'], 2);
if (CacheService::has('start_uploads_' . $request->kefuId()))
$start_uploads = (int)CacheService::get('start_uploads_' . $request->kefuId());
else
$start_uploads = 0;
$start_uploads++;
CacheService::set('start_uploads_' . $request->kefuId(), $start_uploads, 86400);
$res['dir'] = path_to_url($res['dir']);
if (strpos($res['dir'], 'http') === false) $res['dir'] = $request->domain() . $res['dir'];
return $this->success('图片上传成功!', ['name' => $res['name'], 'url' => $res['dir']]);
}
}