Commit db954948 authored by CHINAMI-OOGFOG1\Administrator's avatar CHINAMI-OOGFOG1\Administrator

Merge branch 'dev' of http://rungit.jxdsy.cn:10000/sugar/jwhx into dev

# Conflicts:
#	modules/Order/app/Services/RefundService.php
#	modules/Wechat/app/Services/PayService.php
#	resources/admin/src/config/index.js
#	resources/admin/src/pages/order/exchange/index.vue
parents 5f30bc68 e1caa842
...@@ -33,3 +33,29 @@ SentOS管理系统是一个基于Laravel + Vue 开发的后台管理系统,主 ...@@ -33,3 +33,29 @@ SentOS管理系统是一个基于Laravel + Vue 开发的后台管理系统,主
- [x] 配置管理 参数的管理 - [x] 配置管理 参数的管理
- [x] 字典管理 字典数据管理 - [x] 字典管理 字典数据管理
- [x] 操作日志 后台用户操作记录 - [x] 操作日志 后台用户操作记录
注意:
unlink public/storage 删除现有的链接
php artisan storage:link 重新创建软链接访问图片
ln -s /www/wwwroot/jwhx.xicheda.cn/resources/attachs public/attachs 创建一个新的链接指向不同的目录
ls -l public/storage 检查是否存在链接
php artisan queue:work 命令启动一个队列工作进程(用于事件监听)
php artisan queue:work --daemon
清理和优化配置缓存
php artisan config:cache
清理和优化路由缓存
php artisan route:cache
清理和优化视图缓存
php artisan view:cache
清理日志文件
php artisan log:clear
注意:修改生成缓存文件权限
-----BEGIN CERTIFICATE-----
MIIEFDCCAvygAwIBAgIUQg/xTpir1cQyxxIQAZpCI1xWFsYwDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
Q0EwHhcNMjQwODA2MDkxMTU5WhcNMjkwODA1MDkxMTU5WjBuMRgwFgYDVQQDDA9U
ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl
bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGEwJDTjERMA8GA1UEBwwIU2hlblpo
ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPdcXZvCKERRiBqSic
HyCgj7h6/vJ/ofmPHOsNrxpEcJSKgQH/LkFdb6Ze5I4VwM75Hvg1+GJEECpkFV9r
y8b0NADroG6uBprJZ1FQN/lohYglXeGM60G2deEvw6iXUoebg5ZRm5ISiY+U+A0I
aqF4QvBU9EZBbMQVagMkqbPfEboOn9vZvFoRrCFCqIQScUmE8MsXCPvvmYZm8u9q
vAl5/UXD/HZMTnybUsrQQvxoKyZDJQQgOQPv05zhRoA1vCwidfuZcUD48pSj3IUu
oU34lz8HBKDMDrt0mMTeAoKGW5/jMFkcVDI5v8BKUstnPA44Bv5+3W09zjegmARx
sPNTAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB
kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv
aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4
RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0
MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAVaZ+7FM6uSZoyumTYZ5WyWsvDYAcNQl/
oMaq8vRa7MDDi2pWiZGg0g0100vXj+JEwFBGNRck4PQM+iO4BLVPwjHE7d39QI7Z
VtzC3+z4jNEXjJ0hhH/N4PJqkM3k/+DO7UgUMCrwRFZfCBNMqt3MYSbmdAYbPXf7
axfr+vUB9tzyVjZ5LshVSmzN/H1bdvREeg40dPJHftSwGAH2WKwQCODLZQ9uIEFP
zygbj/Tupn+XHptRcpPFmhhOqlQCfMrl85qSsKuDFHaJJuQypLr3p5rN3wdLw4mZ
jjWmd4NAYqW+fm4pW96RMQOAVjba/+xDGNCDleIdJ+5hRxumDL7hcg==
-----END CERTIFICATE-----
\ No newline at end of file
...@@ -25,6 +25,7 @@ return [ ...@@ -25,6 +25,7 @@ return [
// 商户证书 // 商户证书
'private_key' => __DIR__ . '/certs/apiclient_key.pem', 'private_key' => __DIR__ . '/certs/apiclient_key.pem',
'certificate' => __DIR__ . '/certs/apiclient_cert.pem', 'certificate' => __DIR__ . '/certs/apiclient_cert.pem',
'public_key' => __DIR__ . '/certs/public_cert_key.pem',
// v3 API 秘钥 // v3 API 秘钥
'secret_key' => '60ed9440d9077499f0507471c933e563', 'secret_key' => '60ed9440d9077499f0507471c933e563',
......
...@@ -38,7 +38,7 @@ class GoodsBlance implements ShouldQueue{ ...@@ -38,7 +38,7 @@ class GoodsBlance implements ShouldQueue{
} }
// 积分商品 // 积分商品
if ($goods->goods_type == 0){ if ($goods->goods_type == 0){
app(ScoreService::class)->createScore(order_id: $item->id, member_id: $member->uid, amount: $goods->score, type: 'income', remark: '积分商品购买积分'); app(ScoreService::class)->createScore(store_id: $item->store_id, order_id: $item->id, member_id: $member->uid, amount: $goods->score, type: 'income', account_type: 'order', remark: '积分商品购买积分');
// 更新会员等级 // 更新会员等级
if ($member->level_id < $goods->level_id){ if ($member->level_id < $goods->level_id){
......
...@@ -19,7 +19,7 @@ class Goods extends BaseModel { ...@@ -19,7 +19,7 @@ class Goods extends BaseModel {
protected $table = 'goods'; protected $table = 'goods';
protected $fillable = [ protected $fillable = [
'title', 'user_id', 'brand_id', 'description', 'tags', 'goods_type','cover', 'images', 'price', 'original_price', 'title', 'user_id', 'brand_id', 'description', 'tags', 'goods_type','cover', 'images', 'price', 'original_price',
'service_amount', 'master_amount', 'partner_amount', 'is_partner', 'operate', 'content', 'status' 'service_amount', 'master_amount', 'partner_amount', 'is_partner', 'operate', 'content', 'status','goods_sn'
]; ];
// protected $hidden = ['deleted_at']; // protected $hidden = ['deleted_at'];
......
...@@ -13,7 +13,7 @@ use App\Models\BaseModel; ...@@ -13,7 +13,7 @@ use App\Models\BaseModel;
class GoodsSku extends BaseModel { class GoodsSku extends BaseModel {
protected $table = 'goods_sku'; protected $table = 'goods_sku';
protected $fillable = ['goods_id', 'sku_value', 'sku', 'price', 'integral', 'stock', 'sales', 'cover', 'created_at', 'updated_at']; protected $fillable = ['goods_id', 'sku_value', 'sku', 'price', 'integral', 'stock', 'sales', 'cover', 'created_at', 'updated_at','goods_sn'];
// protected $hidden = ['deleted_at']; // protected $hidden = ['deleted_at'];
protected function casts(): array { protected function casts(): array {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
namespace Modules\Goods\Services; namespace Modules\Goods\Services;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Modules\Goods\Models\Goods; use Modules\Goods\Models\Goods;
use App\Support\Tree; use App\Support\Tree;
...@@ -118,6 +119,7 @@ class GoodsService { ...@@ -118,6 +119,7 @@ class GoodsService {
foreach ($goods->setFilterFields($request->all()) as $key => $value) { foreach ($goods->setFilterFields($request->all()) as $key => $value) {
$goods->$key = $value; $goods->$key = $value;
} }
$goods->goods_sn = empty($request->input('goods_sn'))?"G".date('YmdHis'): $request->input('goods_sn');
$goods->save(); $goods->save();
//更新栏目 //更新栏目
...@@ -129,6 +131,7 @@ class GoodsService { ...@@ -129,6 +131,7 @@ class GoodsService {
foreach ($sku as $key => $value) { foreach ($sku as $key => $value) {
$sku[$key]['sku_value'] = isset($value['sku_value']) ? $value['sku_value'] : Arr::except($value, ['price', 'stock', 'cover', 'original_price', 'sales']); $sku[$key]['sku_value'] = isset($value['sku_value']) ? $value['sku_value'] : Arr::except($value, ['price', 'stock', 'cover', 'original_price', 'sales']);
$sku[$key]['sku'] = implode(';', $value['sku_value']); $sku[$key]['sku'] = implode(';', $value['sku_value']);
$sku[$key]['goods_sn'] =empty($value['goods_sn'])?"S".date('YmdHi').rand(1000,9999): $value['goods_sn'];
} }
$goods->sku()->createMany($sku); $goods->sku()->createMany($sku);
} }
...@@ -162,6 +165,8 @@ class GoodsService { ...@@ -162,6 +165,8 @@ class GoodsService {
$goods->$key = $value; $goods->$key = $value;
} }
$goods->goods_sn = empty($request->input('goods_sn'))?"G".date('YmdHis'):$request->input('goods_sn');
$goods->save(); $goods->save();
//更新栏目 //更新栏目
$goods->category()->sync($request->input('category_id')); $goods->category()->sync($request->input('category_id'));
...@@ -174,6 +179,7 @@ class GoodsService { ...@@ -174,6 +179,7 @@ class GoodsService {
foreach ($sku as $key => $value) { foreach ($sku as $key => $value) {
$value['sku_value'] = isset($value['sku_value']) ? $value['sku_value'] : Arr::except($value, ['price', 'stock', 'cover', 'original_price', 'sales']); $value['sku_value'] = isset($value['sku_value']) ? $value['sku_value'] : Arr::except($value, ['price', 'stock', 'cover', 'original_price', 'sales']);
$value['sku'] = implode(';', $value['sku_value']); $value['sku'] = implode(';', $value['sku_value']);
$value['goods_sn'] = empty($value['goods_sn'])?"S".date('YmdHi').rand(1000,9999):$value['goods_sn'];
$goods->sku()->updateOrCreate(['id' => $value['id'] ?? 0], $value); $goods->sku()->updateOrCreate(['id' => $value['id'] ?? 0], $value);
} }
}else{ }else{
......
...@@ -46,6 +46,7 @@ return new class extends Migration ...@@ -46,6 +46,7 @@ return new class extends Migration
$table->tinyInteger('status')->default(1)->comment('状态 1上架 0下架'); $table->tinyInteger('status')->default(1)->comment('状态 1上架 0下架');
$table->timestamp('created_at')->nullable()->comment('创建时间'); $table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间'); $table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->string('goods_sn')->nullable()->comment('商品编号');
$table->engine = 'InnoDB'; $table->engine = 'InnoDB';
$table->charset = 'utf8mb4'; $table->charset = 'utf8mb4';
......
...@@ -85,4 +85,21 @@ class Account extends BaseController{ ...@@ -85,4 +85,21 @@ class Account extends BaseController{
return response()->json($this->data); return response()->json($this->data);
} }
/**
* @title 通过提现
*
* @param AccountService $service
* @return void
*/
public function withdraw(Request $request, AccountService $service){
try {
$this->data['data'] = $service->withdraw($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
} }
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Member\Services\PolymerService;
class Polymer extends BaseController{
/**
* @title 聚物通列表
*
* @param Request $request
* @param PolymerService $service
* @return void
*/
public function index(Request $request, PolymerService $service){
try {
$this->data['data'] = $service->getDataList($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 添加聚物通
*
* @param Request $request
* @param PolymerService $service
* @return void
*/
public function add(Request $request, PolymerService $service){
try {
$this->data['data'] = $service->createPolymer(store_id: 0, order_id: 0, member_id: $request->input('member_id'), amount: $request->input('amount'), type: $request->input('type'), account_type: 'system', remark: $request->input('remark'));
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 修改聚物通
*
* @param Request $request
* @param PolymerService $service
* @return void
*/
public function edit(Request $request, PolymerService $service){
try {
$this->data['data'] = $service->update($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 删除聚物通
*
* @param Request $request
* @param PolymerService $service
* @return void
*/
public function delete(Request $request, PolymerService $service){
try {
$this->data['data'] = $service->delete($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
}
\ No newline at end of file
...@@ -41,7 +41,7 @@ class Score extends BaseController{ ...@@ -41,7 +41,7 @@ class Score extends BaseController{
*/ */
public function add(Request $request, ScoreService $service){ public function add(Request $request, ScoreService $service){
try { try {
$this->data['data'] = $service->createScore(order_id: 0, member_id: $request->input('member_id'), amount: $request->input('amount'), type: $request->input('type'), remark: $request->input('remark')); $this->data['data'] = $service->createScore(store_id: 0, order_id: 0, member_id: $request->input('member_id'), amount: $request->input('amount'), type: $request->input('type'), account_type: 'system', remark: $request->input('remark'));
} catch (\Exception $e) { } catch (\Exception $e) {
$this->data['code'] = 0; $this->data['code'] = 0;
$this->data['message'] = $e->getMessage(); $this->data['message'] = $e->getMessage();
......
<?php
namespace Modules\Member\Controllers\Admin;
use App\Http\Controllers\BaseController;
use Illuminate\Http\Request;
use Modules\Member\Services\SignService;
class Sign extends BaseController
{
/*
* 签到记录
*/
public function index(Request $request,SignService $service){
try {
$this->data['data'] = $service->getDataList($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
}
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Member\Services\PolymerService;
class Polymer extends BaseController {
/**
* @title 聚物通列表
*
* @param PolymerService $service
* @return void
*/
public function index(Request $request, PolymerService $service){
try {
$request->mergeIfMissing([
'is_user' => 1
]);
$this->data['data'] = $service->getDataList($request);
} catch (\think\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return $this->data;
}
}
<?php
namespace Modules\Member\Controllers\Api;
use App\Http\Controllers\BaseController;
use Illuminate\Http\Request;
use Modules\Member\Services\SignService;
class Sign extends BaseController
{
/*
* 签到记录
*/
public function index(Request $request,SignService $service){
try {
$this->data['data'] = $service->getDataList($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
/**签到
* @param Request $request
* @param SignService $service
* @return array
*/
public function add(Request $request,SignService $service){
try {
$this->data['data'] = $service->create($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return $this->data;
}
}
\ No newline at end of file
...@@ -21,6 +21,6 @@ class OrderRefundListener implements ShouldQueue{ ...@@ -21,6 +21,6 @@ class OrderRefundListener implements ShouldQueue{
$detail = $event->detail; $detail = $event->detail;
// 积分退还 // 积分退还
app(ScoreService::class)->createScore(order_id: $detail->id, member_id: $detail->member_id, amount: $detail->total_integral, type: 'income', remark: '商品退货退款'); app(ScoreService::class)->createScore(store_id: $refund->store_id, order_id: $detail->id, member_id: $detail->member_id, amount: $detail->total_integral, type: 'income', type: 'refund', remark: '商品退货退款');
} }
} }
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class MemberPolymer extends BaseModel {
protected $table = 'member_polymer';
protected $fillable = ['store_id', 'order_id', 'member_id', 'type','account_type', 'amount', 'bf_amount', 'af_amount', 'status', 'remark'];
// protected $hidden = ['deleted_at'];
public function member() {
return $this->belongsTo(Member::class, 'member_id', 'uid');
}
public function admin(){
return $this->belongsTo(\Modules\Auth\Models\Admin::class, 'member_id', 'uid');
}
public function order(){
return $this->belongsTo(\Modules\Order\Models\OrderItem::class, 'order_id', 'id');
}
}
...@@ -13,7 +13,7 @@ use App\Models\BaseModel; ...@@ -13,7 +13,7 @@ use App\Models\BaseModel;
class MemberScore extends BaseModel { class MemberScore extends BaseModel {
protected $table = 'member_score'; protected $table = 'member_score';
protected $fillable = ['store_id', 'order_id', 'member_id', 'type', 'amount', 'bf_amount', 'af_amount', 'status', 'remark']; protected $fillable = ['store_id', 'order_id', 'member_id', 'type', 'amount','account_type', 'bf_amount', 'af_amount', 'status', 'remark'];
// protected $hidden = ['deleted_at']; // protected $hidden = ['deleted_at'];
public function member() { public function member() {
......
<?php
namespace Modules\Member\Models;
use App\Models\BaseModel;
class SignRecord extends BaseModel
{
protected $table = 'sign_record';
protected $fillable = ['member_id','score','day','month'];
}
\ No newline at end of file
...@@ -10,10 +10,12 @@ namespace Modules\Member\Services; ...@@ -10,10 +10,12 @@ namespace Modules\Member\Services;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use App\Support\Time; use App\Support\Time;
use Modules\Member\Models\MemberAccount; use Modules\Member\Models\MemberAccount;
use Modules\Member\Models\Member; use Modules\Member\Models\Member;
use Modules\Wechat\Services\TransferService;
class AccountService { class AccountService {
...@@ -117,7 +119,7 @@ class AccountService { ...@@ -117,7 +119,7 @@ class AccountService {
*/ */
public function createAccount($store_id, $order_id, $member_id, $type, $account_type = 'order', $amount = 0, $remark = ''){ public function createAccount($store_id, $order_id, $member_id, $type, $account_type = 'order', $amount = 0, $remark = ''){
if ($order_id > 0) { if ($order_id > 0) {
$account = MemberAccount::where('order_id', '=', $order_id)->where('member_id', '=', $member_id)->where('type', '=', $type)->first(); $account = MemberAccount::where('order_id', '=', $order_id)->where('member_id', '=', $member_id)->where('type', '=', $type)->where('account_type', '=', $account_type)->first();
if($account){ if($account){
return $account; return $account;
} }
...@@ -134,6 +136,7 @@ class AccountService { ...@@ -134,6 +136,7 @@ class AccountService {
'order_id' => $order_id, 'order_id' => $order_id,
'member_id' => $member_id, 'member_id' => $member_id,
'type' => $type, 'type' => $type,
'account_type' => $account_type,
'amount' => $amount, 'amount' => $amount,
'bf_amount' => $bf_amount, 'bf_amount' => $bf_amount,
'af_amount' => $af_amount, 'af_amount' => $af_amount,
...@@ -240,15 +243,17 @@ class AccountService { ...@@ -240,15 +243,17 @@ class AccountService {
'order_id' => 0, 'order_id' => 0,
'store_id' => 0, 'store_id' => 0,
'member_id' => $member['uid'], 'member_id' => $member['uid'],
'type' => 1,
'amount' => $request->input('amount'), 'amount' => $request->input('amount'),
'type' => 'withdraw', 'type' => 'withdraw',
'account_type' => 'withdraw', 'account_type' => 'withdraw',
'af_amount' => $member['money'],
'bf_amount' => bcsub($member['money'], $request->input('amount'), 2),
'fee_rate' => $config['withdraw_fee_rate'], 'fee_rate' => $config['withdraw_fee_rate'],
'actual_amount' => bcsub($request->input('amount'), bcmul($request->input('amount'), bcdiv($config['withdraw_fee_rate'], 100, 2), 2), 2), 'actual_amount' => bcsub($request->input('amount'), bcmul($request->input('amount'), bcdiv($config['withdraw_fee_rate'], 100, 2), 2), 2),
'pay_type' => $request->input('pay_type'), 'pay_type' => $request->input('pay_type'),
'bank_id' => $request->input('bank_id', 0), 'bank_id' => $request->input('bank_id', 0),
'status' => 0, 'status' => 0,
'request_no' => str_replace('-', '', Str::orderedUuid()),
'remark' => $request->input('remark', '用户提现'), 'remark' => $request->input('remark', '用户提现'),
]; ];
...@@ -259,6 +264,12 @@ class AccountService { ...@@ -259,6 +264,12 @@ class AccountService {
} }
$account->save(); $account->save();
//扣除余额
$user = Member::find($member['uid']);
$user->money = bcsub($user->money, $request->input('amount'), 2);
$user->save();
return $account; return $account;
} }
...@@ -271,17 +282,19 @@ class AccountService { ...@@ -271,17 +282,19 @@ class AccountService {
throw new \Exception("提现记录已处理!", 0); throw new \Exception("提现记录已处理!", 0);
} }
if($request->filled('status')){ $member = Member::where('uid', $account->member_id)->first();
$account->status = $request->input('status');
if($request->input('status') == 1){ if($account->pay_type=="wechat"){//
$member = Member::find($account->member_id); $result = TransferService::transfer($account->bank_realname,$account->request_no,$account->actual_amount,$member['username']);
$member->money = bcsub($member->money, $account->amount, 2); if(isset($result['code'])){
$member->save(); throw new \Exception('异常:'.$result['code'].' '.$result['message'], 0);
} }
MemberAccount::where(['id'=>$account->id])->update(['status'=>1,'out_batch_no'=>$result]);
}else if($account->pay_type=="bank"){
throw new \Exception("银行卡在开发中!", 0);
}else {
throw new \Exception("该提现方式不存在!", 0);
} }
$account->save();
return $account; return $account;
} }
......
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Services;
use Modules\Member\Models\Member;
use Modules\Member\Models\MemberPolymer;
class PolymerService {
/**
* @title 获取会员列表
*
* @param [type] $request
* @return void
*/
public function getDataList($request){
$map = [];
$query = MemberPolymer::query();
if ($request->filled('store_id')) {
$map[] = ['store_id', '=', $request->input('store_id')];
}
if ($request->filled('member_id')) {
$map[] = ['member_id', '=', $request->input('member_id')];
}
if ($request->filled('is_user')) {
$map[] = ['member_id', '=', auth('api')->user()['uid']];
$query->whereIn('type', ['income', 'withdraw', 'pay']);
}
$query->where($map)->orderBy('id', 'desc');
if ($request->filled('username')) {
$query->whereHas('member', function($query) use ($request){
$query->where('username', 'like', '%' . $request->input('username') . '%');
});
}
if ($request->filled('mobile')) {
$query->whereHas('member', function($query) use ($request){
$query->where('mobile', 'like', '%' . $request->input('mobile') . '%');
});
}
if ($request->filled('store_title')) {
$query->whereHas('store', function($query) use ($request){
$query->where('title', 'like', '%' . $request->input('store_title') . '%');
});
}
if ($request->filled('is_admin') && auth('admin')->user()) {
$map[] = ['member_id', '=', auth('admin')->user()['uid']];
$query->whereIn('type', ['service_income', 'service_withdraw', 'service_transfer']);
}else{
$query->whereIn('type', ['income', 'withdraw', 'pay']);
}
if ($request->filled('type')) {
if (is_string($request->input('type'))){
$map[] = ['type', '=', $request->input('type')];
}else if (is_array($request->input('type'))){
$query->whereIn('type', $request->input('type'));
}
}
$query->where($map);
if($request->filled('page')){
$data = [
'total' => $query->count(),
'page' => $request->input('page', 1),
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 30))->get()->each(function($item){
if (in_array($item->type, ['income', 'withdraw','pay'])){
$item->member = $item->member()->select(['uid', 'username', 'nickname', 'avatar'])->first();
}else if (in_array($item->type, ['service_income', 'service_withdraw'])){
$item->member = $item->admin()->select(['uid', 'username', 'nickname', 'avatar'])->first();
}else{
$item->member = $item->member()->select(['uid', 'username', 'nickname', 'avatar'])->first();
}
}),
];
}else{
$data = $query->limit($request->input('limit', 30))->get();
}
return $data;
}
/**
* @title 添加会员
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function createPolymer($store_id, $order_id, $member_id, $amount, $type, $account_type, $remark){
if($order_id != 0){
$polymer = MemberPolymer::where('order_id', '=', $order_id)->where('member_id', '=', $member_id)->where('type', '=', $type)->where('account_type', '=', $account_type)->first();
if($polymer){
return $polymer;
}
}
$member = Member::where('uid', $member_id)->first();
if(!$member){
return false;
}
$af_amount = $member['polymer_money'] ? (in_array($type, ['pay', 'transfer']) ? bcsub($member['polymer_money'], $amount,2) : bcadd($member['polymer_money'], $amount,2)) : $amount;
$bf_amount = $member['polymer_money'] ? $member['polymer_money'] : 0;
$data = [
'store_id' => $store_id,
'order_id' => $order_id,
'member_id' => $member_id,
'type' => $type,
'account_type' => $account_type,
'amount' => $amount,
'bf_amount' => $bf_amount,
'af_amount' => $af_amount,
'status' => 0,
'remark' => $remark,
];
if ($af_amount < 0){
throw new \Exception("会员积分余额不足!", 0);
}
if (in_array($type, ['pay', 'transfer'])){
$member->polymer_money = bcsub($member->polymer_money, $amount, 2);
}else{
$member->polymer_money = bcadd($member->polymer_money, $amount, 2);
}
$member->save();
$polymer = MemberPolymer::create($data);
return $polymer;
}
/**
* @title 修改会员
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function update($request){
$request->validate([
'title' => 'required|max:255',
'name' => 'required|max:255|alpha_dash:ascii|unique:member_level,name,' . $request->input('id'),
]);
try {
$polymer = MemberPolymer::findOrFail($request->input('id'));
} catch (\Throwable $th) {
throw new \Exception("会员不存在!", 1);
}
$data = [
'title'=> $request->input('title', ''),
'name' => $request->input('name', ''),
'icon' => $request->input('icon', ''),
'sort' => $request->input('sort', 0),
'status' => $request->input('status', 1),
'remark' => $request->input('remark', ''),
];
$polymer->update($data);
return $polymer;
}
public function delete($request){
if($request->filled('id')){
try {
$polymer = MemberPolymer::findOrFail($request->input('id'));
} catch (\Throwable $th) {
throw new \Exception("会员等级不存在!", 1);
}
$polymer->delete();
}
if($request->filled('ids')){
try {
$polymer = MemberPolymer::whereIn('id', $request->input('ids'));
$polymer->delete();
} catch (\Throwable $th) {
throw new \Exception($th->getMessage(), 1);
}
}
return $polymer;
}
}
...@@ -68,7 +68,7 @@ class PromoterService { ...@@ -68,7 +68,7 @@ class PromoterService {
$map[] = ['uid', '=', auth('api')->user()['uid']]; $map[] = ['uid', '=', auth('api')->user()['uid']];
$member = Member::with(['level'])->select(['uid', 'username', 'nickname', 'mobile', 'avatar', 'score', 'money', 'level_id', 'invite_uid'])->where($map)->first(); $member = Member::with(['level'])->select(['uid', 'username', 'nickname', 'mobile', 'avatar', 'score', 'money', 'polymer_money', 'level_id', 'invite_uid'])->where($map)->first();
if ($member) { if ($member) {
$member->invite = Member::where('uid', $member->invite_uid)->select(['uid', 'username', 'nickname', 'avatar'])->first(); $member->invite = Member::where('uid', $member->invite_uid)->select(['uid', 'username', 'nickname', 'avatar'])->first();
......
...@@ -93,9 +93,9 @@ class ScoreService { ...@@ -93,9 +93,9 @@ class ScoreService {
* @param MemberService $service * @param MemberService $service
* @return void * @return void
*/ */
public function createScore($order_id, $member_id, $amount, $type, $remark){ public function createScore($store_id, $order_id, $member_id, $amount, $type, $account_type, $remark){
if($order_id != 0){ if($order_id != 0){
$score = MemberScore::where('order_id', '=', $order_id)->where('member_id', '=', $member_id)->where('type', '=', $type)->first(); $score = MemberScore::where('order_id', '=', $order_id)->where('member_id', '=', $member_id)->where('type', '=', $type)->where('account_type', '=', $account_type)->first();
if($score){ if($score){
return $score; return $score;
} }
...@@ -106,14 +106,15 @@ class ScoreService { ...@@ -106,14 +106,15 @@ class ScoreService {
if(!$member){ if(!$member){
return false; return false;
} }
$af_amount = $member['score'] ? (in_array($type, ['pay', 'transfer']) ? bcsub($member['score'], $amount) : bcadd($member['score'], $amount)) : $amount; $af_amount = $member['score'] ? (in_array($type, ['pay', 'transfer']) ? bcsub($member['score'], $amount,2) : bcadd($member['score'], $amount,2)) : $amount;
$bf_amount = $member['score'] ? $member['score'] : 0; $bf_amount = $member['score'] ? $member['score'] : 0;
$data = [ $data = [
'store_id' => 0, 'store_id' => $store_id,
'order_id' => $order_id, 'order_id' => $order_id,
'member_id' => $member_id, 'member_id' => $member_id,
'type' => $type, 'type' => $type,
'account_type' => $account_type,
'amount' => $amount, 'amount' => $amount,
'bf_amount' => $bf_amount, 'bf_amount' => $bf_amount,
'af_amount' => $af_amount, 'af_amount' => $af_amount,
......
<?php
namespace Modules\Member\Services;
use Modules\Member\Models\Member;
use Modules\Member\Models\SignRecord;
class SignService
{
/**
* @title 获取签到列表
*
* @param [type] $request
* @return void
*/
public function getDataList($request){
$map = [];
if($request->filled('is_user')){
$map[] = ['member_id', '=', auth('api')->user()['uid']];
}
if($request->filled('month')){
$map[] = ['month', '=', $request->input('month')];
}
$query = SignRecord::where($map)->orderBy('id', 'desc');
if($request->filled('page')){
$data = [
'total' => $query->count(),
'page' => $request->input('page', 1),
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
];
}else{
$data = $query->get();
}
return $data;
}
/**
* @title 添加签到
*
* @param Request $request
* @return void
*/
public function create($request){
$member_id=auth('api')->user()['uid'];
$checkSign=SignRecord::where(['member_id' => $member_id])->whereDate('created_at', date('Y-m-d'))->count();
if($checkSign){
throw new \Exception('不能重复签到');
}
$config = cache()->get('config');
$member = Member::where('uid', $member_id)->first();
if(!$member){
throw new \Exception('用户不存在!');
}
if($config['sign_score']){//送积分
$member->score = bcadd($member->score, $config['sign_score']);
$member->save();
}
$record = new SignRecord();
$record->member_id = $member_id;
$record->score = $config['sign_score'];
$record->day = date('d');
$record->month = date('Y-m');
$record->save();
return $checkSign;
}
}
\ No newline at end of file
...@@ -65,6 +65,10 @@ return new class extends Migration { ...@@ -65,6 +65,10 @@ return new class extends Migration {
$table->tinyInteger('status')->default(1)->comment('状态 0未用,1已转账,2已提现,3提现记录'); $table->tinyInteger('status')->default(1)->comment('状态 0未用,1已转账,2已提现,3提现记录');
$table->timestamp('created_at')->nullable()->comment('创建时间'); $table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间'); $table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->string('bank_realname', 255)->nullable()->comment('真实姓名');
$table->string('reason', 255)->nullable()->comment('申请理由');
$table->string('out_batch_no', 255)->nullable()->comment('商家批次单号');
$table->string('detail_status', 255)->nullable()->comment('单号查询状态');
$table->engine = 'InnoDB'; $table->engine = 'InnoDB';
$table->charset = 'utf8mb4'; $table->charset = 'utf8mb4';
...@@ -77,6 +81,7 @@ return new class extends Migration { ...@@ -77,6 +81,7 @@ return new class extends Migration {
$table->unsignedBigInteger('order_id')->comment('订单ID'); $table->unsignedBigInteger('order_id')->comment('订单ID');
$table->unsignedBigInteger('store_id')->comment('店铺ID'); $table->unsignedBigInteger('store_id')->comment('店铺ID');
$table->string('type', '20')->nullable()->comment('类型'); $table->string('type', '20')->nullable()->comment('类型');
$table->string('account_type', '20')->nullable()->comment('账单类型');
$table->decimal('amount', total: 10, places: 2)->default(0)->comment('数量'); $table->decimal('amount', total: 10, places: 2)->default(0)->comment('数量');
$table->decimal('bf_amount', total: 10, places: 2)->default(0)->comment('前数量'); $table->decimal('bf_amount', total: 10, places: 2)->default(0)->comment('前数量');
$table->decimal('af_amount', total: 10, places: 2)->default(0)->comment('后数量'); $table->decimal('af_amount', total: 10, places: 2)->default(0)->comment('后数量');
...@@ -90,6 +95,26 @@ return new class extends Migration { ...@@ -90,6 +95,26 @@ return new class extends Migration {
$table->collation = 'utf8mb4_unicode_ci'; $table->collation = 'utf8mb4_unicode_ci';
$table->comment('会员积分表'); $table->comment('会员积分表');
}); });
Schema::create('member_polymer', function (Blueprint $table) {
$table->id()->uniqid()->comment('主键id');
$table->unsignedBigInteger('member_id')->comment('会员id');
$table->unsignedBigInteger('order_id')->comment('订单ID');
$table->unsignedBigInteger('store_id')->comment('店铺ID');
$table->string('type', '20')->nullable()->comment('类型');
$table->string('account_type', '20')->nullable()->comment('账单类型');
$table->decimal('amount', total: 10, places: 2)->default(0)->comment('数量');
$table->decimal('bf_amount', total: 10, places: 2)->default(0)->comment('前数量');
$table->decimal('af_amount', total: 10, places: 2)->default(0)->comment('后数量');
$table->string('remark', 255)->nullable()->comment('备注');
$table->tinyInteger('status')->default(1)->comment('状态 0未用,1已核销');
$table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->comment('会员聚物通表');
});
Schema::create('member_bank', function (Blueprint $table) { Schema::create('member_bank', function (Blueprint $table) {
$table->id()->uniqid()->comment('主键id'); $table->id()->uniqid()->comment('主键id');
$table->unsignedBigInteger('member_id')->comment('会员id'); $table->unsignedBigInteger('member_id')->comment('会员id');
...@@ -119,6 +144,7 @@ return new class extends Migration { ...@@ -119,6 +144,7 @@ return new class extends Migration {
Schema::dropIfExists('member_address'); Schema::dropIfExists('member_address');
Schema::dropIfExists('member_account'); Schema::dropIfExists('member_account');
Schema::dropIfExists('member_score'); Schema::dropIfExists('member_score');
Schema::dropIfExists('member_polymer');
Schema::dropIfExists('member_bank'); Schema::dropIfExists('member_bank');
} }
}; };
...@@ -28,6 +28,7 @@ Route::name('member.')->prefix('member')->middleware(['auth.check:admin'])->grou ...@@ -28,6 +28,7 @@ Route::name('member.')->prefix('member')->middleware(['auth.check:admin'])->grou
Route::post('/add', 'add')->name('add'); Route::post('/add', 'add')->name('add');
Route::put('/edit', 'edit')->name('edit'); Route::put('/edit', 'edit')->name('edit');
Route::delete('/delete', 'delete')->name('delete'); Route::delete('/delete', 'delete')->name('delete');
Route::post('/withdraw', 'withdraw')->name('withdraw');
}); });
Route::controller(Modules\Member\Controllers\Admin\Score::class)->prefix('score')->name('score.')->group(function () { Route::controller(Modules\Member\Controllers\Admin\Score::class)->prefix('score')->name('score.')->group(function () {
Route::get('/index', 'index')->name('index'); Route::get('/index', 'index')->name('index');
...@@ -35,8 +36,17 @@ Route::name('member.')->prefix('member')->middleware(['auth.check:admin'])->grou ...@@ -35,8 +36,17 @@ Route::name('member.')->prefix('member')->middleware(['auth.check:admin'])->grou
Route::put('/edit', 'edit')->name('edit'); Route::put('/edit', 'edit')->name('edit');
Route::delete('/delete', 'delete')->name('delete'); Route::delete('/delete', 'delete')->name('delete');
}); });
Route::controller(Modules\Member\Controllers\Admin\Polymer::class)->prefix('polymer')->name('polymer.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::post('/add', 'add')->name('add');
Route::put('/edit', 'edit')->name('edit');
Route::delete('/delete', 'delete')->name('delete');
});
Route::controller(Modules\Member\Controllers\Admin\Promoter::class)->prefix('promoter')->name('promoter.')->group(function () { Route::controller(Modules\Member\Controllers\Admin\Promoter::class)->prefix('promoter')->name('promoter.')->group(function () {
Route::get('/index', 'index')->name('index'); Route::get('/index', 'index')->name('index');
Route::put('/audit', 'audit')->name('audit'); Route::put('/audit', 'audit')->name('audit');
}); });
Route::controller(Modules\Member\Controllers\Admin\Sign::class)->prefix('sign')->name('sign.')->group(function () {
Route::get('/index', 'index')->name('index');
});
}); });
...@@ -42,6 +42,10 @@ Route::name('member.')->prefix('member')->middleware(['auth.check:api'])->group( ...@@ -42,6 +42,10 @@ Route::name('member.')->prefix('member')->middleware(['auth.check:api'])->group(
Route::get('/index', 'index')->name('index'); Route::get('/index', 'index')->name('index');
}); });
Route::controller(Modules\Member\Controllers\Api\Polymer::class)->prefix('polymer')->name('polymer.')->group(function () {
Route::get('/index', 'index')->name('index');
});
Route::controller(Modules\Member\Controllers\Api\Collect::class)->prefix('collect')->name('collect.')->group(function () { Route::controller(Modules\Member\Controllers\Api\Collect::class)->prefix('collect')->name('collect.')->group(function () {
Route::get('/index', 'index')->name('index'); Route::get('/index', 'index')->name('index');
Route::post('/add', 'add')->name('add'); Route::post('/add', 'add')->name('add');
...@@ -60,4 +64,9 @@ Route::name('member.')->prefix('member')->middleware(['auth.check:api'])->group( ...@@ -60,4 +64,9 @@ Route::name('member.')->prefix('member')->middleware(['auth.check:api'])->group(
Route::post('/withdraw', 'withdraw')->name('withdraw'); Route::post('/withdraw', 'withdraw')->name('withdraw');
Route::get('/count', 'count')->name('count'); Route::get('/count', 'count')->name('count');
}); });
Route::controller(Modules\Member\Controllers\Api\Sign::class)->prefix('sign')->name('sign.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::get('/add', 'add')->name('add');
});
}); });
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Order\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Order\Services\CashierService;
/**收银台
* Class Cashier
* @package Modules\Order\Controllers\Admin
*/
class Cashier extends BaseController {
/**
* @title 购物车列表
*
* @param Request $request
* @param CartService $service
* @return void
*/
public function index(Request $request, CashierService $service){
try {
$this->data['data'] = $service->getDataList(auth('admin')->user()['uid']);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
/**
* @title 添加购物车
*
* @param Request $request
* @param CartService $service
* @return void
*/
public function add(Request $request, CashierService $service){
try {
$this->data['data'] = $service->create($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
/**
* @title 更新购物车
*
* @param Request $request
* @param CartService $service
* @return void
*/
public function edit(Request $request, CashierService $service){
try {
$this->data['data'] = $service->update($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
/**
* @title 删除购物车
*
* @param Request $request
* @param CartService $service
* @return void
*/
public function delete(Request $request, CashierService $service){
try {
$this->data['data'] = $service->delete($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
/**
* @title 立即下单
*
* @param Request $request
* @param OrderService $service
* @return void
*/
public function simple(Request $request, CashierService $service){
try {
$this->data['data'] = $service->simple($request);
$this->data['message'] = '下单成功';
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
}
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Order\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Order\Services\ExchangeService;
class Exchange extends BaseController {
/**
* @title 列表
*
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request, ExchangeService $service){
try {
$this->data['data'] = $service->getDataList($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
}
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Order\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Order\Services\ExchangeService;
class Exchange extends BaseController {
/**
* @title 添加置换收集订单记录
*
* @param Request $request
* @param ExchangeService $service
* @return void
*/
public function add(Request $request, ExchangeService $service){
try {
$this->data['data'] = $service->create($request);
$this->data['message'] = '添加成功,请耐心等候';
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
}
\ No newline at end of file
...@@ -62,7 +62,12 @@ class Order extends BaseController { ...@@ -62,7 +62,12 @@ class Order extends BaseController {
*/ */
public function add(Request $request, OrderService $service){ public function add(Request $request, OrderService $service){
try { try {
$this->data['data'] = $service->create($request); $this->data['data'] = $order = $service->create($request);
if(($order->amount - $order->polymer_money) == 0 ){
app(OrderService::class)->paySuccess($order->order_no);
$this->data['code'] =9999;
}
$this->data['message'] = '下单成功'; $this->data['message'] = '下单成功';
} catch (\Throwable $th) { } catch (\Throwable $th) {
$this->data['code'] = 0; $this->data['code'] = 0;
...@@ -81,7 +86,12 @@ class Order extends BaseController { ...@@ -81,7 +86,12 @@ class Order extends BaseController {
*/ */
public function simple(Request $request, OrderService $service){ public function simple(Request $request, OrderService $service){
try { try {
$this->data['data'] = $service->simpleCreate($request); $this->data['data'] = $order = $service->simpleCreate($request);
if(($order->amount - $order->polymer_money) == 0 ){
app(OrderService::class)->paySuccess($order->order_no);
$this->data['code'] =9999;
}
} catch (\Throwable $th) { } catch (\Throwable $th) {
$this->data['code'] = 0; $this->data['code'] = 0;
$this->data['message'] = $th->getMessage(); $this->data['message'] = $th->getMessage();
......
...@@ -91,7 +91,7 @@ class OrderBlance implements ShouldQueue{ ...@@ -91,7 +91,7 @@ class OrderBlance implements ShouldQueue{
app(AccountService::class)->createAccount(store_id: $store->id, order_id: $item->id, member_id: $store->service_id, type: 'service_income', account_type: 'order', amount: $balance_service_amount, remark: '分仓服务费'); app(AccountService::class)->createAccount(store_id: $store->id, order_id: $item->id, member_id: $store->service_id, type: 'service_income', account_type: 'order', amount: $balance_service_amount, remark: '分仓服务费');
} }
if($balance_service_integral > 0 && $store->service_id){ if($balance_service_integral > 0 && $store->service_id){
app(ScoreService::class)->createScore(order_id: $item->id, member_id: $store->service_id, amount: $balance_service_integral, type: 'service_income', remark: '分仓服务费'); app(ScoreService::class)->createScore(store_id: $store->id, order_id: $item->id, member_id: $store->service_id, amount: $balance_service_integral, type: 'service_income', account_type: 'order', remark: '分仓服务费');
} }
//推广人员服务费 //推广人员服务费
...@@ -104,7 +104,7 @@ class OrderBlance implements ShouldQueue{ ...@@ -104,7 +104,7 @@ class OrderBlance implements ShouldQueue{
app(AccountService::class)->createAccount(store_id: $store->id, order_id: $item->id, member_id: $invite->uid, type: 'income', account_type: 'order', amount: $balance_service_amount, remark: '兼职代理服务费'); app(AccountService::class)->createAccount(store_id: $store->id, order_id: $item->id, member_id: $invite->uid, type: 'income', account_type: 'order', amount: $balance_service_amount, remark: '兼职代理服务费');
} }
if($balance_service_integral > 0){ if($balance_service_integral > 0){
app(ScoreService::class)->createScore(order_id: $item->id, member_id: $invite->uid, amount: $balance_service_integral, type: 'income', remark: '兼职代理服务费'); app(ScoreService::class)->createScore(store_id: $store->id, order_id: $item->id, member_id: $invite->uid, amount: $balance_service_integral, type: 'income', account_type: 'order', remark: '兼职代理服务费');
} }
}else if($invite->level->name == 'signings'){ }else if($invite->level->name == 'signings'){
// 签约代理 // 签约代理
...@@ -114,7 +114,7 @@ class OrderBlance implements ShouldQueue{ ...@@ -114,7 +114,7 @@ class OrderBlance implements ShouldQueue{
app(AccountService::class)->createAccount(store_id: $store->id, order_id: $item->id, member_id: $invite->uid, type: 'income', account_type: 'order', amount: $balance_service_amount, remark: '签约代理服务费'); app(AccountService::class)->createAccount(store_id: $store->id, order_id: $item->id, member_id: $invite->uid, type: 'income', account_type: 'order', amount: $balance_service_amount, remark: '签约代理服务费');
} }
if($balance_service_integral > 0){ if($balance_service_integral > 0){
app(ScoreService::class)->createScore(order_id: $item->id, member_id: $invite->uid, amount: $balance_service_integral, type: 'income', remark: '签约代理服务费'); app(ScoreService::class)->createScore(store_id: $store->id, order_id: $item->id, member_id: $invite->uid, amount: $balance_service_integral, type: 'income', account_type: 'order', remark: '签约代理服务费');
} }
} }
} }
...@@ -128,7 +128,7 @@ class OrderBlance implements ShouldQueue{ ...@@ -128,7 +128,7 @@ class OrderBlance implements ShouldQueue{
app(AccountService::class)->createAccount(store_id: $store->id, order_id: $item->id, member_id: $store->member_id, type: 'income', account_type: 'order', amount: $amount, remark: '店主门店收入'); app(AccountService::class)->createAccount(store_id: $store->id, order_id: $item->id, member_id: $store->member_id, type: 'income', account_type: 'order', amount: $amount, remark: '店主门店收入');
} }
if($integral > 0){ if($integral > 0){
app(ScoreService::class)->createScore(order_id: $item->id, member_id: $store->member_id, amount: $integral, type: 'income', remark: '店主门店收入'); app(ScoreService::class)->createScore(store_id: $store->id, order_id: $item->id, member_id: $store->member_id, amount: $integral, type: 'income', account_type: 'order', remark: '店主门店收入');
} }
} }
} }
......
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Order\Models;
use App\Models\BaseModel;
class Exchange extends BaseModel {
protected $table = 'exchange_order';
protected $fillable = ['uid', 'name', 'mobile', 'status', 'created_at', 'address', 'remark', 'updated_at'];
// protected $hidden = ['deleted'];
protected function casts(): array {
return [
'status' => 'integer',
'created_at' => 'datetime:Y-m-d H:i:s',
'updated_at' => 'datetime:Y-m-d H:i:s',
];
}
}
...@@ -13,7 +13,7 @@ use App\Models\BaseModel; ...@@ -13,7 +13,7 @@ use App\Models\BaseModel;
class Order extends BaseModel { class Order extends BaseModel {
protected $table = 'order'; protected $table = 'order';
protected $fillable = ['order_no', 'store_id', 'member_id', 'invite_uid', 'amount', 'pay_type', 'pay_no', 'delivery_type', 'delivery_no', 'delivery_info', 'status', 'pay_time', 'confirm_time', 'comment_time', 'close_time', 'refund_time', 'refund_no']; protected $fillable = ['order_no', 'store_id', 'member_id', 'invite_uid', 'amount', 'pay_type', 'pay_no', 'delivery_type', 'delivery_no', 'delivery_info', 'status', 'pay_time', 'confirm_time', 'comment_time', 'close_time', 'refund_time', 'refund_no','delivery_type'];
// protected $hidden = ['deleted_at']; // protected $hidden = ['deleted_at'];
protected function casts(): array { protected function casts(): array {
......
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Order\Services;
use Illuminate\Support\Str;
use Modules\Goods\Models\GoodsSku;
use Modules\Order\Models\Cart;
use Modules\Goods\Models\Goods;
use Modules\Order\Models\Order;
use Modules\Order\Models\OrderItem;
class CashierService {
/**
* @title 获取购物车列表
*
* @return void
*/
public function getDataList($admin_id){
$data = Cart::with(['goods:id,title,price,cover,stock,sales,integral', 'store:id,title,cover', 'sku'])->where('admin_id', $admin_id)->get();
return $data;
}
public function create($request){
$request->validate([
'goods_sn' => 'required',
'num' => 'required',
], [
'goods_sn.required' => '商品编号不能为空',
'num.required' => '商品数量不能为空',
]);
$goods_id = $request->input('goods_id');
$goods_sku_id = $request->input('goods_sku_id');
//通过扫码获取商品编号
if(!empty($request->input('goods_sn'))){
$goods_sn=$request->input('goods_sn');
$goodsSN=Goods::where(['goods_sn' => $goods_sn])->first();
if(!empty($goodsSN)){
$goods_id = empty($goodsSN)?$goods_id:$goodsSN->id;
}else{
$goodsSKUSN=GoodsSku::where(['goods_sn' => $goods_sn])->first();
if(!empty($goodsSKUSN)){
$goods_id = empty($goodsSKUSN)?$goods_id:$goodsSKUSN->goods_id;
$goods_sku_id = empty($goodsSKUSN)?$goods_id:$goodsSKUSN->id;
}
}
/*$firstChar = substr($goods_sn, 0, 1); // 截取第一个字符
if($firstChar == "G"){
$goodsSN=Goods::where(['goods_sn' => $goods_sn])->first();
$goods_id = empty($goodsSN)?$goods_id:$goodsSN->id;
}else if($firstChar == "S"){
$goodsSKUSN=GoodsSku::where(['goods_sn' => $goods_sn])->first();
$goods_id = empty($goodsSKUSN)?$goods_id:$goodsSKUSN->goods_id;
$goods_sku_id = empty($goodsSKUSN)?$goods_id:$goodsSKUSN->id;
}*/
}
/////////////////////////////////////////////////////////
$goods = Goods::find($goods_id);
if(!$goods){
throw new \Exception("商品不存在!", 1);
}
$cart = Cart::where('goods_id', $goods_id)->where('admin_id', auth('admin')->user()['uid'])->where('goods_sku_id', $goods_sku_id);
if($cart->doesntExist()){
$cart = new Cart();
$request->merge([
'admin_id' => auth('admin')->user()['uid']
]);
foreach ($cart->setFilterFields($request->all()) as $key => $value) {
if($value != ''){
$cart->$key = $value;
}
}
if($cart->num > $goods->stock){
throw new \Exception("商品库存不足!", 1);
}
}else{
$cart = $cart->first();
if($cart->num > $goods->stock){
throw new \Exception("商品库存不足!", 1);
}
$cart->num = $cart->num + $request->input('num', 1);
}
$cart->goods_id = $goods_id;
$cart->goods_sku_id = $goods_sku_id;
$cart->store_id = $goods->store_id;
$cart->save();
return $cart;
}
public function update($request){
$cart = Cart::where('id', $request->input('id'))->where('admin_id', auth('admin')->user()['uid'])->first();
if(!$cart){
throw new \Exception("购物车不存在!", 1);
}
foreach ($cart->setFilterFields($request->only(['goods_sku_id', 'num'])) as $key => $value) {
if($value){
$cart->$key = $value;
}
}
$cart->save();
return $cart;
}
public function delete($request){
if($request->filled('id')){
try {
$cart = Cart::findOrFail($request->input('id'));
} catch (\Throwable $th) {
throw new \Exception("购物车不存在!", 1);
}
$cart->delete();
}
if($request->filled('ids')){
try {
$cart = Cart::whereIn('id', $request->input('ids'));
} catch (\Throwable $th) {
throw new \Exception($th->getMessage(), 1);
}
$cart->delete();
}
return $cart;
}
/**
* @title 添加订单
*
* @param [type] $request
* @return void
*/
public function simple($request){
$request->validate([
'carts' => 'required',
], [
'carts.required' => '请选择商品',
]);
$order = new Order();
$request->mergeIfMissing(['admin_id' => auth('admin')->user()['uid']]);
if($request->filled('carts')){
$cartsQuery = Cart::with(['goods', 'sku'])->whereIn('id', $request->input('carts'))->where('admin_id', '=', $request->input('admin_id'));
}
if($cartsQuery->doesntExist()){
throw new \Exception("请先加入购物车!", 0);
}
$orderGoods = [];
$carts = $cartsQuery->get()->map(function($item) use (&$orderGoods, $request) {
if(!$item->goods){
throw new \Exception("商品不存在!", 0);
}
if($item->goods->status != 1){
throw new \Exception("商品已下架!", 0);
}
if(!$item->goods->is_repeat_buy){
$orderGoodsQuery = OrderItem::where('goods_id', '=', $item->goods_id)->where('admin_id', '=', $request->input('admin_id'))->where('status', '>=', 3);
if($orderGoodsQuery->exists()){
throw new \Exception("您已购买过此商品,当前产品不能复购!", 0);
}
}
if($item->sku){
if($item->sku->stock < $item->num){
throw new \Exception("商品库存不足!", 0);
}
$item->amount = $item->sku->price * $item->num;
$item->integral = $item->sku->integral * $item->num;
}else{
if($item->goods->stock < $item->num){
throw new \Exception("商品库存不足!", 0);
}
$item->amount = $item->goods->price * $item->num;
$item->integral = $item->goods->integral * $item->num;
}
$orderGoods[] = new OrderItem([
'member_id' =>0,
'store_id' => $item->store_id,
'goods_id' => $item->goods_id,
'goods_sku_id' => $item->goods_sku_id,
'title' => $item->goods->title,
'cover' => $item->goods->cover,
'price' => $item->goods->price,
'integral' => $item->goods->integral,
'total_price' => $item->amount,
'total_integral' => $item->integral,
'num' => $item->num,
'status' => 0,
]);
return $item;
});
$order->order_no = str_replace('-', '', Str::orderedUuid());
$order->member_id =0;
$order->invite_uid = $request->input('invite_uid') ?? 0;
$order->pay_type = $request->input('pay_type') ?? 'wechat';
$order->amount = $carts->sum('amount');
$order->integral = $carts->sum('integral');
$order->status = 0;
$order->admin_id = auth('admin')->user()['uid'];
$order->save();
//下单完成后,删除购物车
$cartsQuery->delete();
$order->detail()->saveMany($orderGoods);
return $order;
}
}
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Order\Services;
use Modules\Order\Models\Exchange;
class ExchangeService {
public function getDataList($request){
$map = [];
if($request->filled('name')){
$map[] = ['name', 'like', '%'.$request->input('name').'%'];
}
if($request->filled('is_user')){
$map[] = ['mobile', 'like', '%'.$request->input('mobile').'%'];
}
$query = Exchange::where($map)->orderBy('id', 'desc');
if($request->filled('page')){
$data = [
'total' => $query->count(),
'page' => $request->input('page', 1),
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
];
}else{
$data = $query->get();
}
return $data;
}
/**
* @title 添加置换收集订单
*
* @param [type] $request
* @return void
*/
public function create($request)
{
$request->validate([
'name' => 'required',
'address' => 'required',
'mobile' => 'required',
], [
'name.required' => '请填写姓名',
'mobile.required' => '请填写手机号码',
// 'mobile.regex' => '手机号格式不正确',
'address.required' => '请填写所在地址'
]);
$exchange = new Exchange();
$info = Exchange::where(['mobile' => $request->input('mobile')])->first();
if($info){
throw new \Exception("此号码已填写过", 0);
}
$exchange->uid = auth('api')->user()['uid'];
$exchange->name = $request->input('name');
$exchange->mobile = $request->input('mobile');
$exchange->status = 1;
$exchange->address = $request->input('address');
$exchange->remark = $request->input('remark') ?? '';
$exchange->save();
return $exchange;
}
}
\ No newline at end of file
...@@ -193,6 +193,8 @@ class OrderService { ...@@ -193,6 +193,8 @@ class OrderService {
return $data; return $data;
} }
/** /**
* @title 添加订单 * @title 添加订单
* *
...@@ -246,6 +248,9 @@ class OrderService { ...@@ -246,6 +248,9 @@ class OrderService {
$item->amount = $item->goods->price * $item->num; $item->amount = $item->goods->price * $item->num;
$item->integral = $item->goods->integral * $item->num; $item->integral = $item->goods->integral * $item->num;
} }
//使用聚物通资金不可用积分
$item->goods->integral = $item->integral = $request->input('pay_way')=="integral" ? $item->integral:0;
$orderGoods[] = new OrderItem([ $orderGoods[] = new OrderItem([
'member_id' => auth('api')->user()['uid'], 'member_id' => auth('api')->user()['uid'],
'store_id' => $item->store_id, 'store_id' => $item->store_id,
...@@ -269,8 +274,17 @@ class OrderService { ...@@ -269,8 +274,17 @@ class OrderService {
$order->pay_type = $request->input('pay_type') ?? 'wechat'; $order->pay_type = $request->input('pay_type') ?? 'wechat';
$order->amount = $carts->sum('amount'); $order->amount = $carts->sum('amount');
$order->integral = $carts->sum('integral'); $order->integral = $carts->sum('integral');
$order->pay_way =$request->input('pay_way');
$order->status = 0; $order->status = 0;
if($request->input('pay_way') == "polymer_money"){
if(auth('api')->user()['polymer_money'] >= $order->amount){
$order->polymer_money = $order->amount;//聚物通
}else{
$order->polymer_money = auth('api')->user()['polymer_money'];
}
}
if($order->integral > auth('api')->user()['score']){ if($order->integral > auth('api')->user()['score']){
throw new \Exception("积分不足!", 0); throw new \Exception("积分不足!", 0);
} }
...@@ -297,6 +311,9 @@ class OrderService { ...@@ -297,6 +311,9 @@ class OrderService {
], [ ], [
'goods_id.required' => '请选择商品', 'goods_id.required' => '请选择商品',
]); ]);
$pay_way=$request->input('pay_way') ?? 'wechat';//付款方式
$order = new Order(); $order = new Order();
$goods = Goods::where('id', '=', $request->input('goods_id'))->first(); $goods = Goods::where('id', '=', $request->input('goods_id'))->first();
...@@ -331,6 +348,9 @@ class OrderService { ...@@ -331,6 +348,9 @@ class OrderService {
if(!$sku){ if(!$sku){
throw new \Exception("商品规格不存在!", 0); throw new \Exception("商品规格不存在!", 0);
} }
//使用聚物通资金不可用积分
$sku->integral = $pay_way == "integral"?$sku->integral:0;
$orderGoods = new OrderItem([ $orderGoods = new OrderItem([
'member_id' => auth('api')->user()['uid'], 'member_id' => auth('api')->user()['uid'],
'store_id' => $goods->store_id, 'store_id' => $goods->store_id,
...@@ -348,6 +368,9 @@ class OrderService { ...@@ -348,6 +368,9 @@ class OrderService {
$amount = $sku->price; $amount = $sku->price;
$integral = $sku->integral; $integral = $sku->integral;
}else{ }else{
//使用聚物通资金不可用积分
$goods->integral = $pay_way == "integral"?$goods->integral:0;
$orderGoods = new OrderItem([ $orderGoods = new OrderItem([
'member_id' => auth('api')->user()['uid'], 'member_id' => auth('api')->user()['uid'],
'store_id' => $goods->store_id, 'store_id' => $goods->store_id,
...@@ -370,10 +393,20 @@ class OrderService { ...@@ -370,10 +393,20 @@ class OrderService {
$order->member_id = auth('api')->user()['uid']; $order->member_id = auth('api')->user()['uid'];
$order->invite_uid = $request->input('invite_uid') ?? 0; $order->invite_uid = $request->input('invite_uid') ?? 0;
$order->pay_type = $request->input('pay_type') ?? 'wechat'; $order->pay_type = $request->input('pay_type') ?? 'wechat';
$order->delivery_type = $request->input('delivery_type') ?? 1;
$order->amount = $amount; $order->amount = $amount;
$order->integral = $integral; $order->integral = $integral;//积分
$order->pay_way =$pay_way;
$order->status = 0; $order->status = 0;
if($pay_way == "polymer_money"){
if(auth('api')->user()['polymer_money'] >= $amount){
$order->polymer_money = $amount;//聚物通
}else{
$order->polymer_money = auth('api')->user()['polymer_money'];
}
}
if($order->integral > auth('api')->user()['score']){ if($order->integral > auth('api')->user()['score']){
throw new \Exception("积分不足!", 0); throw new \Exception("积分不足!", 0);
} }
...@@ -402,7 +435,7 @@ class OrderService { ...@@ -402,7 +435,7 @@ class OrderService {
* @return void * @return void
*/ */
public function update($request){ public function update($request){
$order = Order::where('id', '=', $data['id'])->first(); $order = Order::where('id', '=', $request->input('id'))->first();
if(!$order){ if(!$order){
throw new \Exception("订单不存在!", 0); throw new \Exception("订单不存在!", 0);
} }
...@@ -517,10 +550,14 @@ class OrderService { ...@@ -517,10 +550,14 @@ class OrderService {
$itemCount = $order->detail()->count(); $itemCount = $order->detail()->count();
// 订单详情商品处理 // 订单详情商品处理
$order->detail()->with(['goods', 'sku'])->get()->each(function($item) use ($order, $itemCount) { $order->detail()->with(['goods', 'sku'])->get()->each(function($item,$key) use ($order, $itemCount) {
// 积分商品积分扣除 // 积分商品积分扣除
if($item->total_integral > 0){ if($item->total_integral > 0){
app(\Modules\Member\Services\ScoreService::class)->createScore(order_id: $item->id, member_id: $order->member['uid'], type: 'pay', amount: $item->total_integral, remark: '订单支付'); app(\Modules\Member\Services\ScoreService::class)->createScore(store_id: $item->store_id, order_id: $item->id, member_id: $order->member['uid'], type: 'pay', account_type: 'order', amount: $item->total_integral, remark: '订单支付');
}
// 聚物通扣除
if( $key== 0 && $order->polymer_money > 0){
app(\Modules\Member\Services\PolymerService::class)->createPolymer(store_id: $item->store_id, order_id: $item->id, member_id: $order->member['uid'], type: 'pay', account_type: 'order', amount: $order->polymer_money, remark: '订单支付');
} }
if($item->goods->goods_type == 0){ if($item->goods->goods_type == 0){
$item->status = 3; $item->status = 3;
...@@ -701,21 +738,51 @@ class OrderService { ...@@ -701,21 +738,51 @@ class OrderService {
if(!$order){ if(!$order){
throw new \Exception("订单不存在!", 0); throw new \Exception("订单不存在!", 0);
} }
$item = $order->detail()->where('id', $request->input('detail_id'))->first();
if(!$item){
throw new \Exception("订单详情不存在!", 0);
}
if ($request->is('api/*') && auth('api')->user()){
//判断是否为店主 //判断是否为店主
$level = auth('api')->user()->level()->where('store_id', '=', $order['store_id'])->first(); $store = \Modules\Store\Models\Store::where('id', $item['store_id'])->where('status', 1)->select(['id', 'member_id', 'status'])->first();
if(!$level || $level['name'] != 'master'){ if($store->member_id != auth('api')->user()->uid){
throw new \Exception("您不是店主,无权发货!", 0); throw new \Exception("您不是店主,无权发货!", 0);
} }
}else{
throw new \Exception("请先登录!", 0);
}
$order->status = 3; $order->status = 3;
$order->confirm_time = date('Y-m-d H:i:s'); $order->confirm_time = date('Y-m-d H:i:s');
$order->save(); $order->save();
\Modules\Goods\Events\OrderTake::dispatch($order); $item->status = 3;
$item->delivery_time = date('Y-m-d H:i:s');
$item->delivery_type = $request->input('delivery_type', 'pickup');
$item->save();
\Modules\Order\Events\OrderTake::dispatch($order, $item);
return $order; return $order;
} }
/**商家订单详情
* @param $request
* @return \Illuminate\Database\Concerns\TValue|null
* @throws \Exception
*/
public function getDetailsData($request){
$map = [];
$map[] = ['order_no', '=', $request->input('order_no')];
$data = Order::with(['member', 'detail', 'detail.goods:id,title,price,integral', 'detail.sku', 'detail.store:id,title,cover'])->where($map)->first();
if(!$data){
throw new \Exception("订单不存在!", 0);
}
return $data;
}
/** /**
* @title 订单退款 * @title 订单退款
* *
......
...@@ -89,7 +89,7 @@ class RefundService { ...@@ -89,7 +89,7 @@ class RefundService {
$refund->status = 0; $refund->status = 0;
$refund->refund_no = str_replace('-', '', Str::orderedUuid()); $refund->refund_no = str_replace('-', '', Str::orderedUuid());
$refund->amount = $item->total_price-$item->total_integral; $refund->amount = $item->total_price-$item->total_integral;
// $refund->amount = $item->total_price;
if($refund->save()){ if($refund->save()){
$item->status = 4; $item->status = 4;
$item->save(); $item->save();
......
...@@ -45,6 +45,7 @@ return new class extends Migration ...@@ -45,6 +45,7 @@ return new class extends Migration
$table->string('refund_no')->nullable()->comment('退款单号'); $table->string('refund_no')->nullable()->comment('退款单号');
$table->timestamp('created_at')->nullable()->comment('创建时间'); $table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间'); $table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->string('delivery_type')->nullable()->comment('配送方式');
$table->softDeletes(); $table->softDeletes();
$table->engine = 'InnoDB'; $table->engine = 'InnoDB';
......
...@@ -27,6 +27,7 @@ class OrderDatabaseSeeder extends Seeder ...@@ -27,6 +27,7 @@ class OrderDatabaseSeeder extends Seeder
['title' => '订单', 'name' => 'order', 'path' => '/order', 'component' => '', 'type' => 'menu', 'sort' => 5, 'children' => [ ['title' => '订单', 'name' => 'order', 'path' => '/order', 'component' => '', 'type' => 'menu', 'sort' => 5, 'children' => [
['title' => '订单列表', 'name' => 'order.list', 'path' => '/order/list', 'component' => 'order/list', 'type' => 'menu'], ['title' => '订单列表', 'name' => 'order.list', 'path' => '/order/list', 'component' => 'order/list', 'type' => 'menu'],
['title' => '售后订单', 'name' => 'order.refund', 'path' => '/order/refund', 'component' => 'order/refund', 'type' => 'menu'], ['title' => '售后订单', 'name' => 'order.refund', 'path' => '/order/refund', 'component' => 'order/refund', 'type' => 'menu'],
['title' => '置换订单联系记录', 'name' => 'order.exchange', 'path' => '/order/exchange', 'component' => 'order/exchange', 'type' => 'menu'],
] ]
] ]
]; ];
......
...@@ -23,4 +23,13 @@ Route::name('order.')->prefix('order')->middleware(['auth.check:admin'])->group( ...@@ -23,4 +23,13 @@ Route::name('order.')->prefix('order')->middleware(['auth.check:admin'])->group(
Route::get('/index', 'index')->name('index'); Route::get('/index', 'index')->name('index');
Route::put('/audit', 'audit')->name('audit'); Route::put('/audit', 'audit')->name('audit');
}); });
Route::controller(Modules\Order\Controllers\Admin\Exchange::class)->prefix('exchange')->name('exchange.')->group(function () {
Route::get('/index', 'index')->name('index');
});
Route::controller(Modules\Order\Controllers\Admin\Cashier::class)->prefix('cashier')->name('cashier.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::post('/add', 'add')->name('add');
Route::put('/edit', 'edit')->name('edit');
Route::post('/simple', 'simple')->name('simple');
});
}); });
...@@ -38,4 +38,7 @@ Route::name('order.')->prefix('order')->middleware(['auth.check:api'])->group(fu ...@@ -38,4 +38,7 @@ Route::name('order.')->prefix('order')->middleware(['auth.check:api'])->group(fu
Route::put('/edit', 'edit')->name('edit'); Route::put('/edit', 'edit')->name('edit');
Route::delete('/delete', 'delete')->name('delete'); Route::delete('/delete', 'delete')->name('delete');
}); });
Route::controller(Modules\Order\Controllers\Api\Exchange::class)->prefix('exchange')->name('exchange.')->group(function () {
Route::post('/add', 'add')->name('add');
});
}); });
...@@ -10,7 +10,7 @@ namespace Modules\Store\Controllers\Api; ...@@ -10,7 +10,7 @@ namespace Modules\Store\Controllers\Api;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Controllers\BaseController; use App\Http\Controllers\BaseController;
use Modules\Goods\Services\OrderService; use Modules\Order\Services\OrderService;
class Order extends BaseController { class Order extends BaseController {
...@@ -32,4 +32,22 @@ class Order extends BaseController { ...@@ -32,4 +32,22 @@ class Order extends BaseController {
return response()->json($this->data); return response()->json($this->data);
} }
/**
* @title 订单详情
*
* @param Request $request
* @param \Modules\Order\Services\OrderService $service
* @return void
*/
public function detail(Request $request, OrderService $service){
try {
$this->data['data'] = $service->getDetailsData($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
} }
...@@ -42,7 +42,13 @@ class Payment extends BaseController { ...@@ -42,7 +42,13 @@ class Payment extends BaseController {
'amount.required' => '请输入金额', 'amount.required' => '请输入金额',
'integral.required' => '请输入积分', 'integral.required' => '请输入积分',
]); ]);
$this->data['data'] = $service->create(store_id: $request->input('store_id'), amount: $request->input('amount'), integral: $request->input('integral'), remark: $request->input('remark')); $polymer_money=$request->input('polymer_money',0);
$this->data['data'] = $payment = $service->create(store_id: $request->input('store_id'), amount: $request->input('amount'), integral: $request->input('integral'), polymer_money: $polymer_money,pay_way: $request->input('pay_way'),remark: $request->input('remark'));
if($payment->amount == 0){//聚物通支付完成
app(PaymentService::class)->paySuccess($payment->order_no, null);
$this->data['code'] =9999;
}
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->data['code'] = 0; $this->data['code'] = 0;
$this->data['message'] = $e->getMessage(); $this->data['message'] = $e->getMessage();
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
namespace Modules\Store\Listeners; namespace Modules\Store\Listeners;
use Illuminate\Support\Facades\Log;
use Modules\Member\Services\PolymerService;
use Modules\Store\Events\PaySuccess; use Modules\Store\Events\PaySuccess;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
...@@ -21,7 +23,51 @@ class PayBlance implements ShouldQueue{ ...@@ -21,7 +23,51 @@ class PayBlance implements ShouldQueue{
* Handle the event. * Handle the event.
*/ */
public function handle(PaySuccess $event){ public function handle(PaySuccess $event){
$order = $event->order; $order = $event->payment;
$store = $order->store()->first();
//Log::info("分仓服务费".$store->balance_service_rate);
if($store->balance_service_rate > 0){//分仓服务费
$integral = $order->integral; //店主收入计算
$polymer_money = $order->polymer_money; //店主收入计算
//本金
$cost_money = bcdiv(($order->polymer_money + $order->amount),bcdiv(($store->balance_service_rate + 100),100,2),2);
//Log::info("分仓服务费本金".$cost_money);
//分仓服务费
$balance_service_amount = bcsub(($order->polymer_money + $order->amount), $cost_money, 2);
$amount = bcsub($order->amount, $balance_service_amount, 2); //店主收入计算
if($balance_service_amount > 0 && $store->service_id){
//Log::info("分仓服务费资金".$balance_service_amount);
app(AccountService::class)->createAccount(store_id: $store->id, order_id: $order->id, member_id: $store->service_id, type: 'service_income', account_type: 'payment', amount: $balance_service_amount, remark: '店铺收款分仓服务费');
}
}else{
$amount = $order->amount; //店主收入计算
$integral = $order->integral; //店主收入计算
$polymer_money = $order->polymer_money; //店主收入计算
}
//店主收入
if($amount > 0){
app(AccountService::class)->createAccount(store_id: $order->store_id, order_id: $order->id, member_id: $store->member_id, type: 'income', account_type: 'payment', amount: $amount, remark: '店铺内客户支付');
}
if($integral > 0){
app(ScoreService::class)->createScore(store_id: $store->id, order_id: $order->id, member_id: $store->member_id, amount: $integral, type: 'income', account_type: 'payment', remark: '店铺内客户支付');
}
if($polymer_money > 0){
app(PolymerService::class)->createPolymer(store_id: $store->id, order_id: $order->id, member_id: $store->member_id, type: 'income', account_type: 'payment', amount: $polymer_money, remark: '店铺内客户支付');
}
}
/**原始
* Handle the event.
*/
/*public function handle(PaySuccess $event){
$order = $event->payment;
$store = $order->store()->first(); $store = $order->store()->first();
...@@ -31,11 +77,11 @@ class PayBlance implements ShouldQueue{ ...@@ -31,11 +77,11 @@ class PayBlance implements ShouldQueue{
$invite = null; $invite = null;
} }
if($store->balance_rate > 0){ if($store->balance_rate > 0){
$balance_amount = bcmul($item->amount, bcdiv($store->balance_rate, 100, 2), 2); $balance_amount = bcmul($order->amount, bcdiv($store->balance_rate, 100, 2), 2);
$balance_integral = bcmul($item->integral, bcdiv($store->balance_rate, 100, 2), 2); $balance_integral = bcmul($order->integral, bcdiv($store->balance_rate, 100, 2), 2);
$amount = bcsub($item->amount, $balance_amount, 2); //店主收入计算 $amount = bcsub($order->amount, $balance_amount, 2); //店主收入计算
$integral = bcsub($item->integral, $balance_integral, 2); //店主收入计算 $integral = bcsub($order->integral, $balance_integral, 2); //店主收入计算
// 分仓服务费 // 分仓服务费
$balance_service_amount = bcmul($balance_amount, bcdiv($store->balance_service_rate, 100, 2), 2); $balance_service_amount = bcmul($balance_amount, bcdiv($store->balance_service_rate, 100, 2), 2);
...@@ -44,7 +90,7 @@ class PayBlance implements ShouldQueue{ ...@@ -44,7 +90,7 @@ class PayBlance implements ShouldQueue{
app(AccountService::class)->createAccount(store_id: $store->id, order_id: $order->id, member_id: $store->service_id, type: 'service_income', account_type: 'payment', amount: $balance_service_amount, remark: '店铺收款分仓服务费'); app(AccountService::class)->createAccount(store_id: $store->id, order_id: $order->id, member_id: $store->service_id, type: 'service_income', account_type: 'payment', amount: $balance_service_amount, remark: '店铺收款分仓服务费');
} }
if($balance_service_integral > 0 && $store->service_id){ if($balance_service_integral > 0 && $store->service_id){
app(ScoreService::class)->createScore(order_id: $order->id, member_id: $store->service_id, amount: $balance_service_integral, type: 'service_income', remark: '店铺收款分仓服务费'); app(ScoreService::class)->createScore(store_id: $store->id, order_id: $order->id, member_id: $store->service_id, amount: $balance_service_integral, type: 'service_income', account_type: 'payment', remark: '店铺收款分仓服务费');
} }
//推广人员服务费 //推广人员服务费
...@@ -57,7 +103,7 @@ class PayBlance implements ShouldQueue{ ...@@ -57,7 +103,7 @@ class PayBlance implements ShouldQueue{
app(AccountService::class)->createAccount(store_id: $store->id, order_id: $order->id, member_id: $invite->uid, type: 'income', account_type: 'payment', amount: $balance_service_amount, remark: '店铺收款兼职代理服务费'); app(AccountService::class)->createAccount(store_id: $store->id, order_id: $order->id, member_id: $invite->uid, type: 'income', account_type: 'payment', amount: $balance_service_amount, remark: '店铺收款兼职代理服务费');
} }
if($balance_service_integral > 0){ if($balance_service_integral > 0){
app(ScoreService::class)->createScore(order_id: $order->id, member_id: $invite->uid, amount: $balance_service_integral, type: 'income', remark: '店铺收款兼职代理服务费'); app(ScoreService::class)->createScore(store_id: $store->id, order_id: $order->id, member_id: $invite->uid, amount: $balance_service_integral, type: 'income', account_type: 'payment', remark: '店铺收款兼职代理服务费');
} }
}else if($invite->level->name == 'signings'){ }else if($invite->level->name == 'signings'){
// 签约代理 // 签约代理
...@@ -67,13 +113,13 @@ class PayBlance implements ShouldQueue{ ...@@ -67,13 +113,13 @@ class PayBlance implements ShouldQueue{
app(AccountService::class)->createAccount(store_id: $store->id, order_id: $order->id, member_id: $invite->uid, type: 'income', account_type: 'payment', amount: $balance_service_amount, remark: '店铺收款签约代理服务费'); app(AccountService::class)->createAccount(store_id: $store->id, order_id: $order->id, member_id: $invite->uid, type: 'income', account_type: 'payment', amount: $balance_service_amount, remark: '店铺收款签约代理服务费');
} }
if($balance_service_integral > 0){ if($balance_service_integral > 0){
app(ScoreService::class)->createScore(order_id: $order->id, member_id: $invite->uid, amount: $balance_service_integral, type: 'income', remark: '店铺收款签约代理服务费'); app(ScoreService::class)->createScore(store_id: $store->id, order_id: $order->id, member_id: $invite->uid, amount: $balance_service_integral, type: 'income', account_type: 'payment', remark: '店铺收款签约代理服务费');
} }
} }
} }
}else{ }else{
$amount = $item->amount; //店主收入计算 $amount = $order->amount; //店主收入计算
$integral = $item->integral; //店主收入计算 $integral = $order->integral; //店主收入计算
} }
//店主收入 //店主收入
...@@ -81,7 +127,7 @@ class PayBlance implements ShouldQueue{ ...@@ -81,7 +127,7 @@ class PayBlance implements ShouldQueue{
app(AccountService::class)->createAccount(store_id: $order->store_id, order_id: $order->id, member_id: $store->member_id, type: 'income', account_type: 'payment', amount: $amount, remark: '店铺内客户支付'); app(AccountService::class)->createAccount(store_id: $order->store_id, order_id: $order->id, member_id: $store->member_id, type: 'income', account_type: 'payment', amount: $amount, remark: '店铺内客户支付');
} }
if($order->integral > 0){ if($order->integral > 0){
app(ScoreService::class)->createScore(order_id: $order->id, member_id: $store->member_id, amount: $integral, type: 'income', remark: '店铺内客户支付'); app(ScoreService::class)->createScore(store_id: $store->id, order_id: $order->id, member_id: $store->member_id, amount: $integral, type: 'income', account_type: 'payment', remark: '店铺内客户支付');
}
} }
}*/
} }
\ No newline at end of file
...@@ -47,7 +47,7 @@ class PaymentService { ...@@ -47,7 +47,7 @@ class PaymentService {
return $data; return $data;
} }
public function create($store_id, $amount, $integral, $remark){ public function create($store_id, $amount, $integral, $polymer_money,$pay_way,$remark){
$payment = new Payment(); $payment = new Payment();
...@@ -56,15 +56,25 @@ class PaymentService { ...@@ -56,15 +56,25 @@ class PaymentService {
$payment->member_id = auth('api')->user()->uid; $payment->member_id = auth('api')->user()->uid;
$payment->amount = $amount; $payment->amount = $amount;
$payment->integral = $integral; $payment->integral = $integral;
$payment->polymer_money = $polymer_money;
$payment->pay_way = $pay_way;
$payment->payment_remark = $remark ? $remark : '店铺收款'; $payment->payment_remark = $remark ? $remark : '店铺收款';
$payment->payment_status = 0; $payment->payment_status = 0;
if(($amount + $integral +$polymer_money ) <=0){
throw new \Exception("请输入支付金额!", 0);
}
//判断积分是否满足 //判断积分是否满足
$member = auth('api')->user(); $member = auth('api')->user();
if($member['score'] < $integral){ if($pay_way == "integral" && $member['score'] < $integral){
throw new \Exception("积分不足!", 0); throw new \Exception("积分不足!", 0);
} }
if($pay_way == "polymer_money" && $member['polymer_money'] < $polymer_money){
throw new \Exception("聚物通不足!", 0);
}
$payment->save(); $payment->save();
return $payment; return $payment;
} }
...@@ -95,16 +105,35 @@ class PaymentService { ...@@ -95,16 +105,35 @@ class PaymentService {
} }
public function paySuccess($order_no, $payment_no){ public function paySuccess($order_no, $payment_no){
$payment = Payment::with(['member'])->where($order_no, $order_no)->first(); $payment = Payment::where('order_no', $order_no)->first();
if($payment && $payment->status == 0){ if($payment && $payment->status == 0){
if($payment->integral > 0){//扣除积分
app(\Modules\Member\Services\ScoreService::class)->createScore(store_id: $item->store_id, order_id: $item->id, member_id: $order->member['uid'], type: 'pay', account_type: 'payment', amount: $item->total_integral, remark: '订单支付');
}
if($payment->polymer_money > 0){//扣除聚物通资金
app(\Modules\Member\Services\PolymerService::class)->createPolymer(store_id: $payment->store_id, order_id: $payment->id, member_id: $payment->member['uid'], type: 'pay', account_type: 'payment', amount: $payment->polymer_money, remark: '店铺支付');
}
$res = app(\Modules\Wechat\Services\PayService::class)->orderQuery($order_no);
if(isset($res['trade_state']) && $res['trade_state'] == 'SUCCESS'){
$payment->payment_status = 1; $payment->payment_status = 1;
$payment->payment_time = date('Y-m-d H:i:s'); $payment->payment_time = date('Y-m-d H:i:s');
$payment->payment_sn = $payment_no; $payment->payment_sn = $payment_no;
$payment->save(); $payment->save();
app(ShippingService::class)->pushShipping($order_no, $payment->member_id, '店铺内付款支付'); // app(ShippingService::class)->pushShipping($order_no, $payment->member_id, '店铺内付款支付');
\Modules\Store\Events\PaySuccess::dispatch($payment); \Modules\Store\Events\PaySuccess::dispatch($payment);
}else if($payment->amount == 0){
$payment->payment_status = 1;
$payment->payment_time = date('Y-m-d H:i:s');
$payment->save();
if($payment->polymer_money > 0) {//入账聚物通资金
app(\Modules\Member\Services\PolymerService::class)->createPolymer(store_id: $payment->store_id, order_id: $payment->id, member_id: $payment->store['member_id'], type: 'income', account_type: 'payment', amount: $payment->polymer_money, remark: '店铺内客户支付');
}
}
} }
} }
...@@ -166,33 +195,41 @@ class PaymentService { ...@@ -166,33 +195,41 @@ class PaymentService {
break; break;
case 'score': case 'score':
app(ScoreService::class)->createScore( app(ScoreService::class)->createScore(
store_id: 0,
order_id: 0, order_id: 0,
member_id: auth('api')->user()['uid'], member_id: auth('api')->user()['uid'],
amount: $amount, amount: $amount,
type: 'transfer', type: 'transfer',
account_type: 'member',
remark: '用户转账扣除' remark: '用户转账扣除'
); );
app(ScoreService::class)->createScore( app(ScoreService::class)->createScore(
store_id: 0,
order_id: 0, order_id: 0,
member_id: $uid, member_id: $uid,
amount: $amount, amount: $amount,
type: 'income', type: 'income',
account_type: 'member',
remark: '用户转账' remark: '用户转账'
); );
break; break;
default: default:
app(ScoreService::class)->createScore( app(ScoreService::class)->createScore(
store_id: 0,
order_id: 0, order_id: 0,
member_id: auth('api')->user()['uid'], member_id: auth('api')->user()['uid'],
amount: $amount, amount: $amount,
type: 'transfer', type: 'transfer',
account_type: 'member',
remark: '用户转账扣除' remark: '用户转账扣除'
); );
app(ScoreService::class)->createScore( app(ScoreService::class)->createScore(
store_id: 0,
order_id: 0, order_id: 0,
member_id: $uid, member_id: $uid,
amount: $amount, amount: $amount,
type: 'income', type: 'income',
account_type: 'member',
remark: '用户转账' remark: '用户转账'
); );
break; break;
...@@ -261,17 +298,21 @@ class PaymentService { ...@@ -261,17 +298,21 @@ class PaymentService {
break; break;
case 'score': case 'score':
app(ScoreService::class)->createScore( app(ScoreService::class)->createScore(
store_id: 0,
order_id: 0, order_id: 0,
member_id: auth('api')->user()['uid'], member_id: auth('api')->user()['uid'],
amount: $amount, amount: $amount,
type: 'transfer', type: 'transfer',
account_type: 'receive',
remark: '店铺转账扣除' remark: '店铺转账扣除'
); );
app(ScoreService::class)->createScore( app(ScoreService::class)->createScore(
store_id: 0,
order_id: 0, order_id: 0,
member_id: $service_id, member_id: $service_id,
amount: $amount, amount: $amount,
type: 'service_income', type: 'service_income',
account_type: 'receive',
remark: '店铺转账' remark: '店铺转账'
); );
break; break;
......
...@@ -21,6 +21,8 @@ return new class extends Migration { ...@@ -21,6 +21,8 @@ return new class extends Migration {
$table->string('payment_remark')->nullable()->comment('收款备注'); $table->string('payment_remark')->nullable()->comment('收款备注');
$table->timestamp('created_at')->nullable()->comment('创建时间'); $table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间'); $table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->decimal('polymer_money', total: 10, places: 2)->default(0)->comment('聚物通');
$table->string('pay_way')->nullable()->comment('付款方式');
$table->engine = 'InnoDB'; $table->engine = 'InnoDB';
$table->charset = 'utf8mb4'; $table->charset = 'utf8mb4';
......
...@@ -10,6 +10,7 @@ namespace Modules\System\Controllers\Api; ...@@ -10,6 +10,7 @@ namespace Modules\System\Controllers\Api;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Controllers\BaseController; use App\Http\Controllers\BaseController;
use Illuminate\Support\Facades\Storage;
class File extends BaseController { class File extends BaseController {
...@@ -82,6 +83,9 @@ class File extends BaseController { ...@@ -82,6 +83,9 @@ class File extends BaseController {
$path = $file->store('images/'.date('Ymd')); $path = $file->store('images/'.date('Ymd'));
// 保存图片到storage/app/public/images目录
//$bool = Storage::disk('public')->put($path, file_get_contents($file -> getRealPath()));//解决方式 换成 Storage::disk('')->put()
$data = [ $data = [
'path' => $path, 'path' => $path,
'url' => Storage::disk()->url($path), 'url' => Storage::disk()->url($path),
......
...@@ -44,4 +44,14 @@ class Notify extends BaseController { ...@@ -44,4 +44,14 @@ class Notify extends BaseController {
} }
return 'success'; return 'success';
} }
public function transfer(Request $request, NotifyService $service){
try {
return $service->transferNotify($request);
} catch (\Throwable $th) {
$this->data['message'] = $th->getMessage();
$this->data['code'] = 0;
}
return 'success';
}
} }
\ No newline at end of file
...@@ -24,4 +24,15 @@ class Pay extends BaseController { ...@@ -24,4 +24,15 @@ class Pay extends BaseController {
return response()->json($this->data); return response()->json($this->data);
} }
public function nativepc(Request $request, PayService $service){
try {
$this->data['data'] = $service->getNativePayData('native', $request);
} catch (\Exception $th) {
$this->data['message'] = $th->getMessage();
$this->data['code'] = $th->getCode();
}
return response()->json($this->data);
}
} }
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Wechat\Listeners;
use Modules\Store\Events\PaySuccess;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Modules\Wechat\Services\ShippingService;
class StorePaymentSuccess implements ShouldQueue{
/**
* 任务应该被处理的时间(秒)。
*
* @var int
*/
public $delay = 60;
public function handle(PaySuccess $event){
$payment = $event->payment;
app(ShippingService::class)->pushShipping($payment->order_no, $payment->member_id, $payment->payment_remark, 3);
return true;
}
}
\ No newline at end of file
...@@ -30,6 +30,9 @@ class EventServiceProvider extends ServiceProvider ...@@ -30,6 +30,9 @@ class EventServiceProvider extends ServiceProvider
'Modules\Order\Events\OrderTake' => [ 'Modules\Order\Events\OrderTake' => [
'Modules\Wechat\Listeners\OrderTakePush', 'Modules\Wechat\Listeners\OrderTakePush',
], ],
'Modules\Store\Events\PaySuccess' => [
'Modules\Wechat\Listeners\StorePaymentSuccess',
],
]; ];
/** /**
......
...@@ -9,8 +9,12 @@ ...@@ -9,8 +9,12 @@
namespace Modules\Wechat\Services; namespace Modules\Wechat\Services;
use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use EasyWeChat\Pay\Application; use EasyWeChat\Pay\Application;
use Modules\Member\Models\Member;
use Modules\Member\Models\MemberAccount;
use Modules\Order\Services\OrderService; use Modules\Order\Services\OrderService;
use Modules\Store\Services\PaymentService; use Modules\Store\Services\PaymentService;
use Modules\Order\Services\RefundService; use Modules\Order\Services\RefundService;
...@@ -55,6 +59,36 @@ class NotifyService { ...@@ -55,6 +59,36 @@ class NotifyService {
app(RefundService::class)->refundSuccess($message); app(RefundService::class)->refundSuccess($message);
}); });
return $server->serve();
}
public function transferNotify($request){
$config = Config::get('wechat.miniapp');
$app = new Application($config);
$server = $app->getServer();
//Log::info("转账到零钱异步返回通知:");
// 处理退款结果事件
//DB::connection()->enableQueryLog();
$data= MemberAccount::where(['status'=>1,'detail_status'=>null])->whereNotNull("out_batch_no")->select()->get();
//print_r(DB::getQueryLog());
foreach ($data as $key=>$val){
$result = TransferService::transferQuery($val['out_batch_no'],$val['request_no']);
if(isset($result['code']) && !empty($result['code'])){
MemberAccount::where(['id'=>$val['id']])->update(['status'=>-2,'reason'=>$result['message'],'detail_status'=>$result['fail_reason']]);
//提现失败金额退回
/*$user = Member::find($val['member_id']);
$user->money = bcadd($user->money, $val['amount'], 2);
$user->save();*/
}else{
MemberAccount::where(['id'=>$val['id']])->update(['detail_status'=>'SUCCESS']);
}
}
return $server->serve(); return $server->serve();
} }
} }
\ No newline at end of file
...@@ -30,6 +30,7 @@ class PayService { ...@@ -30,6 +30,7 @@ class PayService {
case 'order': case 'order':
$data = app('Modules\Order\Services\OrderService')->getjsPayData($request, $from); $data = app('Modules\Order\Services\OrderService')->getjsPayData($request, $from);
$description = "订单支付"; $description = "订单支付";
$data->amount = $data->amount - $data->integral - $data->polymer_money;
break; break;
case 'payment': case 'payment':
$data = app('Modules\Store\Services\PaymentService')->getjsPayData($request, $from); $data = app('Modules\Store\Services\PaymentService')->getjsPayData($request, $from);
...@@ -40,8 +41,6 @@ class PayService { ...@@ -40,8 +41,6 @@ class PayService {
$description = "订单支付"; $description = "订单支付";
break; break;
} }
$data->amount = $data->amount-$data->integral;
$payData = [ $payData = [
'mchid' => $config['mch_id'], 'mchid' => $config['mch_id'],
'appid' => $config['app_id'], 'appid' => $config['app_id'],
...@@ -113,4 +112,73 @@ class PayService { ...@@ -113,4 +112,73 @@ class PayService {
// throw new \Exception($response->getContent(), $response->getStatusCode()); // throw new \Exception($response->getContent(), $response->getStatusCode());
// } // }
} }
public function orderQuery($order_no){
$config = Config::get('wechat.miniapp');
$app = new Application($config);
$api = $app->getClient();
$response = $api->get("v3/pay/transactions/out-trade-no/{$order_no}", [
'query' => [
'mchid' => $config['mch_id'],
]
]);
return $response->toArray();
}
/**
* 用户扫码支付
*/
public function getNativePayData($from,$request){
$config = Config::get('wechat.miniapp');
$app = new Application($config);
$utils = $app->getUtils();
$type = $request->input('type', 'order');
$description = "";
switch ($type) {
case 'order':
$data = app('Modules\Order\Services\OrderService')->getjsPayData($request, $from);
$description = "订单支付";
break;
default:
$data = app('Modules\Order\Services\OrderService')->getjsPayData($request, $from);
$description = "订单支付";
break;
}
$payData = [
'mchid' => $config['mch_id'],
'appid' => $config['app_id'],
'out_trade_no' => $data->order_no,
'description' => $description,
'notify_url' => request()->root() .'/api/wechat/notify/'.$type,
'amount' => [
'total' => intval($data->amount * 100),
'currency' => 'CNY',
],
];
$response = $app->getClient()->postJson("v3/pay/transactions/native", $payData);
if($response->isFailed()){
throw new \Exception($response->getContent(), $response->getStatusCode());
}
$prepayId = $response->toArray()['code_url'];
switch ($type) {
case 'order':
Order::where('id', $data->id)->update(['pay_no' => $prepayId, 'pay_type' => $from]);
break;
default:
Order::where('id', $data->id)->update(['pay_no' => $prepayId, 'pay_type' => $from]);
break;
}
return $utils->buildMiniAppConfig($prepayId, $config['app_id'], 'RSA');
}
} }
\ No newline at end of file
<?php
namespace Modules\Wechat\Services;
use EasyWeChat\Pay\Application;
use Illuminate\Support\Facades\Config;
use Modules\Wechat\Utils\AesUtil;
use Modules\Wechat\Utils\WechatUtil;
class TransferService
{
/**
* 商家转账到零钱
* @param $batch_name
* @param $out_trade_no
* @param $money
* @param $openid
* @throws BaseException
*/
public static function transfer($batch_name, $out_trade_no, $money, $openid,$body='用户提现')
{
$config = Config::get('wechat.miniapp');
$app = new Application($config);
//获取微信支付平台证书序列号
$certificates=self::getCertificates();
$serial_no = isset($certificates['data'][0]['serial_no'])?$certificates['data'][0]['serial_no']:null;
$pars = [];
$pars['appid'] = $config['app_id'];//直连商户的appid
$pars['out_batch_no'] = 'batch' . date('Ymd') . mt_rand(1000, 9999);//商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
$pars['batch_name'] = $body;//该笔批量转账的名称
$pars['batch_remark'] = $body;//转账说明,UTF8编码,最多允许32个字符
$pars['total_amount'] = intval($money * 100);//转账总金额 单位为“分”
$pars['total_num'] = 1;//转账总笔数
$pars['transfer_detail_list'][0] = [
'out_detail_no' => $out_trade_no,
'transfer_amount' => $pars['total_amount'],
'transfer_remark' => $body,
'openid' => $openid,
//'user_name'=> WechatUtil::getEncrypt($batch_name,$config['public_key']),
];//转账明细列表
$pars['notify_url'] = request()->root() .'/api/wechat/notify/transfer';
$result = $app->getClient()->postJson("v3/transfer/batches",$pars,[
'headers'=>[
'Wechatpay-Serial' => $serial_no,
],
]);
$response = json_decode($result, true);
if (!isset($response['create_time'])) { //批次受理失败
return ['code'=>$response['code'],'message'=>$response['message']];
}
return $response['out_batch_no'];
}
//获取微信支付平台证书序列号与生成公钥文件
public static function getCertificates($http_method ="GET"){
$url="https://api.mch.weixin.qq.com/v3/certificates";
$config = Config::get('wechat.miniapp');
$token=WechatUtil::getToken($url, $http_method, array(),$config['mch_id'],$config['certificate'],$config['private_key']);
$result = WechatUtil::https_request_transfer($url,array(),$token);
$result_arr = json_decode($result,true);
if(isset($result_arr['data'])){
$certificate=$result_arr['data'][0]['encrypt_certificate'];
$AesUtil = new AesUtil($config['secret_key']);
$dataDecrypt=$AesUtil->decryptToString($certificate['associated_data'],$certificate['nonce'],$certificate['ciphertext']);
$publicCertKey=fopen($config['public_key'], 'w');
fwrite($publicCertKey, $dataDecrypt);
fclose($publicCertKey);
}
return $result_arr;
}
/**查询商家转账到零钱订单状态
* @param $out_batch_no
* @param $out_detail_no
* @param string $http_method
* @return array|mixed
*/
public static function transferQuery($out_batch_no,$out_detail_no,$http_method ="GET")
{
$url = 'https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no/'.$out_batch_no.'/details/out-detail-no/'.$out_detail_no;
$config = Config::get('wechat.miniapp');
$token=WechatUtil::getToken($url, $http_method, array(),$config['mch_id'],$config['certificate'],$config['private_key']);
$result = WechatUtil::https_request_transfer($url,array(),$token);
$result_arr = json_decode($result,true);
if(isset($result_arr['code']) && !empty($result_arr['code'])){
return ['code'=>-3,'message'=>$result_arr['message'],'fail_reason'=>$result_arr['code']];
}else if(isset($result_arr['fail_reason']) && !empty($result_arr['fail_reason'])){
if($result_arr['fail_reason'] === "ACCOUNT_FROZEN"){
return ['code'=>-3,'message'=>"该用户账户被冻结",'fail_reason'=>$result_arr['code']];
}else if($result_arr['fail_reason'] === "REAL_NAME_CHECK_FAIL"){
return ['code'=>-3,'message'=>"收款人未实名认证,需要用户完成微信实名认证",'fail_reason'=>$result_arr['code']];
}else if($result_arr['fail_reason'] === "NAME_NOT_CORRECT"){
return ['code'=>-3,'message'=>"收款人姓名校验不通过,请核实信息",'fail_reason'=>$result_arr['code']];
}else if($result_arr['fail_reason'] === "OPENID_INVALID"){
return ['code'=>-3,'message'=>"Openid格式错误或者不属于商家公众账号",'fail_reason'=>$result_arr['code']];
}else if($result_arr['fail_reason'] === "TRANSFER_QUOTA_EXCEED"){
return ['code'=>-3,'message'=>"超过用户单笔收款额度,核实产品设置是否准确",'fail_reason'=>$result_arr['code']];
}else if($result_arr['fail_reason'] === "DAY_RECEIVED_QUOTA_EXCEED"){
return ['code'=>-3,'message'=>"超过用户单日收款额度,核实产品设置是否准确",'fail_reason'=>$result_arr['code']];
}else if($result_arr['fail_reason'] === "DAY_RECEIVED_COUNT_EXCEED"){
return ['code'=>-3,'message'=>"超过用户单日收款次数,核实产品设置是否准确",'fail_reason'=>$result_arr['code']];
}else if($result_arr['fail_reason'] === "TRANSFER_RISK"){
return ['code'=>-3,'message'=>"该笔转账可能存在风险,已被微信拦截",'fail_reason'=>$result_arr['code']];
}else {
return ['code'=>-3,'message'=>$result_arr['fail_reason'],'fail_reason'=>$result_arr['code']];
}
}
return true;
}
}
\ No newline at end of file
<?php
namespace Modules\Wechat\Utils;
#php证书和回调报文解密
#https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/zheng-shu-he-hui-tiao-bao-wen-jie-mi
use http\Exception\InvalidArgumentException;
class AesUtil
{
/**
* AES key
*
* @var string
*/
private $aesKey;
const KEY_LENGTH_BYTE = 32;
const AUTH_TAG_LENGTH_BYTE = 16;
/**
* Constructor
*/
public function __construct($aesKey)
{
if (strlen($aesKey) != self::KEY_LENGTH_BYTE) {
throw new InvalidArgumentException('无效的ApiV3Key,长度应为32个字节');
}
$this->aesKey = $aesKey;
}
/**
* Decrypt AEAD_AES_256_GCM ciphertext
*
* @param string $associatedData AES GCM additional authentication data
* @param string $nonceStr AES GCM nonce
* @param string $ciphertext AES GCM cipher text
*
* @return string|bool Decrypted string on success or FALSE on failure
*/
public function decryptToString($associatedData, $nonceStr, $ciphertext)
{
$ciphertext = \base64_decode($ciphertext);
if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
return false;
}
// ext-sodium (default installed on >= PHP 7.2)
if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') &&
\sodium_crypto_aead_aes256gcm_is_available()) {
return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
}
// ext-libsodium (need install libsodium-php 1.x via pecl)
if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') &&
\Sodium\crypto_aead_aes256gcm_is_available()) {
return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
}
// openssl (PHP >= 7.1 support AEAD)
if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
$ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
$authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);
return \openssl_decrypt($ctext, 'aes-256-gcm', $this->aesKey, \OPENSSL_RAW_DATA, $nonceStr,
$authTag, $associatedData);
}
throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
}
}
\ No newline at end of file
<?php
namespace Modules\Wechat\Utils;
class WechatUtil
{
/**
* @notes 敏感信息加解密
*/
public static function getEncrypt($user_name,$cert_path)
{
//$str是待加密字符串
$public_key = file_get_contents($cert_path);
$encrypted = '';
if (openssl_public_encrypt($user_name, $encrypted, $public_key, OPENSSL_PKCS1_OAEP_PADDING)) {
//base64编码
$sign = base64_encode($encrypted);
} else {
throw new \Exception('encrypt failed');
}
return $sign;
}
/**
* 敏感信息解密
* @param $str
* @return string
* @throws Exception
*/
public static function getDecrypt($data,$cert_path_key) {
$private_key = file_get_contents($cert_path_key);
$encrypted = '';
if (openssl_private_decrypt($data, $encrypted, $private_key, OPENSSL_PKCS1_OAEP_PADDING)) {
//base64编码
$sign = $encrypted;
} else {
throw new \Exception('解密失败');
}
return $sign;
}
/**
* @notes 获取签名
*/
public static function getToken($url, $http_method, $data,$mch_id,$wxpayCert,$wxPayCertKey)
{
$timestamp = time(); //请求时间戳
$url_parts = parse_url($url); //获取请求的绝对URL
$nonce = $timestamp . rand('10000', '99999'); //请求随机串
$body = empty($data) ? '' : json_encode((object)$data); //请求报文主体
$stream_opts = [
"ssl" => [
"verify_peer" => false,
"verify_peer_name" => false,
]
];
$apiclient_cert_arr = openssl_x509_parse(file_get_contents($wxpayCert, false, stream_context_create($stream_opts)));
$serial_no = $apiclient_cert_arr['serialNumberHex']; //证书序列号
$mch_private_key = file_get_contents($wxPayCertKey, false, stream_context_create($stream_opts)); //密钥
$merchant_id = $mch_id; //商户id
$canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
$message = $http_method . "\n" .
$canonical_url . "\n" .
$timestamp . "\n" .
$nonce . "\n" .
$body . "\n";
openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
$sign = base64_encode($raw_sign); //签名
$schema = 'WECHATPAY2-SHA256-RSA2048';
$token = sprintf(
'mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
$merchant_id,
$nonce,
$timestamp,
$serial_no,
$sign
); //微信返回token
return $schema . ' ' . $token;
}
/**商家转账到零钱
* @notes 新发送请求
*/
public static function https_request_transfer($url, $data, $token,$serial_no='')
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, (string)$url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)) {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//添加请求头
$headers = [
'Authorization:' . $token,
'Wechatpay-Serial: '.$serial_no,
'Accept: application/json',
'Content-Type: application/json; charset=utf-8',
'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
];
if (!empty($headers)) {
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
}
\ No newline at end of file
...@@ -23,7 +23,9 @@ Route::name('wechat.')->prefix('wechat')->middleware(['auth.check:api'])->group( ...@@ -23,7 +23,9 @@ Route::name('wechat.')->prefix('wechat')->middleware(['auth.check:api'])->group(
Route::post('miniapp', 'miniapp')->name('miniapp'); Route::post('miniapp', 'miniapp')->name('miniapp');
}); });
}); });
Route::post('/wechat/pay/nativepc', [Modules\Wechat\Controllers\Api\Pay::class, 'nativepc']);
Route::post('/wechat/notify/order', [Modules\Wechat\Controllers\Api\Notify::class, 'order']); Route::post('/wechat/notify/order', [Modules\Wechat\Controllers\Api\Notify::class, 'order']);
Route::post('/wechat/notify/payment', [Modules\Wechat\Controllers\Api\Notify::class, 'payment']); Route::post('/wechat/notify/payment', [Modules\Wechat\Controllers\Api\Notify::class, 'payment']);
Route::post('/wechat/notify/refund', [Modules\Wechat\Controllers\Api\Notify::class, 'refund']); Route::post('/wechat/notify/refund', [Modules\Wechat\Controllers\Api\Notify::class, 'refund']);
Route::get('/wechat/notify/transfer', [Modules\Wechat\Controllers\Api\Notify::class, 'transfer']);
\ No newline at end of file
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
"element-plus": "2.8.4", "element-plus": "2.8.4",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinyin-match": "^1.2.4", "pinyin-match": "^1.2.4",
"qr-code-styling": "^1.9.1",
"qrcodejs2": "0.0.2", "qrcodejs2": "0.0.2",
"sortablejs": "1.15.0", "sortablejs": "1.15.0",
"vue": "^3.4.21", "vue": "^3.4.21",
...@@ -34,7 +35,11 @@ ...@@ -34,7 +35,11 @@
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue": "^5.0.4",
"autoprefixer": "^10.0.0",
"postcss": "^8.0.0",
"rollup-plugin-postcss": "^4.0.2",
"sass": "1.77.2", "sass": "1.77.2",
"tailwindcss": "^3.0.0",
"terser": "^5.31.0", "terser": "^5.31.0",
"vite": "^5.2.0" "vite": "^5.2.0"
} }
......
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
\ No newline at end of file
import config from "@/config"
import http from "@/utils/request"
export default {
cart: {
list:{
url: `${config.API_URL}order/cashier/index`,
name: "购物车列表",
get: async function(data){
return await http.get(this.url, data);
}
},
edit: {
url: `${config.API_URL}order/cashier/edit`,
name: "修改购物车",
post: async function(params){
return await http.put(this.url, params);
}
},
delete: {
url: `${config.API_URL}order/cashier/delete`,
name: "删除购物车产品",
post: async function(params){
return await http.delete(this.url, params);
}
},
add: {
url: `${config.API_URL}order/cashier/add`,
name: "添加购物车",
post: async function(params){
return await http.post(this.url, params);
}
},
simple:{
url: `${config.API_URL}order/cashier/simple`,
name: "购物车结算",
post: async function(params){
return await http.post(this.url, params);
}
},
nativepc:{
url: `${config.API_URL_TWO}wechat/pay/nativepc`,
name: "支付订单",
post: async function(params){
return await http.post(this.url, params);
}
},
}
}
\ No newline at end of file
...@@ -92,6 +92,36 @@ export default{ ...@@ -92,6 +92,36 @@ export default{
} }
} }
}, },
polymer: {
list: {
url: `${config.API_URL}member/polymer/index`,
name: "获得聚物通列表",
get: async function(params){
return await http.get(this.url, params);
}
},
add: {
url: `${config.API_URL}member/polymer/add`,
name: "添加聚物通",
post: async function(params){
return await http.post(this.url, params);
}
},
edit: {
url: `${config.API_URL}member/polymer/edit`,
name: "编辑聚物通",
post: async function(params){
return await http.put(this.url, params);
}
},
delete: {
url: `${config.API_URL}member/polymer/delete`,
name: "删除积分",
post: async function(params){
return await http.delete(this.url, params);
}
}
},
account: { account: {
list: { list: {
url: `${config.API_URL}member/account/index`, url: `${config.API_URL}member/account/index`,
...@@ -120,6 +150,13 @@ export default{ ...@@ -120,6 +150,13 @@ export default{
post: async function(params){ post: async function(params){
return await http.delete(this.url, params); return await http.delete(this.url, params);
} }
},
withdraw:{
url: `${config.API_URL}member/account/withdraw`,
name: "通过提现",
post: async function(params){
return await http.post(this.url, params);
}
} }
}, },
promoter: { promoter: {
......
...@@ -68,5 +68,15 @@ export default{ ...@@ -68,5 +68,15 @@ export default{
return await http.put(this.url, params); return await http.put(this.url, params);
} }
} }
},
exchange: {
list: {
url: `${config.API_URL}order/exchange/index`,
name: "获得置换列表",
get: async function(params){
return await http.get(this.url, params);
}
},
} }
} }
@tailwind base;
@tailwind components;
@tailwind utilities;
\ No newline at end of file
...@@ -4,3 +4,6 @@ ...@@ -4,3 +4,6 @@
@import 'media.scss'; @import 'media.scss';
@import 'dark.scss'; @import 'dark.scss';
@import 'diy.scss'; @import 'diy.scss';
<template>
<div ref="qrcode" class="qrcodetags">
</div>
</template>
<script>
import QRCodeStyling from "qr-code-styling";
export default {
name: "QrCode",
props: {
value: {
type: String,
required: true
},
width: {
type: Number,
default: 200
}
},
data() {
return {
qrCode: null // 用于存储二维码实例
};
},
mounted() {
// this.initQRCode();
},
methods: {
initQRCode() {
console.info("initQRCode");
if (this.qrCode) {
this.qrCode.clear(); // 清除已存在的二维码
}
this.qrCode = new QRCodeStyling({
width: this.width,
data: this.value,
image: "", // 如果你想添加logo到二维码中间,可以在这里提供图片URL
dotsOptions: {
color: "#000000"
},
backgroundOptions: {
color: "#ffffff"
},
imageOptions: {
crossOrigin: "anonymous",
margin: 10
}
});
this.qrCode.append(this.$refs.qrcode);
},
updateQRCode(newValue) {
if (this.qrCode) {
this.qrCode.update({ data: newValue }); // 更新二维码的数据
} else {
this.initQRCode(); // 如果还没有初始化,则初始化
}
}
},
watch: {
value(newVal, oldVal) {
if (newVal !== oldVal) {
this.updateQRCode(newVal);
}
}
},
beforeDestroy() {
if (this.qrCode) {
this.qrCode.clear(); // 在组件销毁前清除二维码
}
}
};
</script>
<style scoped>
.qrcodetags{
margin: 0 auto;
width: 200px;
/* height: 200px; */
}
</style>
\ No newline at end of file
...@@ -52,7 +52,8 @@ export default { ...@@ -52,7 +52,8 @@ export default {
{ name: 'price', type: 'input', label: '价格' }, { name: 'price', type: 'input', label: '价格' },
{ name: 'integral', type: 'input', label: '积分' }, { name: 'integral', type: 'input', label: '积分' },
{ name: 'sales', type: 'input', label: '销量' }, { name: 'sales', type: 'input', label: '销量' },
{ name: 'stock', type: 'input', label: '库存' } { name: 'stock', type: 'input', label: '库存' },
{ name: 'goods_sn', type: 'input', label: '产品编号' },
] ]
}, },
// sku 字段分隔符 // sku 字段分隔符
......
...@@ -12,8 +12,8 @@ const DEFAULT_CONFIG = { ...@@ -12,8 +12,8 @@ const DEFAULT_CONFIG = {
CORE_VER: "1.6.6", CORE_VER: "1.6.6",
//接口地址 //接口地址
API_URL: 'https://juwu.xicheda.cn/admin/', API_URL: "https://juwu.xicheda.cn/admin/",
API_URL_TWO: "https://juwu.xicheda.cn/api/",
//请求超时 //请求超时
TIMEOUT: 50000, TIMEOUT: 50000,
......
...@@ -5,7 +5,7 @@ import tool from '@/utils/tool' ...@@ -5,7 +5,7 @@ import tool from '@/utils/tool'
export default { export default {
successCode: 1, //请求完成代码 successCode: 1, //请求完成代码
pageSize: 30, //表格每一页条数 pageSize: 30, //表格每一页条数
pageSizes: [30, 100, 200, 500], //表格可设置的一页条数 pageSizes: [10,30, 100, 200, 500], //表格可设置的一页条数
paginationLayout: "total, sizes, prev, pager, next, jumper", //表格分页布局,可设置"total, sizes, prev, pager, next, jumper" paginationLayout: "total, sizes, prev, pager, next, jumper", //表格分页布局,可设置"total, sizes, prev, pager, next, jumper"
parseData: function (res) { //数据分析 parseData: function (res) { //数据分析
return { return {
......
...@@ -132,7 +132,7 @@ ...@@ -132,7 +132,7 @@
<div v-if="!ismobile" class="aminui-side-split"> <div v-if="!ismobile" class="aminui-side-split">
<div class="aminui-side-split-top"> <div class="aminui-side-split-top">
<router-link :to="$CONFIG.DASHBOARD_URL"> <router-link :to="$CONFIG.DASHBOARD_URL">
<img class="logo" :title="$CONFIG.APP_NAME" :src="'/static/images/logo-r.png'"> <img class="logo" :title="$CONFIG.APP_NAME" :src="'./static/images/logo-r.png'">
</router-link> </router-link>
</div> </div>
<div class="adminui-side-split-scroll"> <div class="adminui-side-split-scroll">
......
...@@ -8,8 +8,16 @@ import router from './router' ...@@ -8,8 +8,16 @@ import router from './router'
import store from './store' import store from './store'
import App from './App.vue' import App from './App.vue'
import './assets/style/main.css'; // 假设 main.css 在 src/assets 目录下
import BarcodeScanner from '@/utils/barcode-scanner';
const app = createApp(App); const app = createApp(App);
//扫码组件
app.use(BarcodeScanner);
app.use(i18n); app.use(i18n);
app.use(store); app.use(store);
app.use(router); app.use(router);
......
.sku_card {
.sku_card_title {
font-size: 15px;
line-height: 40px;
color: #222;
font-weight: bold;
}
.sku_card_main {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
.sku_card_item {
font-size: 12px;
line-height: 24px;
background-color: #f1f2f2;
color: #373737;
margin-right: 10px;
margin-bottom: 10px;
padding: 0 10px;
flex-shrink: 0;
border-radius: 3px;
cursor: pointer;
}
.sku_card_item_active {
background-color: #409eff !important;
color: #fff !important;
}
}
}
.card {
margin: 18px auto 0;
background-color: #fff;
.top {
display: flex;
justify-content: flex-start;
align-items: center;
height: 50px;
font-size: 16px;
line-height: 1;
.shop_name {
margin-left: 5px;
font-size: 15px;
font-weight: normal;
font-stretch: normal;
color: #222222;
}
}
.select_box {
width: 40px;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
font-size: 16px;
.circle {
color: #666;
}
.checked {
color: #f64f15;
}
}
.main {
padding-bottom: 23px;
.card_wrap {
margin-top: 15px;
&:first-child {
margin-top: 0;
}
}
.card_item {
width: 100%;
box-sizing: border-box;
}
.card_item_wrap {
display: flex;
justify-content: flex-start;
align-items: center;
}
.img_wrap {
width: 70px;
height: 70px;
border-radius: 10px;
overflow: hidden;
flex-shrink: 0;
img {
display: block;
width: 70px;
height:70px;
}
}
.info {
margin-left: 20px;
padding-right: 20px;
width: calc(100% - 40px - 100px - 15px);
// height: 70px;
display: flex;
flex-direction: column;
justify-content: space-between;
.it {
.goods_title {
display: block;
width: 100%;
font-size: 12px;
font-weight: bold;
font-stretch: normal;
color: #222222;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.deleteicon{
margin: 6px 0;
display: flex;
justify-content: flex-end;
}
.delete{
cursor: pointer;
color: red;
}
.sku {
height: 26px;
border-radius: 5px;
margin-top: 11px;
font-size: 12px;
line-height: 26px;
font-stretch: normal;
color: #838383;
display: flex;
justify-content: flex-start;
align-items: center;
.text {
padding: 0 10px;
background-color: #f6f6f6;
}
.sku_arr {
display: block;
padding-left: 10px;
padding-right: 10px;
background-color: #f6f6f6;
}
}
}
.ib {
display: flex;
justify-content: space-between;
.pricebox{
display: flex;
align-items: center;
}
.jfprice{
margin-left: 8px;
.price_icon,.price_main{
font-size: 12px !important;
color: #a5a5a5 !important;
}
}
.price {
display: flex;
justify-content: flex-start;
align-items: baseline;
.price_icon {
font-size: 13px;
font-weight: bold;
font-stretch: normal;
color: #f64f15;
}
.price_main {
font-size: 16px;
font-weight: bold;
font-stretch: normal;
color: #f64f15;
.mini {
font-size: 15px;
}
}
.ori {
font-size: 12px;
font-stretch: normal;
color: #8a8a8a;
}
}
.num {
flex-shrink: 0;
--stepper-input-disabled-text-color: #323233;
}
}
}
}
}
.qrcodepup{
text-align: center;
}
<!-- 代码已包含 CSS:使用 TailwindCSS , 安装 TailwindCSS 后方可看到布局样式效果 -->
<template>
<div class="min-h-screen bg-white">
<header @click="gtehomepage" class="h-20 px-8 flex items-center justify-between bg-primary">
<div class="flex items-center gap-3 baselogs">
<img src="@/assets/img/120x120.png" alt="超市logo" class="h-14 w-14 object-contain">
<h1 class="text-2xl font-bold text-white">鹿马生活超市 [收银管理系统]</h1>
</div>
<div class="flex items-center gap-4">
<span class="text-white">{{ currentTime }}</span>
<!-- <div class="flex items-center gap-2 text-white">
<i class="fas fa-user"></i>
<span>收银员:admin</span>
</div> -->
</div>
</header>
<div class="flex h-[calc(100vh-5rem)]">
<!-- 左侧商品区域 -->
<div class="w-2/3 p-6 flex flex-col">
<div class="flex items-center gap-4 mb-6">
<div class="relative max-w-md w-full flex">
<input v-model="keyword" type="text" placeholder="搜索商品"
class="w-full px-5 py-3 pl-12 border rounded-lg focus:outline-none focus:border-primary text-lg">
<!-- <i class="fas fa-search absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 text-xl"></i> -->
<button @click="tosearchfun" class="p-4 !rounded-button bg-gray-100 hover:bg-gray-200 whitespace-nowrap text-lg">搜索</button>
</div>
</div>
<!-- 分类标签 -->
<div class="flex flex-col gap-2 mb-6">
<!-- 一级分类 -->
<div class="flex gap-2 overflow-x-auto pb-2">
<button @click="selectCategory(0)" :class="[
'px-6 py-3 !rounded-button whitespace-nowrap text-lg',
currentCategory === 0 ? 'bg-primary text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'
]">
全部
</button>
<button v-for="category in categories" :key="category.id" @click="selectCategory(category.id)" :class="[
'px-6 py-3 !rounded-button whitespace-nowrap text-lg',
currentCategory === category.id ? 'bg-primary text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'
]">
{{ category.title }}
</button>
</div>
<!-- 二级分类 -->
<div v-if="currentCategoryData.children && currentCategoryData.children.length"
class="flex gap-2 overflow-x-auto pb-2">
<button v-for="subCategory in currentCategoryData.children" :key="subCategory.id"
@click="selectSubCategory(subCategory.id)" :class="[
'px-5 py-2 !rounded-button whitespace-nowrap text-base',
currentSubCategory === subCategory.id ? 'bg-blue-100 text-primary' : 'bg-gray-50 text-gray-500 hover:bg-gray-100'
]">
{{ subCategory.title }}
</button>
</div>
</div>
<!-- 商品列表 -->
<div class="grid grid-cols-4 gap-6 overflow-y-auto flex-1" @scroll.passive="handleScroll" ref="productList">
<div v-for="product in products" :key="product.id" @click="addOrderList(product,0)"
class="bg-white rounded-lg shadow-sm border p-4 cursor-pointer hover:shadow-md transition-shadow">
<div class="aspect-square mb-3 overflow-hidden rounded-lg">
<img :src="product.cover" :alt="product.title"
class="w-full h-full object-cover hover:scale-105 transition-transform">
</div>
<h3 class="font-medium text-gray-800 mb-2 text-xl">{{ product.title }}</h3>
<div class="flex items-center justify-between">
<span class="text-red-600 font-medium text-2xl ">{{ product.price }}</span>
<span class="text-gray-500 text-lg">库存: {{ product.stock }}</span>
</div>
</div>
</div>
</div>
<!-- 右侧购物车 -->
<div class="w-1/3 border-l flex flex-col">
<div class="p-6 border-b">
<h2 class="text-2xl font-bold mb-2">购物车</h2>
<p class="text-gray-600 text-lg">{{ totalItems }} 件商品</p>
</div>
<!-- 购物车列表 -->
<div class="flex-1 overflow-y-auto p-6">
<div v-if="listdata.length === 0" class="text-center text-gray-500 mt-10">
购物车是空的
</div>
<template v-else>
<div>
<div v-for="(item, index) in listdata" :key="index">
<div v-for="(cc, inner) in item.content" :key="inner" class="flex items-center gap-4 mb-4 pb-4 border-b last:border-b-0">
<img :src="cc.goods.cover" :alt="item.name" class="w-20 h-20 rounded object-cover">
<div class="flex-1">
<h3 class="font-medium mb-1 text-lg">{{ cc.goods.title }}</h3>
<div class="text-red-600 text-lg ">{{ cc.formatBig }}{{ cc.formatMini }}</div>
</div>
<div class="flex items-center gap-2">
<button @click.stop="stepMinusHandle('minus',cc)"
class="w-10 h-10 !rounded-button flex items-center justify-center bg-gray-100 hover:bg-gray-200">
-
<!-- <i class="fas fa-minus"></i> -->
</button>
<span class="w-10 text-center text-lg">{{ cc.num }}</span>
<button @click.stop="stepMinusHandle('add',cc)"
class="w-10 h-10 !rounded-button flex items-center justify-center bg-gray-100 hover:bg-gray-200">
<!-- <i class="fas fa-plus"></i> -->
+
</button>
</div>
</div>
</div>
</div>
</template>
</div>
<!-- 结算区域 -->
<div class="p-6 border-t bg-gray-50">
<div class="flex justify-between mb-6">
<span class="text-gray-600 text-lg">总计</span>
<span class="text-2xl font-bold text-red-600">¥{{ totalMoney }}</span>
</div>
<div class="grid grid-cols-2 gap-6 mb-6">
<button @click="delAllGoods" class="p-4 !rounded-button bg-gray-100 hover:bg-gray-200 whitespace-nowrap text-lg">清空</button>
<button @click="delAllGoods" class="p-4 !rounded-button bg-gray-100 hover:bg-gray-200 whitespace-nowrap text-lg">清空</button>
</div>
<button @click="checkoutfun()"
class="w-full p-5 !rounded-button bg-primary text-white hover:bg-primary/90 whitespace-nowrap text-xl">
结算
</button>
</div>
</div>
</div>
<!-- Message -->
<div v-if="message.show" :class="[
'message',
message.type === 'success' ? 'success' : 'warning'
]">
{{ message.text }}
</div>
<!-- 弹窗选择规格 -->
<el-dialog
v-model="dialogVisible"
title="选择规格"
width="500"
:before-close="handleClose"
>
<div>
<div class="sku_card" v-for="(item, outer) in childgoods.spec_list" :key="outer">
<div class="sku_card_title">{{ item.name }}</div>
<div class="sku_card_main">
<div :class="{
sku_card_item: true,
sku_card_item_active: item.value[inner] === item.selected,
}" v-for="(cc, inner) in item.value" :key="inner" @click="skuTapHandle(item, outer, cc)">
{{ cc }}
</div>
</div>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="addCartHandle()">
确定
</el-button>
</div>
</template>
</el-dialog>
<el-dialog
v-model="dialogVisibletwo"
title="支付订单"
width="500"
:before-close="handleClosetwo"
>
<div class="qrcodepup">
<!-- v-model="qrcodeurl" :value="qrcodeurl" -->
<qrcode ref="qrcodecomp" :value="qrcodeurl" v-model="qrcodeurl" ></qrcode>
<div class="qrcodepup_foot">
<svg data-v-5c5419a9="" width="137" height="21" viewBox="0 0 137 21" fill="none" xmlns="http://www.w3.org/2000/svg"><path data-v-5c5419a9="" d="M17.9988 0H2.5712C1.15701 0 0 1.15701 0 2.5712V17.9988C0 19.413 1.15701 20.57 2.5712 20.57H17.9988C19.413 20.57 20.57 19.413 20.57 17.9988V2.5712C20.57 1.15701 19.413 0 17.9988 0ZM10.2851 15.8133C9.38512 15.8133 8.61368 15.6847 7.84232 15.4275C7.32807 15.6847 6.5567 16.3274 6.29954 16.456C5.78526 16.7132 5.91387 16.1989 5.91387 16.1989L6.17103 14.6562C4.62823 13.6276 3.72829 11.9563 3.72829 10.1565C3.72829 6.9424 6.68518 4.37109 10.285 4.37109C12.4706 4.37109 14.5275 5.39962 15.6847 6.81381L9.25654 9.77079C9.25654 9.77079 8.74226 10.0279 8.22801 9.64221L7.19948 8.87084C7.19948 8.87084 6.42812 8.22801 6.81379 9.25654L7.84232 11.5707C7.84232 11.5707 7.9709 12.2134 8.74226 11.8278C9.38512 11.5707 14.1419 8.6137 16.1989 7.45667C16.5846 8.22804 16.8417 9.12796 16.8417 10.0279C16.8417 13.1134 13.8848 15.8133 10.2851 15.8133Z" fill="#09BB07"></path><path data-v-5c5419a9="" d="M34.648 2.88H36.104V3.808H39.944V5.04H36.104V5.824H39.384V7.024H36.104V7.824H40.344V9.088H30.456V7.824H34.648V7.024H31.576V5.824H34.648V5.04H30.904V3.808H34.648V2.88ZM33.032 13.12V14.016H37.784V13.12H33.032ZM37.784 11.968V11.056H33.032V11.968H37.784ZM33.032 15.168V17.648H31.592V9.824H39.24V16.064C39.24 17.056 38.7333 17.552 37.72 17.552H36.392L36.04 16.208L37.288 16.288C37.6187 16.288 37.784 16.112 37.784 15.76V15.168H33.032ZM27.784 3.008C28.84 3.81867 29.7093 4.60267 30.392 5.36L29.352 6.416C28.7013 5.648 27.8213 4.85867 26.712 4.048L27.784 3.008ZM25.608 7.648H29.24V14.336C29.5067 14.08 29.9333 13.648 30.52 13.04L30.92 14.64C30.0027 15.5893 29.016 16.4373 27.96 17.184L27.384 15.808C27.6507 15.5733 27.784 15.2907 27.784 14.96V9.104H25.608V7.648ZM46.472 4.384H50.488V2.88H52.008V4.384H56.312V5.84H52.008V7.104H55.704V11.856H51.944C51.816 13.1893 51.5707 14.224 51.208 14.96C52.7333 15.7387 54.4773 16.176 56.44 16.272L56.072 17.728C53.896 17.5787 51.9867 17.0453 50.344 16.128C49.4907 16.9387 48.1467 17.472 46.312 17.728L45.656 16.352C47.16 16.224 48.2747 15.8613 49 15.264C48.1467 14.624 47.3573 13.8613 46.632 12.976L47.8 12.176C48.4187 12.944 49.1067 13.5947 49.864 14.128C50.1307 13.488 50.312 12.7307 50.408 11.856H46.92V7.104H50.488V5.84H46.472V4.384ZM54.28 10.496V8.448H52.008V10.496H54.28ZM50.488 10.496V8.448H48.344V10.496H50.488ZM43.336 9.264C42.9093 9.808 42.4507 10.3467 41.96 10.88L41.464 9.248C43.032 7.392 44.184 5.22667 44.92 2.752L46.36 3.424C45.9867 4.61867 45.4907 5.78133 44.872 6.912V17.68H43.336V9.264ZM60.616 8.688V11.136H64.296V8.688H60.616ZM60.536 12.544C60.344 14.56 59.752 16.224 58.76 17.536L57.592 16.496C58.552 15.12 59.048 13.376 59.08 11.264V3.424H71.352V15.472C71.352 16.6773 70.7387 17.28 69.512 17.28H67.672L67.272 15.792C67.9653 15.8453 68.5467 15.872 69.016 15.872C69.5387 15.872 69.8 15.5573 69.8 14.928V12.544H65.832V17.104H64.296V12.544H60.536ZM69.8 11.136V8.688H65.832V11.136H69.8ZM69.8 7.296V4.896H65.832V7.296H69.8ZM64.296 4.896H60.616V7.296H64.296V4.896ZM85.144 6.704L84.872 7.808C85.096 9.184 85.3947 10.448 85.768 11.6C86.1627 10.1493 86.3813 8.51733 86.424 6.704H85.144ZM85.176 13.28C84.792 12.224 84.472 11.056 84.216 9.776C83.9707 10.384 83.7147 10.9227 83.448 11.392L82.616 10.336L82.696 10.16H77.72V8.816H82.808V9.904C83.5973 8.08 84.136 5.728 84.424 2.848L85.752 3.072C85.6347 4.032 85.528 4.768 85.432 5.28H88.264V6.704H87.704C87.64 9.33867 87.2453 11.6 86.52 13.488C87.0747 14.6613 87.736 15.584 88.504 16.256L87.64 17.552C86.968 16.88 86.376 16.0053 85.864 14.928C85.2987 15.9733 84.5947 16.8747 83.752 17.632L82.952 16.352C83.8693 15.5733 84.6107 14.5493 85.176 13.28ZM80.616 15.488C80.808 15.3813 80.9253 15.216 80.968 14.992V12.48H79.592V13.2C79.56 15.152 79.064 16.608 78.104 17.568L76.984 16.592C77.7627 15.8133 78.1627 14.6827 78.184 13.2V11.104H82.296V14.432C82.808 13.9627 83.2027 13.584 83.48 13.296L83.784 14.56C82.9627 15.4453 82.1147 16.1707 81.24 16.736L80.616 15.488ZM79.736 2.88H81V6.416H81.784V3.744H83.016V7.696H77.688V3.744H78.936V6.416H79.736V2.88ZM77.32 3.504C76.648 5.22133 75.528 6.768 73.96 8.144L73.496 6.672C74.648 5.57333 75.4907 4.31467 76.024 2.896L77.32 3.504ZM77.384 7.792C77.192 8.32533 76.9413 8.86933 76.632 9.424V17.68H75.208V11.424C74.8667 11.808 74.4667 12.2133 74.008 12.64L73.56 11.184C74.712 10.032 75.56 8.69867 76.104 7.184L77.384 7.792ZM91.288 9.216C90.808 9.84533 90.3653 10.3893 89.96 10.848L89.464 9.216C90.936 7.36 92.0347 5.19467 92.76 2.72L94.184 3.392C93.8 4.61867 93.3307 5.76533 92.776 6.832V17.68H91.288V9.216ZM93.896 4.816H98.584C98.3813 4.272 98.1413 3.744 97.864 3.232L99.32 2.832C99.6613 3.55733 99.9173 4.21867 100.088 4.816H104.408V6.24H93.896V4.816ZM95.352 7.216H103.048V8.576H95.352V7.216ZM95.352 9.472H103.048V10.848H95.352V9.472ZM103.384 11.856V17.648H101.912V16.816H96.472V17.648H95V11.856H103.384ZM96.472 15.392H101.912V13.264H96.472V15.392ZM112.2 2.88H113.768V4.848H119.896V6.32H113.768V8.416H118.024V9.76C117.181 11.4773 115.955 12.9547 114.344 14.192C115.133 14.608 115.917 14.9653 116.696 15.264C117.944 15.712 119.155 16.0693 120.328 16.336L119.448 17.68C118.072 17.3173 116.755 16.8693 115.496 16.336C114.621 15.952 113.805 15.536 113.048 15.088C111.288 16.176 109.149 17.0613 106.632 17.744L105.752 16.384C108.077 15.8613 110.072 15.1307 111.736 14.192C110.936 13.5627 110.237 12.864 109.64 12.096C109.085 11.392 108.685 10.64 108.44 9.84H107.32V8.416H112.2V6.32H106.104V4.848H112.2V2.88ZM113.016 13.392C114.445 12.368 115.539 11.184 116.296 9.84H109.944C110.232 10.5867 110.648 11.248 111.192 11.824C111.747 12.4107 112.355 12.9333 113.016 13.392ZM126.52 3.408C126.179 4.464 125.725 5.51467 125.16 6.56V17.68H123.64V8.912C123.128 9.584 122.568 10.24 121.96 10.88L121.48 9.296C123.123 7.408 124.328 5.22133 125.096 2.736L126.52 3.408ZM126.696 6.224H132.552V2.944H134.072V6.224H136.28V7.696H134.072V15.824C134.072 16.9867 133.512 17.568 132.392 17.568H130.008L129.672 16.08C130.429 16.144 131.16 16.176 131.864 16.176C132.323 16.176 132.552 15.9307 132.552 15.44V7.696H126.696V6.224ZM128.344 9.2C129.539 10.608 130.451 11.8293 131.08 12.864L129.784 13.76C129.112 12.6187 128.216 11.3547 127.096 9.968L128.344 9.2Z" fill="#232323"></path></svg>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<!-- <el-button @click="dialogVisibletwo = false">取消</el-button> -->
<el-button type="primary" @click="cleardialog">
关闭
</el-button>
</div>
</template>
</el-dialog>
<save v-if="dialog.save" ref="saveBox" @success="upsearch" @closed="dialog.save=false" />
<!-- 修改产品 -->
<jfsave v-if="dialog.save1" ref="saveBox1" @success="upsearch1" @closed="dialog.save1=false" />
<!-- 修改积分 -->
</div>
</template>
<script>
import { ElLoading, ElMessage } from "element-plus";
import { ElMessageBox } from 'element-plus'
import qrcode from "@/components/qrcode/qrcode.vue";//二维码
import save from '../goods/lists/save.vue'; //编辑产品
import jfsave from "../member/score/save.vue"; //扣积分
export default {
components: {
qrcode,
save,
jfsave,
},
data() {
return {
logo: 'https://ai-public.mastergo.com/ai/img_res/18f0763466be01b5ffd3e0df086be63d.jpg',
currentTime: '',
keyword: '',
currentCategory: "",//选中的分类id
currentSubCategory: null,
cart: [],
message: { show: false, text: '', type: 'success' },
categories: [
],
products: [
],
//cope code
childgoods:{spec_list:[]},
dialogVisible:false,
scrollbarheight:0,
dialogVisibletwo:false,
dialog: {search: false, import: false, print: false},
selection: [],
search: {},
totalMoney: 0,
totalCount: 0,
loading:null,
scannedCode: '', // 存储扫码后的结果 结果
port:null,
// 原始数据 购物车
odata: [],
listdata: [],
mirror: [],
total: 0,
totaljifen:0,//总共所需积分
Userprice:0,//不使用积分的价格
qrcodeurl:"",
listeningtype:1,//1 扫产品 2扫会员码 状态
page:0,
// 已有代码...
isLoading: false,
hasMore: true
};
},
computed: {
//计算二级分类列表内容
currentCategoryData() {
// return this.categories.find(c => c.id === this.currentCategory);
let list = [];
for (let i = 0; i < this.categories.length; i++) {
let itemss = this.categories[i];
if (itemss.id == this.currentCategory) {
// list.push(itemss);
list = itemss;
}
}
return list;
},
totalItems() {
return this.cart.reduce((sum, item) => sum + item.quantity, 0);
},
totalAmount() {
return this.cart.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
},
methods: {
gtehomepage(){
console.log('gtehomepage')
this.$router.push({
path: '/cashierhome/cashierhome'
})
},
//瀑布流
handleScroll(e) {
const listEl = this.$refs.productList
// 计算是否滚动到底部(距离底部50px时触发)
if (listEl.scrollHeight - listEl.scrollTop - listEl.clientHeight < 50) {
this.loadMore()
}
},
//瀑布流
async loadMore() {
if (this.isLoading || !this.hasMore) return
this.isLoading = true
try {
await this.getProducts()
} finally {
this.isLoading = false
}
},
//获取产品列表
getProducts() {
this.page++;
let params = { page: this.page, limit: 30 };
//一级分类id
if(this.currentCategory){
params.category_id = this.currentCategory
}
//二级分类id
if(this.currentSubCategory){
params.category_id = this.currentSubCategory
}
//关键词搜索
if(this.keyword){
params.keyword = this.keyword
}
this.$API.goods.lists.list.get(params).then(res=>{
if (res.code == 1) {
// this.products = res.data.data;
this.products = [...this.products, ...res.data.data];
this.hasMore = res.data.data.length >= params.limit;
}else{
}
}).catch((err) => {
console.log("🚀 ~ getProducts ~ err:", err);
});
},
//获取分类列表
getCatetList(){
this.$API.goods.category.list.get({
is_tree: 1
}).then(res=>{
console.log("🚀 ~ getCatetList ~ res:", res);
if (res.code == 1) {
this.categories = res.data;
}else{
}
}).catch((err) => {
console.log("🚀 ~ getCatetList ~ err:", err);
});
},
updateTime() {
// this.currentTime = new Date().toLocaleTimeString('zh-CN');
let now = new Date();
let options = { year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit',
hour12: false };
// console.log();
this.currentTime = now.toLocaleString('zh-CN', options)
},
//搜索事件
tosearchfun(){
this.page = 0;
this.products = [];
this.getProducts();
},
//一级分类点击
selectCategory(categoryId) {
this.currentCategory = categoryId;
this.currentSubCategory = null;
this.page = 0;
this.products = [];
this.getProducts();
},
//二级分类点击
selectSubCategory(subCategoryId) {
this.currentSubCategory = subCategoryId;
this.page = 0;
this.products = [];
this.getProducts();
},
showMessage(text, type) {
this.message = { show: true, text, type };
setTimeout(() => {
this.message.show = false;
}, 2000);
},
//---cope------------------------------------------------------------------
add(){
this.dialog.save = true
this.$nextTick(() => {
this.$refs.saveBox.open().setData({})
})
},
table_edit(row){
this.dialog.save = true
this.$nextTick(() => {
this.$refs.saveBox.open('edit').setData(row)
})
},
//---规格加入购物车-------------------------------------------------------------------------
//规格提交
addCartHandle() {
this.dialogVisible = false;
let skuId = this.childgoods.skuId;
let number = this.childgoods.popNumber;
// this.$emit("popAddCart", skuId, number);
this.addCart("multiple", skuId, number);
},
//提交加入购物车
addCart(type, skuId, number) {
let that = this;
let req = {};
if (type === "single") {//没有规格
req = {
goods_sn:that.childgoods.goods_sn,//商品编号
goods_id: that.childgoods.id,
goods_sku_id: 0,
num: 1,
store_id: that.childgoods.store_id,
};
} else {//有规格
req = {
goods_sn:that.childgoods.popSkuGoods_sn,//商品编号
goods_id: that.childgoods.id,
goods_sku_id: skuId,
num: number,
store_id: that.childgoods.store_id,
};
}
console.info('req',req);
this.$API.cashier.cart.add.post(req).then(res=>{
if (res.code == 1) {
this.$message({
message: "添加成功~",
type: "success"
});
this.getCartList();//获取购物清单
this.scannedCode = "";
this.childgoods={spec_list:[]};
}else{
this.scannedCode = "";
this.childgoods={spec_list:[]};
this.$message.error(res.message);
}
}).catch((err) => {
this.scannedCode = "";
this.childgoods={spec_list:[]};
console.log("🚀 ~ cart ~ err:", err);
});
},
//购物车产品数量加减
stepMinusHandle(type,cc) {
let num = cc.num
if(type=="add"){
num = num+1;
}else{
if(num>1){
num = num-1;
}else{
num = 0;
//不能再减了
// this.$message.error('不能再减了');
// return;
}
}
console.info('stepMinusHandle',num,cc);
let that = this;
let goods_id = cc.goods_id;
let goods_sku_id = cc.goods_sku_id;
let cart_id = cc.cart_id;
let obj = that.odata.find((v) => v.id == cart_id);
console.log("🚀 ~ stepMinusHandle ~ obj:", obj);
// let num = obj.num - 1;
if (num != 0) {
let req = {
id: cart_id,
goods_id: goods_id,
goods_sku_id: goods_sku_id,
num: num,
};
this.$API.cashier.cart.edit.post(req)
.then((res) => {
console.log("🚀 ~ editCart ~ res:", res);
if (res.code == 1) {
that.getCartList();
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ editCart ~ err:", err);
});
} else {
//删除
let req = {
id: cart_id,
};
this.$API.cashier.cart.delete.post(req)
.then((res) => {
console.log("🚀 ~ delCart ~ res:", res);
if (res.code == 1) {
that.getCartList();
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ delCart ~ err:", err);
});
}
},
//数量加减
numberChangeHandle(e) {
console.log(e.detail);
console.log(this.childgoods.popStock.match(/\d+/)[0]);
if (Number(e.detail) > Number(this.childgoods.popStock.match(/\d+/)[0])) {
this.$message.error("库存不足~");
} else {
this.childgoods.popNumber = e.detail;
}
},
//规格被选择
skuTapHandle(item, outer, cc) {
this.childgoods.spec_list[outer]["selected"] = cc;
this.changeSku();
},
//修改规格
changeSku() {
let arr = this.childgoods.spec_list;
if (arr.every((item) => item.selected)) {
console.log("所有规格已选择");
// 取出item的name和selected,组成{name:selected}格式
let sku = arr.reduce((acc, cur) => {
acc[cur.name] = cur.selected;
return acc;
}, {});
let skuObj = this.childgoods.sku.find(
(item) => JSON.stringify(item.sku_value) === JSON.stringify(sku)
);
console.log("🚀 ~ changeSku ~ skuObj:", skuObj);
let parts = skuObj.price.split(".");
this.childgoods.popFormatBig = parts[0];
this.childgoods.popFormatMini = parts[1] ? "." + parts[1] : ".00";
this.childgoods.popStock = "库存 " + skuObj.stock;
this.childgoods.popNumber = 1;
this.childgoods.popSkuGoods_sn = skuObj.goods_sn;
this.childgoods["skuId"] = skuObj.id;
} else {
console.log("还有规格未选择");
}
},
//删除产品
goodsDeleteHandle(gid, sid) {
let that = this;
let cid = that.odata
.filter((v) => v.goods_id == gid && v.goods_sku_id == sid)
.map((v) => v.id);
let req = {
ids: cid,
};
this.$API.cashier.cart.delete.post(req)
.then((res) => {
console.log("🚀 ~ delCart ~ res:", res);
if (res.code == 1) {
that.getCartList();
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ delCart ~ err:", err);
});
},
//获取购物车列表
getCartList(){
let that = this;
this.$API.cashier.cart.list.get({page:1,limit:100}).then((res) => {
console.log("🚀 ~ getCartList ~ res:", res);
if (res.code == 1) {
let data = res.data;
that.odata = data;
const groupedData = data.reduce((acc, item) => {
const storeId = item.store_id;
if (!acc[storeId]) {
acc[storeId] = {
id: storeId,
title: item.store.title,
cover: item.store.cover,
content: [],
selected: 0,
};
}
acc[storeId].content.push({
cart_id: item.id,
member_id: item.member_id,
goods_id: item.goods_id,
goods_sku_id: item.goods_sku_id,
num: item.num,
created_at: item.created_at,
updated_at: item.updated_at,
goods: item.goods,
sku: item.sku,
});
return acc;
}, {});
const result = Object.values(groupedData);
result.forEach((store) => {
store.content.forEach((item) => {
if (item.sku && item.sku.price) {
const priceParts = item.sku.price.split(".");
const formatBig = priceParts[0];
const formatMini =
priceParts.length > 1 ? `.${priceParts[1]}` : ".00";
item.formatBig = formatBig;
item.formatMini = formatMini;
item.readyPrice = item.sku.price;
item.selected = 0;
item.ready_integral = item.sku.integral;//积分
} else {
const priceParts = item.goods.price.split(".");
const formatBig = priceParts[0];
const formatMini =
priceParts.length > 1 ? `.${priceParts[1]}` : ".00";
item.formatBig = formatBig;
item.formatMini = formatMini;
item.readyPrice = item.goods.price;
item.selected = 0;
item.ready_integral = item.goods.integral;////积分
}
});
const mergedData = Object.values(
that.mergeObjects(store.content)
);
console.log("🚀 ~ result.forEach ~ mergedData:", mergedData);
store.content = mergedData;
});
console.log("🚀 ~ result.forEach ~ result:", result);
that.listdata = result;
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ getCartList ~ err:", err);
});
},
// 合并购物车相同规格的商品
mergeObjects(arr) {
return arr.reduce((acc, curr) => {
const key = curr.sku ?
`${curr.goods.id}-${curr.sku.id}` :
`${curr.goods.id}`;
if (acc[key]) {
acc[key].num += curr.num;
} else {
acc[key] = {
...curr,
goods: {
...curr.goods
},
sku: curr.sku ? {
...curr.sku
} : null,
};
delete acc[key].id;
}
return acc;
}, {});
},
//关闭 支付订单 弹窗
cleardialog(){
this.dialogVisibletwo = false;
this.getCartList();
},
//关闭 支付订单 弹窗
handleClosetwo(done) {
ElMessageBox.confirm('确定要关闭弹窗吗?')
.then(() => {
done()
this.getCartList();
})
.catch(() => {
// catch error
})
},
//---规格加入购物车-------------------------------------------------------------------------
//关闭 选择规格 弹窗
handleClose(done) {
ElMessageBox.confirm('确定要关闭弹窗吗?')
.then(() => {
done()
})
.catch(() => {
// catch error
})
},
//监听扫码枪识别 和 会员扣积分
focusfun(types){
// 自动聚焦到输入框,方便直接扫描
if(types==2 && this.totaljifen==0){
this.$message.error("店员,没有可抵积分的东西,怎么扣积分呀~");
return false;
}
this.listeningtype = types;
// this.loading = ElLoading.service({
// lock: true,
// text: "请开始扫码识别",
// background: "rgba(255, 255, 255, 0.7)",
// });
},
// 扫码识别
handleScan(event){
console.info('handleScan',event);
console.log('扫描结果:', event.detail);
// this.$emit('scan', event.detail);
this.scannedCode = event.detail;
if(this.listeningtype==1){
//扫产品
if(this.scannedCode && this.scannedCode.length>5){
this.childgoods.goods_sn = this.scannedCode;
this.childgoods.store_id = 0;
this.addCart("single", "", 1);
}
}else if(this.listeningtype==2){
//扫会员码
console.info("this.scannedCode 扫会员码",this.scannedCode);
var idPattern = /^\d+$/;
if(this.scannedCode && idPattern.test(this.scannedCode) && this.scannedCode.length<8){
this.addjf(this.scannedCode);
}
}
},
//会员扣积分 事件
addjf(user_id){
console.info("addjf");
this.dialog.save1 = true
this.$nextTick(() => {
this.$refs.saveBox1.open().setData({
amount:this.totaljifen,//积分额度
member_id:user_id,//用户
type:'pay',//积分类型
remark:"到店消费",//积分描述
})
})
},
// 添加和计算商品价格 添加数量
addOrderList(goods,index) {
// 商品是否已经存在于订单列表中
if(goods.sku.length){
//规格
this.dialogVisible = true;
this.childgoods = goods;
return false;
}else{
//非规格
this.childgoods = goods;
this.addCart("single", 0, 1);
return false;
}
},
// 全部删除商品 清空购物车
delAllGoods() {
// this.odata = [];
this.listdata = [];
this.totalMoney = 0;
this.totalCount = 0;
this.totaljifen = 0;
this.childgoods = {spec_list:[]};
let req = {
ids: this.odata.map(product => product.id),
};
this.$API.cashier.cart.delete.post(req)
.then((res) => {
console.log("🚀 ~ delCart ~ res:", res);
if (res.code == 1) {
that.getCartList();
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ delCart ~ err:", err);
});
},
// 模拟结账 用户结算
checkoutfun() {
console.info("模拟结账 用户结算");
// this.$message.error("程序猿小哥正在开发中~");
if(this.odata.length){
this.$API.cashier.cart.simple.post({
carts:this.odata.map(item=>{return item.id}),
})
.then((res) => {
console.log("🚀 ~ simple ~ res:", res);
if(res.code==1){
this.$API.cashier.cart.nativepc.post({order_id:res.data.id}).then(restwo=>{
console.log("🚀 ~ simple ~ restwo:", restwo);
if(restwo.code==1){
let packagestr = restwo.data.package;
let match = packagestr.match(/prepay_id=([^&]+)/);
if (match) {
let qrcodeurl = match[1];
console.log(qrcodeurl); // 输出: weixin://wxpay/bizpayurl?pr=g5bMCytz3
this.qrcodeurl = qrcodeurl;
this.dialogVisibletwo = true;
this.$nextTick(()=>{
setTimeout(()=>{
this.$refs.qrcodecomp.updateQRCode(this.qrcodeurl);
},100)
})
}
}else{
this.$message.error(restwo.message);
}
})
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ simple ~ err:", err);
});
}else{
this.$message.error("店员,没有东西,怎么结账呀~");
}
},
upsearch(){
this.$refs.table.reload(this.search);
},
upsearch1(){
},
moreUpsearch(search){
this.search = search;
this.upsearch();
},
moreSearch(){
this.dialog.search = true
this.$nextTick(() => {
this.$refs.searchBox.open().setData(this.search)
})
},
//表格选择后回调事件
selectionChange(selection){
this.selection = selection;
},
//---------------------------------------------------------------------
},
mounted() {
this.updateTime();
setInterval(this.updateTime, 1000);
var orderHeight = document.body.clientHeight;
// document.getElementById("order_list").style.height = (orderHeight - 100) + "px";
this.scrollbarheight = orderHeight - 330;
//扫码枪监听事件
this.$barcodeScanner.init({
endChar: 'Enter',
minLength: 4
});
document.addEventListener('barcodeScanned', this.handleScan);
},
beforeUnmount() {
this.$barcodeScanner.destroy();
document.removeEventListener('barcodeScanned', this.handleScan);
// 如果使用被动监听则不需要手动移除
const listEl = this.$refs.productList
listEl?.removeEventListener('scroll', this.handleScroll)
},
created: function() {
this.getCartList();//获取购物清单
//获取产品列表
this.getProducts();
//获取分类列表
this.getCatetList();
},
watch:{
//计算价格
listdata:{
handler(newValue) {
let total = 0;
let totalCount = 0;
let totaljifen = 0;
newValue.forEach((item) => {
item.content.forEach((cc) => {
total += parseFloat(cc.readyPrice) * Number(cc.num);
totalCount = totalCount + cc.num;
totaljifen += parseFloat(cc.ready_integral) * Number(cc.num)
});
});
total = total.toFixed(2);
totaljifen = totaljifen.toFixed(2);
const priceParts = total.split(".");
const formatBig = priceParts[0];
const formatMini = priceParts.length > 1 ? `.${priceParts[1]}` : ".00";
this.totalMoney = total;
this.totalCount = totalCount;
this.totaljifen = totaljifen;//积分
this.Userprice = parseFloat(parseFloat(total) - parseFloat(this.totaljifen)).toFixed(2);
},
deep: true,
}
},
};
</script>
<style scoped lang="scss">
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
.message {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
padding: 10px 20px;
border-radius: 4px;
z-index: 9999;
color: white;
}
.message.success {
background-color: #67C23A;
}
.message.warning {
background-color: #E6A23C;
}
@import url('./cashier.scss');
</style>
\ No newline at end of file
.input {
position: fixed;
left: 0;
transform: translateX(-200%);
}
.pos_order {
background-color: #f9fafc;
border-right: 1px solid #c0ccda;
}
.pos_btn {
margin-top: 20px;
}
.often_title {
border-bottom: 1px solid #d3dce6;
background-color: #f9fafc;
padding: 10px;
text-align: left;
cursor: pointer;
}
.often_goodsList ul li {
list-style: none;
float: left;
border: 1px solid #d3dce6;
padding: 10px;
margin: 10px;
background-color: #ffffff;
cursor: pointer;
}
.often_price {
color: #63b8ff;
}
.goodsType {
clear: both;
height: auto;
overflow: hidden;
border-top: 1px solid #d3dce6;
}
.cookList li {
list-style: none;
width: 23%;
border: 1px solid #e5e9f2;
height: auot;
overflow: hidden;
background-color: #fff;
padding: 2px;
float: left;
margin: 2px;
cursor: pointer;
}
.cookList_div{
width: 60%;
display: inline-block;
float: left;
}
.cookList li span {
display: block;
float: left;
}
.foodImg {
width: 40%;
height: 120px;
}
.foodImg img{
/* width: 100%; */
width: 100%;
height: auto;
}
.foodName {
font-size: 16px;
padding-left: 10px;
color: brown;
}
.foodPrice {
font-size: 16px;
padding-left: 10px;
padding-top: 10px;
color: #F64F15;
}
.total {
background: #ffffff;
padding: 10px;
border-bottom: 1px solid #d3dce6;
color: red;
font-size: 18px;
}
.total small {
padding: 0 10px;
text-align: center;
}
.sku_card {
.sku_card_title {
font-size: 15px;
line-height: 40px;
color: #222;
font-weight: bold;
}
.sku_card_main {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
.sku_card_item {
font-size: 12px;
line-height: 24px;
background-color: #f1f2f2;
color: #373737;
margin-right: 10px;
margin-bottom: 10px;
padding: 0 10px;
flex-shrink: 0;
border-radius: 3px;
cursor: pointer;
}
.sku_card_item_active {
background-color: #409eff !important;
color: #fff !important;
}
}
}
.card {
margin: 18px auto 0;
background-color: #fff;
.top {
display: flex;
justify-content: flex-start;
align-items: center;
height: 50px;
font-size: 16px;
line-height: 1;
.shop_name {
margin-left: 5px;
font-size: 15px;
font-weight: normal;
font-stretch: normal;
color: #222222;
}
}
.select_box {
width: 40px;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
font-size: 16px;
.circle {
color: #666;
}
.checked {
color: #f64f15;
}
}
.main {
padding-bottom: 23px;
.card_wrap {
margin-top: 15px;
&:first-child {
margin-top: 0;
}
}
.card_item {
width: 100%;
box-sizing: border-box;
}
.card_item_wrap {
display: flex;
justify-content: flex-start;
align-items: center;
}
.img_wrap {
width: 70px;
height: 70px;
border-radius: 10px;
overflow: hidden;
flex-shrink: 0;
img {
display: block;
width: 70px;
height:70px;
}
}
.info {
margin-left: 20px;
padding-right: 20px;
width: calc(100% - 40px - 100px - 15px);
// height: 70px;
display: flex;
flex-direction: column;
justify-content: space-between;
.it {
.goods_title {
display: block;
width: 100%;
font-size: 12px;
font-weight: bold;
font-stretch: normal;
color: #222222;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.deleteicon{
margin: 6px 0;
display: flex;
justify-content: flex-end;
}
.delete{
cursor: pointer;
color: red;
}
.sku {
height: 26px;
border-radius: 5px;
margin-top: 11px;
font-size: 12px;
line-height: 26px;
font-stretch: normal;
color: #838383;
display: flex;
justify-content: flex-start;
align-items: center;
.text {
padding: 0 10px;
background-color: #f6f6f6;
}
.sku_arr {
display: block;
padding-left: 10px;
padding-right: 10px;
background-color: #f6f6f6;
}
}
}
.ib {
display: flex;
justify-content: space-between;
.pricebox{
display: flex;
align-items: center;
}
.jfprice{
margin-left: 8px;
.price_icon,.price_main{
font-size: 12px !important;
color: #a5a5a5 !important;
}
}
.price {
display: flex;
justify-content: flex-start;
align-items: baseline;
.price_icon {
font-size: 13px;
font-weight: bold;
font-stretch: normal;
color: #f64f15;
}
.price_main {
font-size: 16px;
font-weight: bold;
font-stretch: normal;
color: #f64f15;
.mini {
font-size: 15px;
}
}
.ori {
font-size: 12px;
font-stretch: normal;
color: #8a8a8a;
}
}
.num {
flex-shrink: 0;
--stepper-input-disabled-text-color: #323233;
}
}
}
}
}
.qrcodepup{
text-align: center;
}
<template>
<el-container>
<el-main class="nopadding">
<!-- -->
<div class="pos">
<el-row>
<el-col :span='9' class="pos_order" id="order_list">
<el-tabs style="padding-left:10px;">
<el-tab-pane label="购物单">
<el-scrollbar :height="scrollbarheight">
<div class="card" v-for="(item, index) in listdata" :key="index">
<div class="top">
<div class="shop_name">{{ item.title }}</div>
</div>
<div class="main">
<div class="card_wrap" v-for="(cc, inner) in item.content" :key="inner">
<div class="card_item" right-width="65">
<div class="card_item_wrap">
<div class="select_box" @click="goodsSelectedHandle(cc.goods_id, cc.goods_sku_id)">
</div>
<div class="img_wrap">
<img :src="cc.goods.cover" mode="aspectFill" />
</div>
<div class="info">
<div class="it">
<div class="goods_title">
{{ cc.goods.title }}
</div>
<div class="deleteicon">
<div class="delete" @click="goodsDeleteHandle(cc.goods_id, cc.goods_sku_id)">删除</div>
</div>
<!-- @click="skuChangeHandle(cc)" -->
<div class="sku" v-if="cc.sku" >
<div class="text">{{ cc.sku.sku }}</div>
</div>
</div>
<div class="ib">
<!-- 会员 -->
<div class="pricebox">
<div class="price">
<div class="price_icon"> ¥</div>
<div class="price_main din">
{{ cc.formatBig }}
<text class="mini">{{ cc.formatMini }}</text>
</div>
</div>
</div>
<div class="num">
<el-input-number :data-gid="cc.goods_id" :data-sid="cc.goods_sku_id"
:data-cid="cc.cart_id" :min="1" @change="(e)=>stepMinusHandle(e, cc)" size="small" v-model="cc.num"></el-input-number>
</div>
</div>
<div class="ib">
<!-- 会员 -->
<div class="pricebox">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</el-scrollbar>
<div class="total">
<small>数量:</small>{{ totalCount }}
</div>
<div class="total">
<small>需付:</small>{{totalMoney }}
</div>
<div class="pos_btn">
<!-- <el-button size="large" type="primary" @click="focusfun(1)" >监听扫码枪识别</el-button> -->
<el-button size="large" type="danger" @click="delAllGoods()">清空购物单</el-button>
<!-- <el-button size="large" type="success" @click="focusfun(2)">会员扣积分</el-button> -->
<el-button size="large" type="success" @click="checkOut()">用户结算</el-button>
<!-- addjf 会员扣积分 -->
</div>
</el-tab-pane>
</el-tabs>
</el-col>
<el-col :span="15">
<el-header>
<div class="left-panel">
<el-input v-model="search.keyword" placeholder="关键词" style="width:150px; margin-right: 10px;" clearable />
<sc-select-tree v-model="search.category_id" :apiObj="$API.goods.category.list" :props="{label: 'title', value: 'id'}" style="width: 240px; margin-right: 10px;" />
<el-select v-model="search.status" placeholder="状态" clearable style="width: 100px;">
<el-option v-for="item in [{value: 0, title: '下架'}, {value: 1, title: '上架'}]" :key="item.value" :label="item.title" :value="item.value" />
</el-select>
<el-button-group style="margin-left: 10px;">
<el-button type="primary" icon="el-icon-search" @click="upsearch">搜索</el-button>
<el-button type="danger" icon="el-icon-plus" @click="add">添加产品</el-button>
</el-button-group>
</div>
</el-header>
<scTable tableName="member" ref="table" :pageSize="11" :apiObj="list.apiObj" :column="list.column" row-key="id" @selection-change="selectionChange" border stripe>
<el-table-column type="selection" width="50"></el-table-column>
<template #cover="scope">
<img :src="scope.row.cover" width="40" height="40" v-if="scope.row.cover" />
</template>
<template #status="scope">
<el-tag :type="scope.row.status == 1 ? 'success' : 'danger'">{{scope.row.status == 1 ? '上架' : '下架'}}</el-tag>
</template>
<el-table-column label="操作" fixed="right" align="center" width="140">
<template #default="scope">
<el-button-group>
<el-button type="primary" @click="addOrderList(scope.row, scope.$index)">加购</el-button>
<el-button type="primary" @click="table_edit(scope.row, scope.$index)">编辑</el-button>
</el-button-group>
</template>
</el-table-column>
</scTable>
</el-col>
</el-row>
</div>
<!-- 弹窗选择规格 -->
<el-dialog
v-model="dialogVisible"
title="选择规格"
width="500"
:before-close="handleClose"
>
<div>
<div class="sku_card" v-for="(item, outer) in childgoods.spec_list" :key="outer">
<div class="sku_card_title">{{ item.name }}</div>
<div class="sku_card_main">
<div :class="{
sku_card_item: true,
sku_card_item_active: item.value[inner] === item.selected,
}" v-for="(cc, inner) in item.value" :key="inner" @click="skuTapHandle(item, outer, cc)">
{{ cc }}
</div>
</div>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="addCartHandle()">
确定
</el-button>
</div>
</template>
</el-dialog>
<el-dialog
v-model="dialogVisibletwo"
title="支付订单"
width="500"
:before-close="handleClosetwo"
>
<div class="qrcodepup">
<!-- v-model="qrcodeurl" :value="qrcodeurl" -->
<qrcode ref="qrcodecomp" :value="qrcodeurl" v-model="qrcodeurl" ></qrcode>
<div class="qrcodepup_foot">
<svg data-v-5c5419a9="" width="137" height="21" viewBox="0 0 137 21" fill="none" xmlns="http://www.w3.org/2000/svg"><path data-v-5c5419a9="" d="M17.9988 0H2.5712C1.15701 0 0 1.15701 0 2.5712V17.9988C0 19.413 1.15701 20.57 2.5712 20.57H17.9988C19.413 20.57 20.57 19.413 20.57 17.9988V2.5712C20.57 1.15701 19.413 0 17.9988 0ZM10.2851 15.8133C9.38512 15.8133 8.61368 15.6847 7.84232 15.4275C7.32807 15.6847 6.5567 16.3274 6.29954 16.456C5.78526 16.7132 5.91387 16.1989 5.91387 16.1989L6.17103 14.6562C4.62823 13.6276 3.72829 11.9563 3.72829 10.1565C3.72829 6.9424 6.68518 4.37109 10.285 4.37109C12.4706 4.37109 14.5275 5.39962 15.6847 6.81381L9.25654 9.77079C9.25654 9.77079 8.74226 10.0279 8.22801 9.64221L7.19948 8.87084C7.19948 8.87084 6.42812 8.22801 6.81379 9.25654L7.84232 11.5707C7.84232 11.5707 7.9709 12.2134 8.74226 11.8278C9.38512 11.5707 14.1419 8.6137 16.1989 7.45667C16.5846 8.22804 16.8417 9.12796 16.8417 10.0279C16.8417 13.1134 13.8848 15.8133 10.2851 15.8133Z" fill="#09BB07"></path><path data-v-5c5419a9="" d="M34.648 2.88H36.104V3.808H39.944V5.04H36.104V5.824H39.384V7.024H36.104V7.824H40.344V9.088H30.456V7.824H34.648V7.024H31.576V5.824H34.648V5.04H30.904V3.808H34.648V2.88ZM33.032 13.12V14.016H37.784V13.12H33.032ZM37.784 11.968V11.056H33.032V11.968H37.784ZM33.032 15.168V17.648H31.592V9.824H39.24V16.064C39.24 17.056 38.7333 17.552 37.72 17.552H36.392L36.04 16.208L37.288 16.288C37.6187 16.288 37.784 16.112 37.784 15.76V15.168H33.032ZM27.784 3.008C28.84 3.81867 29.7093 4.60267 30.392 5.36L29.352 6.416C28.7013 5.648 27.8213 4.85867 26.712 4.048L27.784 3.008ZM25.608 7.648H29.24V14.336C29.5067 14.08 29.9333 13.648 30.52 13.04L30.92 14.64C30.0027 15.5893 29.016 16.4373 27.96 17.184L27.384 15.808C27.6507 15.5733 27.784 15.2907 27.784 14.96V9.104H25.608V7.648ZM46.472 4.384H50.488V2.88H52.008V4.384H56.312V5.84H52.008V7.104H55.704V11.856H51.944C51.816 13.1893 51.5707 14.224 51.208 14.96C52.7333 15.7387 54.4773 16.176 56.44 16.272L56.072 17.728C53.896 17.5787 51.9867 17.0453 50.344 16.128C49.4907 16.9387 48.1467 17.472 46.312 17.728L45.656 16.352C47.16 16.224 48.2747 15.8613 49 15.264C48.1467 14.624 47.3573 13.8613 46.632 12.976L47.8 12.176C48.4187 12.944 49.1067 13.5947 49.864 14.128C50.1307 13.488 50.312 12.7307 50.408 11.856H46.92V7.104H50.488V5.84H46.472V4.384ZM54.28 10.496V8.448H52.008V10.496H54.28ZM50.488 10.496V8.448H48.344V10.496H50.488ZM43.336 9.264C42.9093 9.808 42.4507 10.3467 41.96 10.88L41.464 9.248C43.032 7.392 44.184 5.22667 44.92 2.752L46.36 3.424C45.9867 4.61867 45.4907 5.78133 44.872 6.912V17.68H43.336V9.264ZM60.616 8.688V11.136H64.296V8.688H60.616ZM60.536 12.544C60.344 14.56 59.752 16.224 58.76 17.536L57.592 16.496C58.552 15.12 59.048 13.376 59.08 11.264V3.424H71.352V15.472C71.352 16.6773 70.7387 17.28 69.512 17.28H67.672L67.272 15.792C67.9653 15.8453 68.5467 15.872 69.016 15.872C69.5387 15.872 69.8 15.5573 69.8 14.928V12.544H65.832V17.104H64.296V12.544H60.536ZM69.8 11.136V8.688H65.832V11.136H69.8ZM69.8 7.296V4.896H65.832V7.296H69.8ZM64.296 4.896H60.616V7.296H64.296V4.896ZM85.144 6.704L84.872 7.808C85.096 9.184 85.3947 10.448 85.768 11.6C86.1627 10.1493 86.3813 8.51733 86.424 6.704H85.144ZM85.176 13.28C84.792 12.224 84.472 11.056 84.216 9.776C83.9707 10.384 83.7147 10.9227 83.448 11.392L82.616 10.336L82.696 10.16H77.72V8.816H82.808V9.904C83.5973 8.08 84.136 5.728 84.424 2.848L85.752 3.072C85.6347 4.032 85.528 4.768 85.432 5.28H88.264V6.704H87.704C87.64 9.33867 87.2453 11.6 86.52 13.488C87.0747 14.6613 87.736 15.584 88.504 16.256L87.64 17.552C86.968 16.88 86.376 16.0053 85.864 14.928C85.2987 15.9733 84.5947 16.8747 83.752 17.632L82.952 16.352C83.8693 15.5733 84.6107 14.5493 85.176 13.28ZM80.616 15.488C80.808 15.3813 80.9253 15.216 80.968 14.992V12.48H79.592V13.2C79.56 15.152 79.064 16.608 78.104 17.568L76.984 16.592C77.7627 15.8133 78.1627 14.6827 78.184 13.2V11.104H82.296V14.432C82.808 13.9627 83.2027 13.584 83.48 13.296L83.784 14.56C82.9627 15.4453 82.1147 16.1707 81.24 16.736L80.616 15.488ZM79.736 2.88H81V6.416H81.784V3.744H83.016V7.696H77.688V3.744H78.936V6.416H79.736V2.88ZM77.32 3.504C76.648 5.22133 75.528 6.768 73.96 8.144L73.496 6.672C74.648 5.57333 75.4907 4.31467 76.024 2.896L77.32 3.504ZM77.384 7.792C77.192 8.32533 76.9413 8.86933 76.632 9.424V17.68H75.208V11.424C74.8667 11.808 74.4667 12.2133 74.008 12.64L73.56 11.184C74.712 10.032 75.56 8.69867 76.104 7.184L77.384 7.792ZM91.288 9.216C90.808 9.84533 90.3653 10.3893 89.96 10.848L89.464 9.216C90.936 7.36 92.0347 5.19467 92.76 2.72L94.184 3.392C93.8 4.61867 93.3307 5.76533 92.776 6.832V17.68H91.288V9.216ZM93.896 4.816H98.584C98.3813 4.272 98.1413 3.744 97.864 3.232L99.32 2.832C99.6613 3.55733 99.9173 4.21867 100.088 4.816H104.408V6.24H93.896V4.816ZM95.352 7.216H103.048V8.576H95.352V7.216ZM95.352 9.472H103.048V10.848H95.352V9.472ZM103.384 11.856V17.648H101.912V16.816H96.472V17.648H95V11.856H103.384ZM96.472 15.392H101.912V13.264H96.472V15.392ZM112.2 2.88H113.768V4.848H119.896V6.32H113.768V8.416H118.024V9.76C117.181 11.4773 115.955 12.9547 114.344 14.192C115.133 14.608 115.917 14.9653 116.696 15.264C117.944 15.712 119.155 16.0693 120.328 16.336L119.448 17.68C118.072 17.3173 116.755 16.8693 115.496 16.336C114.621 15.952 113.805 15.536 113.048 15.088C111.288 16.176 109.149 17.0613 106.632 17.744L105.752 16.384C108.077 15.8613 110.072 15.1307 111.736 14.192C110.936 13.5627 110.237 12.864 109.64 12.096C109.085 11.392 108.685 10.64 108.44 9.84H107.32V8.416H112.2V6.32H106.104V4.848H112.2V2.88ZM113.016 13.392C114.445 12.368 115.539 11.184 116.296 9.84H109.944C110.232 10.5867 110.648 11.248 111.192 11.824C111.747 12.4107 112.355 12.9333 113.016 13.392ZM126.52 3.408C126.179 4.464 125.725 5.51467 125.16 6.56V17.68H123.64V8.912C123.128 9.584 122.568 10.24 121.96 10.88L121.48 9.296C123.123 7.408 124.328 5.22133 125.096 2.736L126.52 3.408ZM126.696 6.224H132.552V2.944H134.072V6.224H136.28V7.696H134.072V15.824C134.072 16.9867 133.512 17.568 132.392 17.568H130.008L129.672 16.08C130.429 16.144 131.16 16.176 131.864 16.176C132.323 16.176 132.552 15.9307 132.552 15.44V7.696H126.696V6.224ZM128.344 9.2C129.539 10.608 130.451 11.8293 131.08 12.864L129.784 13.76C129.112 12.6187 128.216 11.3547 127.096 9.968L128.344 9.2Z" fill="#232323"></path></svg>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<!-- <el-button @click="dialogVisibletwo = false">取消</el-button> -->
<el-button type="primary" @click="cleardialog">
关闭
</el-button>
</div>
</template>
</el-dialog>
<save v-if="dialog.save" ref="saveBox" @success="upsearch" @closed="dialog.save=false" />
<!-- 修改产品 -->
<jfsave v-if="dialog.save1" ref="saveBox1" @success="upsearch1" @closed="dialog.save1=false" />
<!-- 修改积分 -->
</el-main>
</el-container>
</template>
<script >
import { ElLoading, ElMessage } from "element-plus";
import { ElMessageBox } from 'element-plus'
import qrcode from "@/components/qrcode/qrcode.vue";//二维码
import save from '../goods/lists/save.vue'; //编辑产品
import jfsave from "../member/score/save.vue"; //扣积分
export default {
name: "ucenter.cashierhome",
components: {
qrcode,
save,
jfsave,
},
data() {
return {
childgoods:{spec_list:[]},
dialogVisible:false,
scrollbarheight:0,
dialogVisibletwo:false,
dialog: {search: false, import: false, print: false},
list: {
apiObj: this.$API.goods.lists.list,
column: [
{prop: 'id', label: 'ID', width: 80},
{prop: 'goods_sn', label: '商品编号'},
{prop: 'title', label: '商品名称'},
{prop: 'cover', label: '封面图', width: 120},
{prop: 'price', label: '售价', width: 120},
{prop: 'original_price', label: '原价', width: 120},
// {prop: 'status', label: '状态', width: 80},
],
},
selection: [],
search: {},
totalMoney: 0,
totalCount: 0,
loading:null,
scannedCode: '', // 存储扫码后的结果 结果
port:null,
// 原始数据 购物车
odata: [],
listdata: [],
mirror: [],
total: 0,
totaljifen:0,//总共所需积分
Userprice:0,//不使用积分的价格
qrcodeurl:"",
listeningtype:1,//1 扫产品 2扫会员码 状态
};
},
mounted(){
var orderHeight = document.body.clientHeight;
// document.getElementById("order_list").style.height = (orderHeight - 100) + "px";
this.scrollbarheight = orderHeight - 330;
//扫码枪监听事件
this.$barcodeScanner.init({
endChar: 'Enter',
minLength: 4
});
document.addEventListener('barcodeScanned', this.handleScan);
},
beforeUnmount() {
this.$barcodeScanner.destroy();
document.removeEventListener('barcodeScanned', this.handleScan);
},
created: function() {
this.getCartList();//获取购物清单
},
watch:{
listdata:{
handler(newValue) {
let total = 0;
let totalCount = 0;
let totaljifen = 0;
newValue.forEach((item) => {
item.content.forEach((cc) => {
total += parseFloat(cc.readyPrice) * Number(cc.num);
totalCount = totalCount + cc.num;
totaljifen += parseFloat(cc.ready_integral) * Number(cc.num)
});
});
total = total.toFixed(2);
totaljifen = totaljifen.toFixed(2);
const priceParts = total.split(".");
const formatBig = priceParts[0];
const formatMini = priceParts.length > 1 ? `.${priceParts[1]}` : ".00";
this.totalMoney = total;
this.totalCount = totalCount;
this.totaljifen = totaljifen;//积分
this.Userprice = parseFloat(parseFloat(total) - parseFloat(this.totaljifen)).toFixed(2);
},
deep: true,
}
},
methods: {
add(){
this.dialog.save = true
this.$nextTick(() => {
this.$refs.saveBox.open().setData({})
})
},
table_edit(row){
this.dialog.save = true
this.$nextTick(() => {
this.$refs.saveBox.open('edit').setData(row)
})
},
//---规格加入购物车-------------------------------------------------------------------------
//规格提交
addCartHandle() {
this.dialogVisible = false;
let skuId = this.childgoods.skuId;
let number = this.childgoods.popNumber;
// this.$emit("popAddCart", skuId, number);
this.addCart("multiple", skuId, number);
},
//提交加入购物车
addCart(type, skuId, number) {
let that = this;
let req = {};
if (type === "single") {//没有规格
req = {
goods_sn:that.childgoods.goods_sn,//商品编号
goods_id: that.childgoods.id,
goods_sku_id: 0,
num: 1,
store_id: that.childgoods.store_id,
};
} else {//有规格
req = {
goods_sn:that.childgoods.popSkuGoods_sn,//商品编号
goods_id: that.childgoods.id,
goods_sku_id: skuId,
num: number,
store_id: that.childgoods.store_id,
};
}
console.info('req',req);
this.$API.cashier.cart.add.post(req).then(res=>{
if (res.code == 1) {
this.$message({
message: "添加成功~",
type: "success"
});
this.getCartList();//获取购物清单
this.scannedCode = "";
this.childgoods={spec_list:[]};
}else{
this.$message.error(res.message);
this.scannedCode = "";
this.childgoods={spec_list:[]};
}
}).catch((err) => {
this.scannedCode = "";
this.childgoods={spec_list:[]};
console.log("🚀 ~ cart ~ err:", err);
});
},
//购物车产品数量加减
stepMinusHandle(num,cc) {
console.info('stepMinusHandle',num,cc);
let that = this;
let goods_id = cc.goods_id;
let goods_sku_id = cc.goods_sku_id;
let cart_id = cc.cart_id;
let obj = that.odata.find((v) => v.id == cart_id);
console.log("🚀 ~ stepMinusHandle ~ obj:", obj);
// let num = obj.num - 1;
if (num != 0) {
let req = {
id: cart_id,
goods_id: goods_id,
goods_sku_id: goods_sku_id,
num: num,
};
this.$API.cashier.cart.edit.post(req)
.then((res) => {
console.log("🚀 ~ editCart ~ res:", res);
if (res.code == 1) {
that.getCartList();
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ editCart ~ err:", err);
});
} else {
//删除
let req = {
id: cart_id,
};
this.$API.cashier.cart.delete.post(req)
.then((res) => {
console.log("🚀 ~ delCart ~ res:", res);
if (res.code == 1) {
that.getCartList();
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ delCart ~ err:", err);
});
}
},
//数量加减
numberChangeHandle(e) {
console.log(e.detail);
console.log(this.childgoods.popStock.match(/\d+/)[0]);
if (Number(e.detail) > Number(this.childgoods.popStock.match(/\d+/)[0])) {
this.$message.error("库存不足~");
} else {
this.childgoods.popNumber = e.detail;
}
},
//规格被选择
skuTapHandle(item, outer, cc) {
this.childgoods.spec_list[outer]["selected"] = cc;
this.changeSku();
},
//修改规格
changeSku() {
let arr = this.childgoods.spec_list;
if (arr.every((item) => item.selected)) {
console.log("所有规格已选择");
// 取出item的name和selected,组成{name:selected}格式
let sku = arr.reduce((acc, cur) => {
acc[cur.name] = cur.selected;
return acc;
}, {});
let skuObj = this.childgoods.sku.find(
(item) => JSON.stringify(item.sku_value) === JSON.stringify(sku)
);
console.log("🚀 ~ changeSku ~ skuObj:", skuObj);
let parts = skuObj.price.split(".");
this.childgoods.popFormatBig = parts[0];
this.childgoods.popFormatMini = parts[1] ? "." + parts[1] : ".00";
this.childgoods.popStock = "库存 " + skuObj.stock;
this.childgoods.popNumber = 1;
this.childgoods.popSkuGoods_sn = skuObj.goods_sn;
this.childgoods["skuId"] = skuObj.id;
} else {
console.log("还有规格未选择");
}
},
//删除产品
goodsDeleteHandle(gid, sid) {
let that = this;
let cid = that.odata
.filter((v) => v.goods_id == gid && v.goods_sku_id == sid)
.map((v) => v.id);
let req = {
ids: cid,
};
this.$API.cashier.cart.delete.post(req)
.then((res) => {
console.log("🚀 ~ delCart ~ res:", res);
if (res.code == 1) {
that.getCartList();
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ delCart ~ err:", err);
});
},
//获取购物车列表
getCartList(){
let that = this;
this.$API.cashier.cart.list.get({page:1,limit:100}).then((res) => {
console.log("🚀 ~ getCartList ~ res:", res);
if (res.code == 1) {
let data = res.data;
that.odata = data;
const groupedData = data.reduce((acc, item) => {
const storeId = item.store_id;
if (!acc[storeId]) {
acc[storeId] = {
id: storeId,
title: item.store.title,
cover: item.store.cover,
content: [],
selected: 0,
};
}
acc[storeId].content.push({
cart_id: item.id,
member_id: item.member_id,
goods_id: item.goods_id,
goods_sku_id: item.goods_sku_id,
num: item.num,
created_at: item.created_at,
updated_at: item.updated_at,
goods: item.goods,
sku: item.sku,
});
return acc;
}, {});
const result = Object.values(groupedData);
result.forEach((store) => {
store.content.forEach((item) => {
if (item.sku && item.sku.price) {
const priceParts = item.sku.price.split(".");
const formatBig = priceParts[0];
const formatMini =
priceParts.length > 1 ? `.${priceParts[1]}` : ".00";
item.formatBig = formatBig;
item.formatMini = formatMini;
item.readyPrice = item.sku.price;
item.selected = 0;
item.ready_integral = item.sku.integral;//积分
} else {
const priceParts = item.goods.price.split(".");
const formatBig = priceParts[0];
const formatMini =
priceParts.length > 1 ? `.${priceParts[1]}` : ".00";
item.formatBig = formatBig;
item.formatMini = formatMini;
item.readyPrice = item.goods.price;
item.selected = 0;
item.ready_integral = item.goods.integral;////积分
}
});
const mergedData = Object.values(
that.mergeObjects(store.content)
);
console.log("🚀 ~ result.forEach ~ mergedData:", mergedData);
store.content = mergedData;
});
console.log("🚀 ~ result.forEach ~ result:", result);
that.listdata = result;
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ getCartList ~ err:", err);
});
},
// 合并购物车相同规格的商品
mergeObjects(arr) {
return arr.reduce((acc, curr) => {
const key = curr.sku ?
`${curr.goods.id}-${curr.sku.id}` :
`${curr.goods.id}`;
if (acc[key]) {
acc[key].num += curr.num;
} else {
acc[key] = {
...curr,
goods: {
...curr.goods
},
sku: curr.sku ? {
...curr.sku
} : null,
};
delete acc[key].id;
}
return acc;
}, {});
},
//关闭 支付订单 弹窗
cleardialog(){
this.dialogVisibletwo = false;
this.getCartList();
},
//关闭 支付订单 弹窗
handleClosetwo(done) {
ElMessageBox.confirm('确定要关闭弹窗吗?')
.then(() => {
done()
this.getCartList();
})
.catch(() => {
// catch error
})
},
//---规格加入购物车-------------------------------------------------------------------------
//关闭 选择规格 弹窗
handleClose(done) {
ElMessageBox.confirm('确定要关闭弹窗吗?')
.then(() => {
done()
})
.catch(() => {
// catch error
})
},
//监听扫码枪识别 和 会员扣积分
focusfun(types){
// 自动聚焦到输入框,方便直接扫描
if(types==2 && this.totaljifen==0){
this.$message.error("店员,没有可抵积分的东西,怎么扣积分呀~");
return false;
}
this.listeningtype = types;
// this.loading = ElLoading.service({
// lock: true,
// text: "请开始扫码识别",
// background: "rgba(255, 255, 255, 0.7)",
// });
},
// 扫码识别
handleScan(event){
console.info('handleScan',event);
console.log('扫描结果:', event.detail);
// this.$emit('scan', event.detail);
this.scannedCode = event.detail;
if(this.listeningtype==1){
//扫产品
if(this.scannedCode && this.scannedCode.length>5){
this.childgoods.goods_sn = this.scannedCode;
this.childgoods.store_id = 0;
this.addCart("single", "", 1);
}
}else if(this.listeningtype==2){
//扫会员码
console.info("this.scannedCode 扫会员码",this.scannedCode);
var idPattern = /^\d+$/;
if(this.scannedCode && idPattern.test(this.scannedCode) && this.scannedCode.length<8){
this.addjf(this.scannedCode);
}
}
},
//会员扣积分 事件
addjf(user_id){
console.info("addjf");
this.dialog.save1 = true
this.$nextTick(() => {
this.$refs.saveBox1.open().setData({
amount:this.totaljifen,//积分额度
member_id:user_id,//用户
type:'pay',//积分类型
remark:"到店消费",//积分描述
})
})
},
// 添加和计算商品价格 添加数量
addOrderList(goods,index) {
// 商品是否已经存在于订单列表中
if(goods.sku.length){
//规格
this.dialogVisible = true;
this.childgoods = goods;
return false;
}else{
//非规格
this.childgoods = goods;
this.addCart("single", 0, 1);
return false;
}
},
// 全部删除商品 清空购物车
delAllGoods() {
// this.odata = [];
this.listdata = [];
this.totalMoney = 0;
this.totalCount = 0;
this.totaljifen = 0;
this.childgoods = {spec_list:[]};
let req = {
ids: this.odata.map(product => product.id),
};
this.$API.cashier.cart.delete.post(req)
.then((res) => {
console.log("🚀 ~ delCart ~ res:", res);
if (res.code == 1) {
that.getCartList();
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ delCart ~ err:", err);
});
},
// 模拟结账 用户结算
checkOut() {
// this.$message.error("程序猿小哥正在开发中~");
if(this.odata.length){
this.$API.cashier.cart.simple.post({
carts:this.odata.map(item=>{return item.id}),
})
.then((res) => {
console.log("🚀 ~ simple ~ res:", res);
if(res.code==1){
this.$API.cashier.cart.nativepc.post({order_id:res.data.id}).then(restwo=>{
console.log("🚀 ~ simple ~ restwo:", restwo);
if(restwo.code==1){
let packagestr = restwo.data.package;
let match = packagestr.match(/prepay_id=([^&]+)/);
if (match) {
let qrcodeurl = match[1];
console.log(qrcodeurl); // 输出: weixin://wxpay/bizpayurl?pr=g5bMCytz3
this.qrcodeurl = qrcodeurl;
this.dialogVisibletwo = true;
this.$nextTick(()=>{
setTimeout(()=>{
this.$refs.qrcodecomp.updateQRCode(this.qrcodeurl);
},100)
})
}
}else{
this.$message.error(restwo.message);
}
})
}else{
this.$message.error(res.message);
}
})
.catch((err) => {
console.log("🚀 ~ simple ~ err:", err);
});
}else{
this.$message.error("店员,没有东西,怎么结账呀~");
}
},
upsearch(){
this.$refs.table.reload(this.search);
},
upsearch1(){
},
moreUpsearch(search){
this.search = search;
this.upsearch();
},
moreSearch(){
this.dialog.search = true
this.$nextTick(() => {
this.$refs.searchBox.open().setData(this.search)
})
},
//表格选择后回调事件
selectionChange(selection){
this.selection = selection;
},
},
};
</script>
<style scoped>
@import url('./cashierhome.scss');
</style>
\ No newline at end of file
...@@ -26,11 +26,11 @@ ...@@ -26,11 +26,11 @@
<template #default="scope"> <template #default="scope">
<el-button-group> <el-button-group>
<el-button type="primary" @click="table_edit(scope.row, scope.$index)">编辑</el-button> <el-button type="primary" @click="table_edit(scope.row, scope.$index)">编辑</el-button>
<el-popconfirm title="确定删除吗?" @confirm="table_del(scope.row, scope.$index)"> <!-- <el-popconfirm title="确定删除吗?" @confirm="table_del(scope.row, scope.$index)">
<template #reference> <template #reference>
<el-button type="danger">删除</el-button> <el-button type="danger">删除</el-button>
</template> </template>
</el-popconfirm> </el-popconfirm> -->
</el-button-group> </el-button-group>
</template> </template>
</el-table-column> </el-table-column>
......
...@@ -30,11 +30,11 @@ ...@@ -30,11 +30,11 @@
<template #default="scope"> <template #default="scope">
<el-button-group> <el-button-group>
<el-button type="primary" @click="table_edit(scope.row, scope.$index)">编辑</el-button> <el-button type="primary" @click="table_edit(scope.row, scope.$index)">编辑</el-button>
<el-popconfirm title="确定删除吗?" @confirm="table_del(scope.row, scope.$index)"> <!-- <el-popconfirm title="确定删除吗?" @confirm="table_del(scope.row, scope.$index)">
<template #reference> <template #reference>
<el-button type="danger">删除</el-button> <el-button type="danger">删除</el-button>
</template> </template>
</el-popconfirm> </el-popconfirm> -->
</el-button-group> </el-button-group>
</template> </template>
</el-table-column> </el-table-column>
...@@ -60,6 +60,7 @@ export default{ ...@@ -60,6 +60,7 @@ export default{
apiObj: this.$API.goods.lists.list, apiObj: this.$API.goods.lists.list,
column: [ column: [
{prop: 'id', label: 'ID', width: 80}, {prop: 'id', label: 'ID', width: 80},
{prop: 'goods_sn', label: '商品编号'},
{prop: 'title', label: '商品名称'}, {prop: 'title', label: '商品名称'},
{prop: 'cover', label: '封面图', width: 120}, {prop: 'cover', label: '封面图', width: 120},
{prop: 'price', label: '售价', width: 120}, {prop: 'price', label: '售价', width: 120},
......
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
<el-form-item label="标签" prop="tags"> <el-form-item label="标签" prop="tags">
<sc-tag-input v-model="form.tags" placeholder="请输入标签"/> <sc-tag-input v-model="form.tags" placeholder="请输入标签"/>
</el-form-item> </el-form-item>
<el-form-item label="产品编码" prop="goods_sn">
<el-input v-model="form.goods_sn" placeholder="请输入产品编码" clearable />
</el-form-item>
<el-form-item label="简述" prop="description"> <el-form-item label="简述" prop="description">
<el-input type="textarea" v-model="form.description" placeholder="请输入简述" clearable /> <el-input type="textarea" v-model="form.description" placeholder="请输入简述" clearable />
</el-form-item> </el-form-item>
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
<div class="login-form"> <div class="login-form">
<div class="login-header"> <div class="login-header">
<div class="logo"> <div class="logo">
<img :alt="$CONFIG.APP_NAME" :src="'/static/images/logo.png'"> <img :alt="$CONFIG.APP_NAME" :src="'./static/images/logo.png'">
<label>{{$CONFIG.APP_NAME}}</label> <label>{{$CONFIG.APP_NAME}}</label>
</div> </div>
</div> </div>
......
<template> <template>
<el-container> <el-container>
<!-- 大使账单 -->
<el-header> <el-header>
<div class="left-panel"> <div class="left-panel">
<el-select v-model="search.type" placeholder="请选择类型" style="width: 180px; margin-right: 10px;" clearable> <el-select v-model="search.type" placeholder="请选择类型" style="width: 180px; margin-right: 10px;" clearable>
...@@ -8,7 +9,7 @@ ...@@ -8,7 +9,7 @@
<el-input v-model="search.store_title" placeholder="请输入店铺名称" style="width: 180px; margin-right: 10px;" clearable /> <el-input v-model="search.store_title" placeholder="请输入店铺名称" style="width: 180px; margin-right: 10px;" clearable />
<el-input v-model="search.username" placeholder="请输入用户名" style="width: 180px; margin-right: 10px;" clearable /> <el-input v-model="search.username" placeholder="请输入用户名" style="width: 180px; margin-right: 10px;" clearable />
<el-select v-model="search.status" placeholder="请选择状态" style="width: 180px;" clearable v-if="search.type == 'withdraw'"> <el-select v-model="search.status" placeholder="请选择状态" style="width: 180px;" clearable v-if="search.type == 'withdraw'">
<el-option :label="item.label" :value="item.value" v-for="(item, index) in [{label: '已提现', value: 1}, {label: '待提现', value: 0}, {label: '已拒绝', value: 2}]" :key="index"></el-option> <el-option :label="item.label" :value="item.value" v-for="(item, index) in [{label: '已提现', value: 1}, {label: '待提现', value: 0}, {label: '已拒绝', value: 2},{label: '提现失败', value: -2}]" :key="index"></el-option>
</el-select> </el-select>
<el-select v-model="search.status" placeholder="请选择状态" style="width: 180px;" clearable v-if="search.type == 'income'"> <el-select v-model="search.status" placeholder="请选择状态" style="width: 180px;" clearable v-if="search.type == 'income'">
<el-option :label="item.label" :value="item.value" v-for="(item, index) in [{label: '已到账', value: 1}, {label: '未入账', value: 0}]" :key="index"></el-option> <el-option :label="item.label" :value="item.value" v-for="(item, index) in [{label: '已到账', value: 1}, {label: '未入账', value: 0}]" :key="index"></el-option>
...@@ -43,7 +44,13 @@ ...@@ -43,7 +44,13 @@
</template> </template>
<template #status="scope"> <template #status="scope">
<el-tag v-if="scope.row.type == 'income'" :type="scope.row.status == 1 ? 'success' : 'danger'">{{ scope.row.status == 1 ? '已到账' : '未入账' }}</el-tag> <el-tag v-if="scope.row.type == 'income'" :type="scope.row.status == 1 ? 'success' : 'danger'">{{ scope.row.status == 1 ? '已到账' : '未入账' }}</el-tag>
<el-tag v-else :type="scope.row.status == 1 ? 'success' : 'danger'">{{ scope.row.status == 1 ? '已提现' : '待确认' }}</el-tag> <el-tag v-else :type="scope.row.status == 1 ? 'success' : 'danger'">
<span v-show="scope.row.status == 0">待提现</span>
<span v-show="scope.row.status == 1">已提现</span>
<span v-show="scope.row.status == 2">已拒绝</span>
<span v-show="scope.row.status == -2">提现失败</span>
</el-tag>
</template> </template>
<el-table-column label="操作" fixed="right" align="center" width="100"> <el-table-column label="操作" fixed="right" align="center" width="100">
<template #default="scope"> <template #default="scope">
...@@ -76,10 +83,12 @@ export default{ ...@@ -76,10 +83,12 @@ export default{
column: [ column: [
{prop: 'member', label: '头像'}, {prop: 'member', label: '头像'},
{prop: 'mobile', label: '手机号码', width: 120}, {prop: 'mobile', label: '手机号码', width: 120},
{prop: 'bank_realname', label: '真实姓名', width: 50},
{prop: 'type', label: '类型', width: 120, align: 'center'}, {prop: 'type', label: '类型', width: 120, align: 'center'},
{prop: 'amount', label: '额度', width: 120}, {prop: 'amount', label: '额度', width: 120},
{prop: 'af_amount', label: '余额', width: 120}, {prop: 'af_amount', label: '余额', width: 120},
{prop: 'remark', label: '备注', width: 120}, {prop: 'remark', label: '备注', width: 120},
{prop: 'reason', label: '失败理由', width: 60},
{prop: 'status', label: '状态', width: 120}, {prop: 'status', label: '状态', width: 120},
{prop: 'created_at', label: '添加时间', width: 140}, {prop: 'created_at', label: '添加时间', width: 140},
{prop: 'updated_at', label: '更新时间', width: 140}, {prop: 'updated_at', label: '更新时间', width: 140},
......
...@@ -24,11 +24,11 @@ ...@@ -24,11 +24,11 @@
<template #default="scope"> <template #default="scope">
<el-button-group> <el-button-group>
<el-button type="primary" size="small" @click="table_edit(scope.row, scope.$index)">编辑</el-button> <el-button type="primary" size="small" @click="table_edit(scope.row, scope.$index)">编辑</el-button>
<el-popconfirm title="您确定删除该数据" @confirm="table_del(scope.row, scope.$index)"> <!-- <el-popconfirm title="您确定删除该数据" @confirm="table_del(scope.row, scope.$index)">
<template #reference> <template #reference>
<el-button type="danger" size="small">删除</el-button> <el-button type="danger" size="small">删除</el-button>
</template> </template>
</el-popconfirm> </el-popconfirm> -->
</el-button-group> </el-button-group>
</template> </template>
</el-table-column> </el-table-column>
......
<template>
<el-container>
<el-header>
<div class="left-panel">
<!-- <el-select v-model="search.type" placeholder="请选择" style="width: 180px; margin-right: 10px;" clearable>
<el-option :label="item.label" :value="item.value" v-for="(item, index) in typeList"></el-option>
</el-select> -->
<el-input v-model="search.store_title" placeholder="请输入店铺名称" style="width: 180px; margin-right: 10px;" clearable />
<el-input v-model="search.username" placeholder="请输入用户名" style="width: 180px; margin-right: 10px;" clearable />
<el-button-group style="margin-left: 10px;">
<el-button type="primary" icon="el-icon-search" @click="upsearch">搜索</el-button>
</el-button-group>
</div>
<div class="right-panel">
<el-button-group>
<el-button type="danger" icon="el-icon-plus" @click="add">添加</el-button>
</el-button-group>
</div>
</el-header>
<el-main class="nopadding">
<scTable tableName="member" ref="table" :apiObj="list.apiObj" :column="list.column" row-key="id" @selection-change="selectionChange" border stripe size="small">
<el-table-column type="selection" width="50"></el-table-column>
<template #member="scope">
<div style="display: flex; gap: 8px; align-items: center;">
<el-image :src="scope.row.member?.avatar" style="width: 40px; height: 40px;" />
<div style="display: flex; flex-direction: column;">
<span>{{ scope.row.member?.nickname }}</span>
<span>{{ scope.row.member?.username }}</span>
</div>
</div>
</template>
<template #mobile="scope">
{{ scope.row.member?.mobile }}
</template>
</scTable>
</el-main>
</el-container>
<save v-if="dialog.save" ref="saveBox" @success="upsearch" @closed="dialog.save=false" />
</template>
<script>
import save from './save.vue'
export default{
name: 'memberpolymer',
components:{
save
},
data(){
return {
dialog: {search: false, import: false, save: false},
list: {
apiObj: this.$API.member.polymer.list,
column: [
{prop: 'id', label: 'ID', width: 80},
{prop: 'member', label: '用户'},
{prop: 'member_id', label: '用户id'},
{prop: 'mobile', label: '手机号码', width: 120},
{prop: 'amount', label: '额度', width: 120},
{prop: 'af_amount', label: '余额', width: 120},
{prop: 'remark', label: '备注', width: 120},
{prop: 'created_at', label: '添加时间', width: 140},
{prop: 'updated_at', label: '更新时间', width: 140},
],
},
selection: [],
typeList: [{label: '分享', value: 'share'}, {label: '排队', value: 'queue'},{label: '合伙人', value: 'partner'},{label: '货款', value: 'sale'}],
search: {},
}
},
methods: {
upsearch(){
this.$refs.table.reload(this.search);
},
moreUpsearch(search){
this.search = search;
this.upsearch();
},
moreSearch(){
this.dialog.search = true
this.$nextTick(() => {
this.$refs.searchBox.open().setData(this.search)
})
},
//表格选择后回调事件
selectionChange(selection){
this.selection = selection;
},
add(){
this.dialog.save = true
this.$nextTick(() => {
this.$refs.saveBox.open().setData({})
})
}
}
}
</script>
\ No newline at end of file
<template>
<el-dialog :title="titleMap[mode]" v-model="visible" :width="500" destroy-on-close :close-on-click-modal="false" @closed="$emit('closed')">
<el-form :model="form" :rules="rules" :disabled="mode=='show'" ref="dialogForm" label-width="100px" label-position="left">
<el-form-item label="聚物通额度" prop="amount">
<el-input v-model="form.amount" placeholder="聚物通额度" clearable />
</el-form-item>
<el-form-item label="用户" prop="member_id">
<el-input v-model="form.member_id" placeholder="用户" clearable />
</el-form-item>
<el-form-item label="聚物通类型" prop="type">
<el-select v-model="form.type" placeholder="聚物通类型" clearable>
<el-option label="增加" value="income" />
<el-option label="减少" value="pay" />
</el-select>
</el-form-item>
<el-form-item label="聚物通描述" prop="remark">
<el-input type="textarea" v-model="form.remark" placeholder="聚物通描述" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible=false" >取 消</el-button>
<el-button v-if="mode!='show'" type="primary" :loading="isSaveing" @click="submit()">提 交</el-button>
</template>
</el-dialog>
</template>
<script>
export default {
emits: ['success', 'closed'],
data() {
return {
mode: "add",
titleMap: {
add: '聚物通',
edit: '编辑等级',
show: '查看'
},
visible: false,
isSaveing: false,
//表单数据
form: { title: '', name: ''},
//验证规则
rules: {
amount: [{required: true, message: '请输入聚物通额度'}],
member_id: [{required: true, message: '请输入用户UID'}],
type: [{required: true, message: '请选择聚物通类型'}],
remark: [{required: true, message: '请输入聚物通描述'}]
}
}
},
mounted() {
},
methods: {
//显示
open(mode='add'){
this.mode = mode;
this.visible = true;
return this
},
//表单提交方法
submit(){
this.$refs.dialogForm.validate(async (valid) => {
if (valid) {
this.isSaveing = true;
var res = {};
if(this.mode == 'add'){
res = await this.$API.member.polymer.add.post(this.form);
}else{
res = await this.$API.member.polymer.edit.post(this.form);
}
this.isSaveing = false;
if(res.code == 1){
this.$emit('success', this.form, this.mode)
this.visible = false;
this.$message.success("操作成功")
}else{
this.$alert(res.message, "提示", {type: 'error'})
}
}else{
return false;
}
})
},
//表单注入数据
setData(data){
this.form = data
}
}
}
</script>
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
</el-form> </el-form>
<template #footer> <template #footer>
<el-button @click="visible=false" >取 消</el-button> <el-button @click="visible=false" >取 消</el-button>
<el-button v-if="mode!='show'" type="primary" :loading="isSaveing" @click="submit()">保 存</el-button> <el-button v-if="mode!='show'" type="primary" :loading="isSaveing" @click="submit()">提 交</el-button>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
...@@ -31,7 +31,7 @@ export default { ...@@ -31,7 +31,7 @@ export default {
return { return {
mode: "add", mode: "add",
titleMap: { titleMap: {
add: '新增等级', add: '积分',
edit: '编辑等级', edit: '编辑等级',
show: '查看' show: '查看'
}, },
......
...@@ -3,65 +3,46 @@ ...@@ -3,65 +3,46 @@
<el-header> <el-header>
<div class="left-panel"> <div class="left-panel">
<el-input v-model="search.keyword" placeholder="关键词" style="width:150px; margin-right: 10px;" clearable></el-input> <el-input v-model="search.keyword" placeholder="关键词" style="width:150px; margin-right: 10px;" clearable></el-input>
<el-input v-model="search.name" placeholder="申请人" style="width:150px; margin-right: 10px;" clearable />
<el-input v-model="search.mobile" placeholder="手机号码" style="width:150px; margin-right: 10px;" clearable />
<el-button-group style="margin-left: 10px;"> <el-button-group style="margin-left: 10px;">
<el-button type="primary" icon="el-icon-search" @click="upsearch">搜索</el-button> <el-button type="primary" icon="el-icon-search" @click="upsearch">搜索</el-button>
</el-button-group> </el-button-group>
</div> </div>
<div class="right-panel">
<el-button-group>
<el-button type="danger" icon="el-icon-plus" @click="add">添加</el-button>
</el-button-group>
</div>
</el-header> </el-header>
<el-main class="nopadding"> <el-main class="nopadding">
<scTable tableName="member" ref="table" :apiObj="list.apiObj" :column="list.column" row-key="id" @selection-change="selectionChange" border stripe> <scTable tableName="member" ref="table" :apiObj="list.apiObj" :column="list.column" row-key="id" @selection-change="selectionChange" border stripe>
<el-table-column type="selection" width="50"></el-table-column> <el-table-column type="selection" width="50"></el-table-column>
<template #order_no="scope">
{{ scope.row.order?.order_no }}
</template>
<template #member="scope">
{{ scope.row.member?.nickname }}{{ scope.row.member?.username }}
</template>
<template #status="scope">
<el-tag :type="status[scope.row.status]?.type">{{ status[scope.row.status]?.label ?? '未知'}}</el-tag>
</template>
<el-table-column label="操作" fixed="right" align="center" width="140"> <el-table-column label="操作" fixed="right" align="center" width="140">
<template #default="scope">
<el-button-group>
<el-button type="primary" @click="table_audit(scope.row, scope.$index)" v-if="scope.row.status == 0">审核</el-button>
</el-button-group>
</template>
</el-table-column> </el-table-column>
</scTable> </scTable>
</el-main> </el-main>
<save v-if="dialog.save" ref="saveBox" @success="upsearch" @closed="dialog.save=false" />
</el-container> </el-container>
</template> </template>
<script> <script>
import save from './save.vue'
export default{ export default{
name: 'order.exchange', name: 'order.exchange',
components:{ components:{
save,
}, },
data(){ data(){
return { return {
dialog: {search: false, import: false, print: false}, dialog: {search: false, import: false, print: false},
status: {0: {label: '待审核', type: 'primary'}, 1: {label: '已通过', type: 'success'}, 2: {label: '已拒绝', type: 'danger'}, 3: {label: '已完成', type: 'warning'}},
list: { list: {
apiObj: this.$API.order.refund.list, apiObj: this.$API.order.exchange.list,
column: [ column: [
{prop: 'id', label: 'ID', width: 80}, {prop: 'id', label: 'ID', width: 80},
{prop: 'order_id', label: '订单ID', width: 120}, {prop: 'name', label: '置换申请人', width: 120},
{prop: 'order_no', label: '订单号', width: 240}, {prop: 'mobile', label: '手机号', width: 120},
{prop: 'member', label: '申请人'}, {prop: 'address', label: '地址'},
{prop: 'amount', label: '退款金额', width: 120}, {prop: 'remark', label: '行业备注'},
{prop: 'reason', label: '退款原因', width: 120}, {prop: 'status', label: '状态', width: 120},
{prop: 'status', label: '退款状态', width: 120},
{prop: 'created_at', label: '添加时间', width: 140}, {prop: 'created_at', label: '添加时间', width: 140},
{prop: 'updated_at', label: '更新时间', width: 140},
], ],
}, },
selection: [], selection: [],
...@@ -85,46 +66,7 @@ export default{ ...@@ -85,46 +66,7 @@ export default{
//表格选择后回调事件 //表格选择后回调事件
selectionChange(selection){ selectionChange(selection){
this.selection = selection; this.selection = selection;
},
batch_del(){
},
table_show(row){
this.dialog.detail = true
this.$nextTick(() => {
this.$refs.detailBox.open().setData(row)
})
},
add(){
this.dialog.save = true
this.$nextTick(() => {
this.$refs.saveBox.open()
})
},
table_edit(row){
this.dialog.save = true
this.$nextTick(() => {
this.$refs.saveBox.open('edit').setData(row)
})
},
table_audit(row){
this.dialog.save = true
this.$nextTick(() => {
this.$refs.saveBox.open('audit').setData(row)
})
},
async table_del(row){
var reqData = {id: row.id}
var res = await this.$API.order.refund.delete.post(reqData);
if(res.code == 1){
//这里选择刷新整个表格 OR 插入/编辑现有表格数据
this.upsearch()
this.$message.success("删除成功")
}else{
this.$alert(res.message, "提示", {type: 'error'})
}
} }
} }
} }
</script> </script>
\ No newline at end of file
...@@ -38,11 +38,11 @@ ...@@ -38,11 +38,11 @@
<template #default="scope"> <template #default="scope">
<el-button-group> <el-button-group>
<el-button type="primary" @click="table_show(scope.row, scope.$index)">详情</el-button> <el-button type="primary" @click="table_show(scope.row, scope.$index)">详情</el-button>
<el-popconfirm title="确定删除吗?" @confirm="table_del(scope.row, scope.$index)"> <!-- <el-popconfirm title="确定删除吗?" @confirm="table_del(scope.row, scope.$index)">
<template #reference> <template #reference>
<el-button type="danger">删除</el-button> <el-button type="danger">删除</el-button>
</template> </template>
</el-popconfirm> </el-popconfirm> -->
</el-button-group> </el-button-group>
</template> </template>
</el-table-column> </el-table-column>
......
<template> <template>
<el-container> <el-container>
<!-- 我的收益 -->
<el-header> <el-header>
<div class="left-panel"> <div class="left-panel">
<el-select v-model="search.type" placeholder="请选择类型" style="width: 180px; margin-right: 10px;" clearable> <el-select v-model="search.type" placeholder="请选择类型" style="width: 180px; margin-right: 10px;" clearable>
...@@ -8,7 +9,7 @@ ...@@ -8,7 +9,7 @@
<el-input v-model="search.store_title" placeholder="请输入店铺名称" style="width: 180px; margin-right: 10px;" clearable /> <el-input v-model="search.store_title" placeholder="请输入店铺名称" style="width: 180px; margin-right: 10px;" clearable />
<el-input v-model="search.username" placeholder="请输入用户名" style="width: 180px; margin-right: 10px;" clearable /> <el-input v-model="search.username" placeholder="请输入用户名" style="width: 180px; margin-right: 10px;" clearable />
<el-select v-model="search.status" placeholder="请选择状态" style="width: 180px;" clearable v-if="search.type == 'withdraw'"> <el-select v-model="search.status" placeholder="请选择状态" style="width: 180px;" clearable v-if="search.type == 'withdraw'">
<el-option :label="item.label" :value="item.value" v-for="(item, index) in [{label: '已提现', value: 1}, {label: '待提现', value: 0}, {label: '已拒绝', value: 2}]" :key="index"></el-option> <el-option :label="item.label" :value="item.value" v-for="(item, index) in [{label: '已提现', value: 1}, {label: '待提现', value: 0}, {label: '已拒绝', value: 2},{label: '提现失败', value: -2}]" :key="index"></el-option>
</el-select> </el-select>
<el-select v-model="search.status" placeholder="请选择状态" style="width: 180px;" clearable v-if="search.type == 'income'"> <el-select v-model="search.status" placeholder="请选择状态" style="width: 180px;" clearable v-if="search.type == 'income'">
<el-option :label="item.label" :value="item.value" v-for="(item, index) in [{label: '已到账', value: 1}, {label: '未入账', value: 0}]" :key="index"></el-option> <el-option :label="item.label" :value="item.value" v-for="(item, index) in [{label: '已到账', value: 1}, {label: '未入账', value: 0}]" :key="index"></el-option>
...@@ -37,7 +38,14 @@ ...@@ -37,7 +38,14 @@
</template> </template>
<template #status="scope"> <template #status="scope">
<el-tag v-if="scope.row.type == 'service_income'" :type="scope.row.status == 1 ? 'success' : 'danger'">{{ scope.row.status == 1 ? '已到账' : '未入账' }}</el-tag> <el-tag v-if="scope.row.type == 'service_income'" :type="scope.row.status == 1 ? 'success' : 'danger'">{{ scope.row.status == 1 ? '已到账' : '未入账' }}</el-tag>
<el-tag v-else :type="scope.row.status == 1 ? 'success' : 'danger'">{{ scope.row.status == 1 ? '已提现' : '待确认' }}</el-tag> <!-- <el-tag v-else :type="scope.row.status == 1 ? 'success' : 'danger'">{{ scope.row.status == 1 ? '已提现' : '待确认' }}</el-tag> -->
<el-tag v-else :type="scope.row.status == 1 ? 'success' : 'danger'">
<span v-show="scope.row.status == 0">待提现</span>
<span v-show="scope.row.status == 1">已提现</span>
<span v-show="scope.row.status == 2">已拒绝</span>
<span v-show="scope.row.status == -2">提现失败</span>
</el-tag>
</template> </template>
<el-table-column label="操作" fixed="right" align="center" width="100"> <el-table-column label="操作" fixed="right" align="center" width="100">
<template #default="scope"> <template #default="scope">
...@@ -71,6 +79,7 @@ export default{ ...@@ -71,6 +79,7 @@ export default{
{prop: 'af_amount', label: '余额', width: 120}, {prop: 'af_amount', label: '余额', width: 120},
{prop: 'remark', label: '备注', width: 120}, {prop: 'remark', label: '备注', width: 120},
{prop: 'status', label: '状态', width: 120}, {prop: 'status', label: '状态', width: 120},
{prop: 'reason', label: '提败理由', width: 120},
{prop: 'created_at', label: '添加时间', width: 140}, {prop: 'created_at', label: '添加时间', width: 140},
{prop: 'updated_at', label: '更新时间', width: 140}, {prop: 'updated_at', label: '更新时间', width: 140},
], ],
......
...@@ -31,7 +31,7 @@ export default { ...@@ -31,7 +31,7 @@ export default {
return { return {
mode: "add", mode: "add",
titleMap: { titleMap: {
add: '新增等级', add: '积分',
edit: '编辑等级', edit: '编辑等级',
show: '查看' show: '查看'
}, },
......
class BarcodeScanner {
constructor(options = {}) {
this.options = {
endChar: 'Enter', // 默认结束符为回车
minLength: 3, // 最小条码长度
timeout: 100, // 输入超时(毫秒)
...options
};
this.barcode = '';
this.timer = null;
this.init();
this.handleKeyDown = this.handleKeyDown.bind(this); // 固定this指向
}
init() {
// document.addEventListener('keydown', this.handleKeyDown.bind(this));
document.addEventListener('keydown', this.handleKeyDown);
}
handleKeyDown(event) {
// 忽略组合键和结束符之前的处理
if (event.ctrlKey || event.altKey || event.metaKey || event.keyCode === 229) return;
const { key } = event;
// 检测到结束符
if (key === this.options.endChar) {
event.preventDefault(); // 阻止默认回车行为
if (this.barcode.length >= this.options.minLength) {
this.processBarcode(this.barcode);
}
this.reset();
return;
}
// 处理有效字符
if (key.length === 1 && !event.repeat) {
this.barcode += key;
this.resetTimer();
}
}
resetTimer() {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
if (this.barcode.length >= this.options.minLength) {
this.processBarcode(this.barcode);
}
this.reset();
}, this.options.timeout);
}
reset() {
this.barcode = '';
clearTimeout(this.timer);
}
processBarcode(barcode) {
console.log('Scanned barcode:', barcode);
// 触发自定义事件或回调函数
const event = new CustomEvent('barcodeScanned', { detail: barcode });
document.dispatchEvent(event);
}
// 保持之前的类实现,但增加销毁方法
destroy() {
// document.removeEventListener('keydown', this.handleKeyDown);
document.removeEventListener('keydown', this.handleKeyDown);
}
}
export default BarcodeScanner
/*
// 使用示例
const scanner = new BarcodeScanner();
// 监听扫描事件
document.addEventListener('barcodeScanned', (e) => {
console.log('Received barcode:', e.detail);
});
*/
//本代码为1.0 版本
\ No newline at end of file
let scannerInstance = null;
export default {
install(app) {
const createScanner = () => {
class BarcodeScanner {
constructor(options = {}) {
// 先绑定事件处理器!!!
this.handleKeyDown = this.handleKeyDown.bind(this);
// 初始化配置
this.options = {
endChar: 'Enter',
minLength: 3,
timeout: 100,
...options
};
// 状态初始化
this.barcode = '';
this.timer = null;
// 启动监听
this.init();
}
init() {
// document.addEventListener('keydown', this.handleKeyDown);
try {
document.addEventListener('keydown', this.handleKeyDown);
} catch (e) {
console.error('条码扫描器初始化失败:', e);
}
}
// 其他方法保持不变...
handleKeyDown(event) {
if (event.ctrlKey || event.altKey || event.metaKey || event.keyCode === 229) return;
const { key } = event;
if (key === this.options.endChar) {
event.preventDefault();
if (this.barcode.length >= this.options.minLength) {
this.processBarcode(this.barcode);
}
this.reset();
return;
}
if (key.length === 1 && !event.repeat) {
this.barcode += key;
this.resetTimer();
}
}
resetTimer() {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
if (this.barcode.length >= this.options.minLength) {
this.processBarcode(this.barcode);
}
this.reset();
}, this.options.timeout);
}
reset() {
this.barcode = '';
clearTimeout(this.timer);
}
processBarcode(barcode) {
// 防重复触发(500ms内不处理相同条码)
if (this.lastBarcode === barcode && Date.now() - this.lastScan < 500) return;
this.lastBarcode = barcode;
this.lastScan = Date.now();
// 触发事件...
const event = new CustomEvent('barcodeScanned', { detail: barcode });
document.dispatchEvent(event);
}
destroy() {
document.removeEventListener('keydown', this.handleKeyDown);
}
}
return new BarcodeScanner();
};
app.config.globalProperties.$barcodeScanner = {
init(options) {
if (!scannerInstance) {
scannerInstance = createScanner(options);
}
return scannerInstance;
},
destroy() {
scannerInstance?.destroy();
scannerInstance = null;
}
};
}
};
//本代码为2.0 版本 在使用中
\ No newline at end of file
module.exports = {
content: [
'./src/**/*.{html,js,vue}', // 根据你的项目结构调整路径
],
theme: {
extend: {
colors: {
primary: '#3490dc', // 这里替换为你想要的颜色代码
pricecolar:"#f64f15",
},
},
},
plugins: [],
}
\ No newline at end of file
...@@ -2,6 +2,9 @@ import { defineConfig } from 'vite' ...@@ -2,6 +2,9 @@ import { defineConfig } from 'vite'
import path from 'path' import path from 'path'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
import tailwindcss from 'tailwindcss'
import autoprefixer from 'autoprefixer'
export default defineConfig({ export default defineConfig({
base:'./', base:'./',
plugins: [vue()], plugins: [vue()],
...@@ -20,7 +23,7 @@ export default defineConfig({ ...@@ -20,7 +23,7 @@ export default defineConfig({
__INTLIFY_PROD_DEVTOOLS__: false __INTLIFY_PROD_DEVTOOLS__: false
}, },
server: { server: {
port: 8080, port: 8081,
host: true, host: true,
open: false, open: false,
proxy: { proxy: {
...@@ -35,6 +38,8 @@ export default defineConfig({ ...@@ -35,6 +38,8 @@ export default defineConfig({
css: { css: {
postcss: { postcss: {
plugins: [ plugins: [
tailwindcss(),
autoprefixer(),
{ {
postcssPlugin: 'internal:charset-removal', postcssPlugin: 'internal:charset-removal',
AtRule: { AtRule: {
......
...@@ -10,9 +10,6 @@ use Illuminate\Support\Facades\Route; ...@@ -10,9 +10,6 @@ use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request; use Illuminate\Http\Request;
Route::get('/', function (Request $request) { Route::get('/', function (Request $request) {
// $order = \Modules\Order\Models\Order::where('id', 21)->first();
// $item = $order->detail()->first();
if (Route::has('home')){ if (Route::has('home')){
return redirect()->route('home', $request->all()); return redirect()->route('home', $request->all());
}else{ }else{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment