You've already forked guangan
商品Address
This commit is contained in:
@ -14,6 +14,9 @@
|
||||
"php": ">7.1"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"./src/helper.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"plugin\\points_mall\\": "src"
|
||||
}
|
||||
|
@ -2,7 +2,15 @@
|
||||
|
||||
namespace plugin\points_mall\controller;
|
||||
|
||||
use HttpResponseException;
|
||||
use plugin\points_mall\model\PointsMallGoodsStock;
|
||||
use plugin\points_mall\model\PointsMallGoods;
|
||||
use plugin\points_mall\model\PointsMallGoodsCate;
|
||||
use plugin\points_mall\model\PointsMallGoodsItem;
|
||||
use plugin\points_mall\service\GoodsService;
|
||||
use think\admin\Controller;
|
||||
use think\admin\extend\CodeExtend;
|
||||
use think\admin\helper\QueryHelper;
|
||||
|
||||
/**
|
||||
* 商品管理
|
||||
@ -10,13 +18,211 @@ use think\admin\Controller;
|
||||
class Goods extends Controller
|
||||
{
|
||||
/**
|
||||
* 商品管理
|
||||
* 商品数据管理
|
||||
* @auth true
|
||||
* @menu true
|
||||
* @return void
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->title = '商品管理';
|
||||
$this->type = $this->request->get('type', 'index');
|
||||
PointsMallGoods::mQuery($this->get)->layTable(function () {
|
||||
$this->title = '商品数据管理';
|
||||
$this->cates = PointsMallGoodsCate::items();
|
||||
}, function (QueryHelper $query) {
|
||||
$query->withoutField('specs,content')->like('code|name#name')->like('marks,cates', ',');
|
||||
$query->equal('status,level_upgrade,delivery_code,rebate_type')->dateBetween('create_time');
|
||||
$query->where(['status' => intval($this->type === 'index'), 'deleted' => 0]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品选择器
|
||||
* @login true
|
||||
* @return void
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function select()
|
||||
{
|
||||
$this->get['status'] = 1;
|
||||
$this->get['deleted'] = 0;
|
||||
$this->index();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加商品数据
|
||||
* @auth true
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
$this->mode = 'add';
|
||||
$this->title = '添加商品数据';
|
||||
PointsMallGoods::mForm('form', 'code');
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑商品数据
|
||||
* @auth true
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
$this->mode = 'edit';
|
||||
$this->title = '编辑商品数据';
|
||||
PointsMallGoods::mForm('form', 'code');
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制编辑商品
|
||||
* @auth true
|
||||
*/
|
||||
public function copy()
|
||||
{
|
||||
$this->mode = 'copy';
|
||||
$this->title = '复制编辑商品';
|
||||
PointsMallGoods::mForm('form', 'code');
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单数据处理
|
||||
* @param array $data
|
||||
*/
|
||||
protected function _copy_form_filter(array &$data)
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
$data['code'] = CodeExtend::uniqidNumber(16, 'G');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单数据处理
|
||||
* @param array $data
|
||||
* @throws \think\admin\Exception
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
protected function _form_filter(array &$data)
|
||||
{
|
||||
if (empty($data['code'])) {
|
||||
$data['code'] = CodeExtend::uniqidNumber(16, 'G');
|
||||
}
|
||||
if ($this->request->isGet()) {
|
||||
$this->cates = PointsMallGoodsCate::items(true);
|
||||
$data['marks'] = $data['marks'] ?? [];
|
||||
$data['cates'] = $data['cates'] ?? [];
|
||||
$data['specs'] = json_encode($data['specs'] ?? [], 64 | 256);
|
||||
$data['items'] = PointsMallGoodsItem::itemsJson($data['code']);
|
||||
$data['slider'] = is_array($data['slider'] ?? []) ? join('|', $data['slider'] ?? []) : '';
|
||||
$data['delivery_code'] = $data['delivery_code'] ?? 'FREE';
|
||||
} elseif ($this->request->isPost()) try {
|
||||
if (empty($data['cover'])) $this->error('商品图片不能为空!');
|
||||
if (empty($data['slider'])) $this->error('轮播图片不能为空!');
|
||||
// 商品规格保存
|
||||
[$count, $items] = [0, json_decode($data['items'], true)];
|
||||
$data['marks'] = arr2str($data['marks'] ?? []);
|
||||
foreach ($items as $item) if ($item['status'] > 0) {
|
||||
$count++;
|
||||
$data['price_market'] = min($data['price_market'] ?? $item['market'], $item['market']);
|
||||
$data['price_selling'] = min($data['price_selling'] ?? $item['selling'], $item['selling']);
|
||||
$data['allow_balance'] = max($data['allow_balance'] ?? $item['allow_balance'], $item['allow_balance']);
|
||||
$data['allow_integral'] = max($data['allow_integral'] ?? $item['allow_integral'], $item['allow_integral']);
|
||||
}
|
||||
if (empty($count)) $this->error('无效的的商品价格信息!');
|
||||
$this->app->db->transaction(static function () use ($data, $items) {
|
||||
// 标识所有规格无效
|
||||
PointsMallGoodsItem::mk()->where(['gcode' => $data['code']])->update(['status' => 0]);
|
||||
$model = PointsMallGoods::mk()->where(['code' => $data['code']])->findOrEmpty();
|
||||
$model->{$model->isExists() ? 'onAdminUpdate' : 'onAdminInsert'}($data['code']);
|
||||
$model->save($data);
|
||||
// 更新或写入商品规格
|
||||
foreach ($items as $item) PointsMallGoodsItem::mUpdate([
|
||||
'gsku' => $item['gsku'],
|
||||
'ghash' => $item['hash'],
|
||||
'gcode' => $data['code'],
|
||||
'gspec' => $item['spec'],
|
||||
'gimage' => $item['image'],
|
||||
'status' => $item['status'] ? 1 : 0,
|
||||
'price_cost' => $item['cost'],
|
||||
'price_market' => $item['market'],
|
||||
'price_selling' => $item['selling'],
|
||||
'allow_balance' => $item['allow_balance'],
|
||||
'allow_integral' => $item['allow_integral'],
|
||||
'number_virtual' => $item['virtual'],
|
||||
'number_express' => $item['express'],
|
||||
'reward_balance' => $item['balance'],
|
||||
'reward_integral' => $item['integral'],
|
||||
], 'ghash', ['gcode' => $data['code']]);
|
||||
});
|
||||
// 刷新产品库存
|
||||
GoodsService::stock($data['code']);
|
||||
$this->success('商品编辑成功!', 'javascript:history.back()');
|
||||
} catch (HttpResponseException $exception) {
|
||||
throw $exception;
|
||||
} catch (\Exception $exception) {
|
||||
throw $exception;
|
||||
// $this->error($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品库存入库
|
||||
* @auth true
|
||||
* @return void
|
||||
*/
|
||||
public function stock()
|
||||
{
|
||||
$input = $this->_vali(['code.require' => '商品不能为空哦!']);
|
||||
if ($this->request->isGet()) {
|
||||
$this->vo = PointsMallGoods::mk()->where($input)->with('items')->findOrEmpty()->toArray();
|
||||
empty($this->vo) ? $this->error('无效的商品!') : $this->fetch();
|
||||
} else try {
|
||||
[$data, $post, $batch] = [[], $this->request->post(), CodeExtend::uniqidDate(12, 'B')];
|
||||
if (isset($post['gcode']) && is_array($post['gcode'])) {
|
||||
foreach (array_keys($post['gcode']) as $key) if ($post['gstock'][$key] > 0) $data[] = [
|
||||
'batch_no' => $batch,
|
||||
'ghash' => $post['ghash'][$key],
|
||||
'gcode' => $post['gcode'][$key],
|
||||
'gspec' => $post['gspec'][$key],
|
||||
'gstock' => $post['gstock'][$key],
|
||||
];
|
||||
empty($data) || PointsMallGoodsStock::mk()->saveAll($data);
|
||||
}
|
||||
GoodsService::stock($input['code']);
|
||||
$this->success('库存更新成功!');
|
||||
} catch (HttpResponseException $exception) {
|
||||
throw $exception;
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
// $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品上下架
|
||||
* @auth true
|
||||
*/
|
||||
public function state()
|
||||
{
|
||||
PointsMallGoods::mSave($this->_vali([
|
||||
'status.in:0,1' => '状态值范围异常!',
|
||||
'status.require' => '状态值不能为空!',
|
||||
]), 'code');
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品数据
|
||||
* @auth true
|
||||
*/
|
||||
public function remove()
|
||||
{
|
||||
PointsMallGoods::mSave($this->_vali([
|
||||
'code.require' => '编号不能为空!',
|
||||
'deleted.value' => 1
|
||||
]), 'code');
|
||||
}
|
||||
}
|
114
plugs/think-plugs-points-mall/src/controller/GoodsCate.php
Normal file
114
plugs/think-plugs-points-mall/src/controller/GoodsCate.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\controller;
|
||||
|
||||
use plugin\points_mall\model\PointsMallGoodsCate;
|
||||
use think\admin\Controller;
|
||||
use think\admin\extend\DataExtend;
|
||||
use think\admin\helper\QueryHelper;
|
||||
|
||||
class GoodsCate extends Controller
|
||||
{
|
||||
/**
|
||||
* 最大级别
|
||||
* @var integer
|
||||
*/
|
||||
protected $maxLevel = 3;
|
||||
|
||||
/**
|
||||
* 商品分类管理
|
||||
* @auth true
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
PointsMallGoodsCate::mQuery($this->get)->layTable(function () {
|
||||
$this->title = "商品分类管理";
|
||||
}, static function (QueryHelper $query) {
|
||||
$query->where(['deleted' => 0]);
|
||||
$query->like('name')->equal('status')->dateBetween('create_time');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表数据处理
|
||||
* @param array $data
|
||||
*/
|
||||
protected function _page_filter(array &$data)
|
||||
{
|
||||
$data = DataExtend::arr2table($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加商品分类
|
||||
* @auth true
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
PointsMallGoodsCate::mForm('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑商品分类
|
||||
* @auth true
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
PointsMallGoodsCate::mForm('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单数据处理
|
||||
* @param array $data
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
protected function _form_filter(array &$data)
|
||||
{
|
||||
if ($this->request->isGet()) {
|
||||
$data['pid'] = intval($data['pid'] ?? input('pid', '0'));
|
||||
$this->cates = PointsMallGoodsCate::pdata($this->maxLevel, $data, [
|
||||
'id' => '0', 'pid' => '-1', 'name' => '顶部分类',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改商品分类状态
|
||||
* @auth true
|
||||
*/
|
||||
public function state()
|
||||
{
|
||||
PointsMallGoodsCate::mSave($this->_vali([
|
||||
'status.in:0,1' => '状态值范围异常!',
|
||||
'status.require' => '状态值不能为空!',
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品分类
|
||||
* @auth true
|
||||
*/
|
||||
public function remove()
|
||||
{
|
||||
PointsMallGoodsCate::mDelete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品分类选择器
|
||||
* @login true
|
||||
* @return void
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function select()
|
||||
{
|
||||
$this->get['status'] = 1;
|
||||
$this->get['deleted'] = 0;
|
||||
$this->index();
|
||||
}
|
||||
}
|
138
plugs/think-plugs-points-mall/src/controller/Order.php
Normal file
138
plugs/think-plugs-points-mall/src/controller/Order.php
Normal file
@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\controller;
|
||||
|
||||
use plugin\account\model\PluginAccountUser;
|
||||
use plugin\points_mall\model\PointsMallOrder;
|
||||
use plugin\points_mall\service\UserOrderService;
|
||||
use think\admin\Controller;
|
||||
use think\admin\extend\CodeExtend;
|
||||
use think\admin\helper\QueryHelper;
|
||||
use think\exception\HttpResponseException;
|
||||
|
||||
class Order extends Controller
|
||||
{
|
||||
/**
|
||||
* 订单数据管理
|
||||
* @auth true
|
||||
* @menu true
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->type = trim($this->get['type'] ?? 'ta', 't');
|
||||
PointsMallOrder::mQuery()->layTable(function (QueryHelper $query) {
|
||||
$this->title = '订单数据管理';
|
||||
$this->total = ['t0' => 0, 't1' => 0, 't2' => 0, 't3' => 0, 't4' => 0, 't5' => 0, 't6' => 0, 't7' => 0, 'ta' => 0];
|
||||
$this->types = ['ta' => '全部订单', 't2' => '待支付', 't3' => '待审核', 't4' => '待发货', 't5' => '已发货', 't6' => '已收货', 't7' => '已评论', 't0' => '已取消'];
|
||||
foreach ($query->db()->field('status,count(1) total')->group('status')->cursor() as $vo) {
|
||||
[$this->total["t{$vo['status']}"] = $vo['total'], $this->total['ta'] += $vo['total']];
|
||||
}
|
||||
}, function (QueryHelper $query) {
|
||||
|
||||
$query->with(['user', 'from', 'items', 'address']);
|
||||
|
||||
$query->equal('status,refund_status')->like('order_no');
|
||||
$query->dateBetween('create_time,payment_time,cancel_time,delivery_type');
|
||||
|
||||
// 用户搜索查询
|
||||
$db = PluginAccountUser::mQuery()->like('phone|nickname#user_keys')->db();
|
||||
if ($db->getOptions('where')) $query->whereRaw("unid in {$db->field('id')->buildSql()}");
|
||||
|
||||
// 列表选项卡
|
||||
if (is_numeric($this->type)) {
|
||||
$query->where(['status' => $this->type]);
|
||||
}
|
||||
|
||||
// 分页排序处理
|
||||
$query->where(['deleted_status' => 0]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 单据凭证支付审核
|
||||
* @auth true
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function audit()
|
||||
{
|
||||
if ($this->request->isGet()) {
|
||||
PointsMallOrder::mForm('', 'order_no');
|
||||
} else {
|
||||
$data = $this->_vali([
|
||||
'order_no.require' => '订单单号不能为空!',
|
||||
'status.in:0,1' => '审核状态数值异常!',
|
||||
'status.require' => '审核状态不能为空!',
|
||||
'remark.default' => '',
|
||||
]);
|
||||
if (empty($data['status'])) {
|
||||
$data['status'] = 0;
|
||||
$data['cancel_status'] = 1;
|
||||
$data['cancel_remark'] = $data['remark'] ?: '后台审核驳回并取消订单';
|
||||
$data['cancel_time'] = date('Y-m-d H:i:s');
|
||||
} else {
|
||||
$data['status'] = 4;
|
||||
$data['payment_code'] = CodeExtend::uniqidDate(16, 'T');
|
||||
$data['payment_time'] = date('Y-m-d H:i:s');
|
||||
$data['payment_status'] = 1;
|
||||
$data['payment_remark'] = $data['remark'] ?: '后台审核支付凭证通过';
|
||||
}
|
||||
$order = PointsMallOrder::mk()->where(['order_no' => $data['order_no']])->findOrEmpty();
|
||||
if ($order->isEmpty() || $order['status'] !== 3) $this->error('不允许操作审核!');
|
||||
// 无需发货时的处理
|
||||
if ($data['status'] === 4 && empty($order['delivery_type'])) $data['status'] = 6;
|
||||
// 更新订单支付状态
|
||||
$map = ['status' => 3, 'order_no' => $data['order_no']];
|
||||
if (PointsMallOrder::mk()->strict(false)->where($map)->update($data) !== false) {
|
||||
if (in_array($data['status'], [4, 5, 6])) {
|
||||
$this->app->event->trigger('PluginPaymentSuccess', $data);
|
||||
$this->success('订单审核通过成功!');
|
||||
} else {
|
||||
$this->app->event->trigger('PluginWemallOrderCancel', $order);
|
||||
UserOrderService::stock($data['order_no']);
|
||||
$this->success('审核驳回并取消成功!');
|
||||
}
|
||||
} else {
|
||||
$this->error('订单审核失败!');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消未支付的订单
|
||||
* @auth true
|
||||
* @return void
|
||||
*/
|
||||
public function cancel()
|
||||
{
|
||||
$data = $this->_vali(['order_no.require' => '订单号不能为空!']);
|
||||
$order = PointsMallOrder::mk()->where($data)->findOrEmpty();
|
||||
if ($order->isEmpty()) $this->error('订单查询异常!');
|
||||
try {
|
||||
if (!in_array($order['status'], [1, 2, 3])) {
|
||||
$this->error('订单不能取消!');
|
||||
}
|
||||
$result = $order->save([
|
||||
'status' => 0,
|
||||
'cancel_status' => 1,
|
||||
'cancel_remark' => '后台取消未支付的订单',
|
||||
'cancel_time' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
if ($result !== false) {
|
||||
UserOrderService::stock($order['order_no']);
|
||||
$this->app->event->trigger('PluginWemallOrderCancel', $order);
|
||||
$this->success('取消未支付的订单成功!');
|
||||
} else {
|
||||
$this->error('取消支付的订单失败!');
|
||||
}
|
||||
} catch (HttpResponseException $exception) {
|
||||
throw $exception;
|
||||
} catch (\Exception $exception) {
|
||||
$this->error($exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ use think\exception\HttpResponseException;
|
||||
|
||||
class Auth extends AuthController
|
||||
{
|
||||
protected $checkBind = false;
|
||||
/**
|
||||
* 控制器初始化
|
||||
* @return void
|
||||
@ -15,7 +16,7 @@ class Auth extends AuthController
|
||||
{
|
||||
try {
|
||||
parent::initialize();
|
||||
$this->checkUserStatus(false);
|
||||
$this->checkUserStatus($this->checkBind);
|
||||
} catch (HttpResponseException $exception) {
|
||||
throw $exception;
|
||||
} catch (\Exception $exception) {
|
||||
|
95
plugs/think-plugs-points-mall/src/controller/api/Goods.php
Normal file
95
plugs/think-plugs-points-mall/src/controller/api/Goods.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\controller\api;
|
||||
|
||||
use plugin\points_mall\model\PointsMallGoods;
|
||||
use plugin\points_mall\model\PointsMallGoodsCate;
|
||||
use plugin\points_mall\model\PointsMallGoodsItem;
|
||||
use think\admin\Controller;
|
||||
use think\admin\extend\CodeExtend;
|
||||
use think\admin\helper\QueryHelper;
|
||||
use think\db\Query;
|
||||
|
||||
/**
|
||||
* 商品数据管理
|
||||
* @class Goods
|
||||
* @package plugin\points_mall\controller\api
|
||||
*/
|
||||
class Goods extends Controller
|
||||
{
|
||||
/**
|
||||
* 获取商品列表或详情
|
||||
* @return void
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$this->cnames = null;
|
||||
PointsMallGoods::mQuery(null, function (QueryHelper $query) {
|
||||
// 显示分类显示
|
||||
if (!empty($vCates = input('cates'))) {
|
||||
$cates = array_filter(PointsMallGoodsCate::items(), function ($v) use ($vCates) {
|
||||
return $v['id'] == $vCates;
|
||||
});
|
||||
$this->cnames = null;
|
||||
if (count($cates) > 0) {
|
||||
$cate = array_pop($cates);
|
||||
$this->cnames = array_combine($cate['ids'], $cate['names']);
|
||||
}
|
||||
}
|
||||
$query->equal('code')->like('name#keys')->like('marks,cates', ',');
|
||||
if (!empty($code = input('code'))) {
|
||||
// 查询单个商品详情
|
||||
$query->with(['discount', 'items', 'comments' => function (Query $query) {
|
||||
$query->limit(2)->where(['status' => 1, 'deleted' => 0]);
|
||||
}])->withCount(['comments' => function (Query $query) {
|
||||
$query->where(['status' => 1, 'deleted' => 0]);
|
||||
}]);
|
||||
PointsMallGoods::mk()->where(['code' => $code])->inc('num_read')->update([]);
|
||||
} else {
|
||||
$query->with('discount')->withoutField('content');
|
||||
}
|
||||
// 数据排序处理
|
||||
$sort = intval(input('sort', 0));
|
||||
$type = intval(input('order', 0)) ? 'asc' : 'desc';
|
||||
if ($sort === 1) {
|
||||
$query->order("num_read {$type},sort {$type},id {$type}");
|
||||
} elseif ($sort === 2) {
|
||||
$query->order("price_selling {$type},sort {$type},id {$type}");
|
||||
} else {
|
||||
$query->order("sort {$type},id {$type}");
|
||||
}
|
||||
$query->where(['status' => 1, 'deleted' => 0]);
|
||||
// 查询数据分页
|
||||
$page = intval(input('page', 1));
|
||||
$limit = max(min(intval(input('limit', 20)), 60), 1);
|
||||
$this->success('获取商品数据', $query->page($page, false, false, $limit));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据结果处理
|
||||
* @param array $data
|
||||
* @param array $result
|
||||
* @return void
|
||||
*/
|
||||
protected function _get_page_filter(array &$data, array &$result)
|
||||
{
|
||||
$result['cnames'] = $this->cnames ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品分类及标签
|
||||
* @return void
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function cate()
|
||||
{
|
||||
$this->success('获取分类成功', [
|
||||
'cate' => PointsMallGoodsCate::dtree(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\controller\api\auth;
|
||||
|
||||
use plugin\points_mall\controller\api\Auth;
|
||||
use plugin\points_mall\model\PointsMallGoods;
|
||||
use plugin\points_mall\model\PointsMallGoodsItem;
|
||||
use plugin\points_mall\model\PointsMallOrderCart;
|
||||
use plugin\points_mall\service\UserActionService;
|
||||
use think\admin\helper\QueryHelper;
|
||||
use think\db\Query;
|
||||
|
||||
class Cart extends Auth
|
||||
{
|
||||
|
||||
/**
|
||||
* 获取购买车数据
|
||||
* @return void
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
PointsMallOrderCart::mQuery(null, function (QueryHelper $query) {
|
||||
$query->equal('ghash')->where(['unid' => $this->unid])->with([
|
||||
'goods' => static function (Query $query) {
|
||||
$query->with('items');
|
||||
},
|
||||
'specs' => static function (Query $query) {
|
||||
$query->withoutField('id,create_time,update_time');
|
||||
},
|
||||
]);
|
||||
$this->success('获取购买车数据!', $query->order('id desc')->page(false, false));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改购买车数据
|
||||
* @return void
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function set()
|
||||
{
|
||||
$data = $this->_vali([
|
||||
'unid.value' => $this->unid,
|
||||
'ghash.require' => '商品不能为空!',
|
||||
'number.require' => '数量不能为空!',
|
||||
]);
|
||||
// 清理数量0的记录
|
||||
$map = ['unid' => $this->unid, 'ghash' => $data['ghash']];
|
||||
if ($data['number'] < 1) {
|
||||
PointsMallOrderCart::mk()->where($map)->delete();
|
||||
UserActionService::recount($this->unid);
|
||||
$this->success('移除成功!');
|
||||
}
|
||||
// 检查商品是否存在
|
||||
$gspec = PointsMallGoodsItem::mk()->where(['ghash' => $data['ghash']])->findOrEmpty();
|
||||
$goods = PointsMallGoods::mk()->where(['code' => $gspec->getAttr('gcode')])->findOrEmpty();
|
||||
if ($goods->isEmpty() || $gspec->isEmpty()) $this->error('商品不存在!');
|
||||
// 保存商品数据
|
||||
$data += ['gcode' => $gspec['gcode'], 'gspec' => $gspec['gspec']];
|
||||
if (($cart = PointsMallOrderCart::mk()->where($map)->findOrEmpty())->save($data)) {
|
||||
UserActionService::recount($this->unid);
|
||||
$this->success('保存成功!', $cart->refresh()->toArray());
|
||||
} else {
|
||||
$this->error('保存失败!');
|
||||
}
|
||||
}
|
||||
}
|
509
plugs/think-plugs-points-mall/src/controller/api/auth/Order.php
Normal file
509
plugs/think-plugs-points-mall/src/controller/api/auth/Order.php
Normal file
@ -0,0 +1,509 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\controller\api\auth;
|
||||
|
||||
use plugin\points_mall\controller\api\Auth;
|
||||
use plugin\points_mall\model\PointsMallAddress;
|
||||
use plugin\points_mall\model\PointsMallOrder;
|
||||
use plugin\points_mall\model\PointsMallOrderCart;
|
||||
use plugin\points_mall\model\PointsMallOrderItem;
|
||||
use plugin\points_mall\service\GoodsService;
|
||||
use plugin\points_mall\service\UserActionService;
|
||||
use plugin\points_mall\service\UserOrderService;
|
||||
use plugin\points_mall\service\UserPointService;
|
||||
use think\admin\extend\CodeExtend;
|
||||
use think\admin\helper\QueryHelper;
|
||||
use think\db\Query;
|
||||
use think\exception\HttpResponseException;
|
||||
|
||||
class Order extends Auth
|
||||
{
|
||||
protected $checkBind = true;
|
||||
/**
|
||||
* 获取订单数据
|
||||
* @return void
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
PointsMallOrder::mQuery(null, function (QueryHelper $query) {
|
||||
if (empty(input('order_no'))) {
|
||||
$query->with('items')->where(['refund_status' => 0]);
|
||||
} else {
|
||||
$query->with(['items', 'address', 'sender', 'payments' => function (Query $query) {
|
||||
$query->where(static function (Query $query) {
|
||||
// $query->whereOr(['channel_type' => Payment::VOUCHER, 'payment_status' => 1, 'audit_status' => 1]);
|
||||
$query->whereOr(['payment_status' => 1, 'audit_status' => 1]);
|
||||
});
|
||||
}]);
|
||||
}
|
||||
$query->in('status')->equal('order_no');
|
||||
$query->where(['unid' => $this->unid, 'deleted_status' => 0])->order('id desc');
|
||||
$this->success('获取订单成功!', $query->page(intval(input('page')), false, false, 10));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建订单数据
|
||||
* @return void
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
try {
|
||||
// 请求参数检查
|
||||
$input = $this->_vali([
|
||||
'carts.default' => '',
|
||||
'rules.default' => '',
|
||||
'agent.default' => '0',
|
||||
]);
|
||||
if (empty($input['rules']) && empty($input['carts'])) $this->error('参数无效!');
|
||||
// 生成统一编号
|
||||
do $extra = ['order_no' => $order['order_no'] = CodeExtend::uniqidNumber(16, 'N')];
|
||||
while (PointsMallOrder::mk()->master()->where($extra)->findOrEmpty()->isExists());
|
||||
[$items, $deliveryType] = [[], 0];
|
||||
// 组装订单数据
|
||||
foreach (GoodsService::parse($this->unid, trim($input['rules'], ':;'), $input['carts']) as $item) {
|
||||
if (empty($item['count'])) continue;
|
||||
if (empty($item['goods']) || empty($item['specs'])) $this->error('商品无效!');
|
||||
[$goods, $gspec, $count] = [$item['goods'], $item['specs'], intval($item['count'])];
|
||||
// 订单物流类型
|
||||
if (empty($deliveryType) && $goods['delivery_code'] !== 'NONE') $deliveryType = 1;
|
||||
// 限制购买数量
|
||||
if (isset($goods['limit_maxnum']) && $goods['limit_maxnum'] > 0) {
|
||||
$join = [PointsMallOrderItem::mk()->getTable() => 'b'];
|
||||
$where = [['a.unid', '=', $this->unid], ['a.status', '>', 1], ['b.gcode', '=', $goods['code']]];
|
||||
$buyCount = PointsMallOrder::mk()->alias('a')->join($join, 'a.order_no=b.order_no')->where($where)->sum('b.stock_sales');
|
||||
if ($buyCount + $count > $goods['limit_maxnum']) $this->error('商品限购!');
|
||||
}
|
||||
// 限制购买身份
|
||||
// if ($goods['limit_lowvip'] > $this->levelCode) $this->error('等级不够!');
|
||||
// 商品库存检查
|
||||
if ($gspec['stock_sales'] + $count > $gspec['stock_total']) $this->error('库存不足!');
|
||||
// 订单详情处理
|
||||
$items[] = [
|
||||
'unid' => $order['unid'],
|
||||
'order_no' => $order['order_no'],
|
||||
// 商品字段
|
||||
'gsku' => $gspec['gsku'],
|
||||
'gname' => $goods['name'],
|
||||
'gcode' => $gspec['gcode'],
|
||||
'ghash' => $gspec['ghash'],
|
||||
'gspec' => $gspec['gspec'],
|
||||
'gunit' => $gspec['gunit'],
|
||||
'gcover' => empty($gspec['gimage']) ? $goods['cover'] : $gspec['gimage'],
|
||||
// 库存数量处理
|
||||
'stock_sales' => $count,
|
||||
// 快递发货数据
|
||||
'delivery_code' => $goods['delivery_code'],
|
||||
'delivery_count' => $goods['rebate_type'] > 0 ? $gspec['number_express'] * $count : 0,
|
||||
// 商品费用字段
|
||||
'price_cost' => $gspec['price_cost'],
|
||||
'price_market' => $gspec['price_market'],
|
||||
'price_selling' => $gspec['price_selling'],
|
||||
// 商品费用统计
|
||||
'total_price_cost' => $gspec['price_cost'] * $count,
|
||||
'total_price_market' => $gspec['price_market'] * $count,
|
||||
'total_price_selling' => $gspec['price_selling'] * $count,
|
||||
'total_allow_balance' => $gspec['allow_balance'] * $count,
|
||||
'total_allow_integral' => $gspec['allow_integral'] * $count,
|
||||
'total_reward_balance' => $gspec['reward_balance'] * $count,
|
||||
'total_reward_integral' => $gspec['reward_integral'] * $count,
|
||||
];
|
||||
}
|
||||
// 默认使用销售销售
|
||||
$order['rebate_amount'] = array_sum(array_column($items, 'rebate_amount'));
|
||||
$order['allow_balance'] = array_sum(array_column($items, 'total_allow_balance'));
|
||||
$order['allow_integral'] = array_sum(array_column($items, 'total_allow_integral'));
|
||||
$order['reward_balance'] = array_sum(array_column($items, 'total_reward_balance'));
|
||||
$order['reward_integral'] = array_sum(array_column($items, 'total_reward_integral'));
|
||||
// 会员及代理升级
|
||||
$order['level_agent'] = intval(max(array_column($items, 'level_agent')));
|
||||
$order['level_member'] = intval(max(array_column($items, 'level_upgrade')));
|
||||
// 订单发货类型
|
||||
$order['status'] = $deliveryType ? 1 : 2;
|
||||
$order['delivery_type'] = $deliveryType;
|
||||
$order['ratio_integral'] = 100;
|
||||
// 统计商品数量
|
||||
$order['number_goods'] = array_sum(array_column($items, 'stock_sales'));
|
||||
$order['number_express'] = array_sum(array_column($items, 'delivery_count'));
|
||||
// 统计商品金额
|
||||
$order['amount_cost'] = array_sum(array_column($items, 'total_price_cost'));
|
||||
$order['amount_goods'] = array_sum(array_column($items, 'total_price_selling'));
|
||||
// 折扣后的金额
|
||||
$order['amount_discount'] = array_sum(array_column($items, 'discount_amount'));
|
||||
$order['amount_reduct'] = $order['amount_goods'];
|
||||
// 统计订单金额
|
||||
$order['amount_real'] = round($order['amount_discount'] - $order['amount_reduct'], 2);
|
||||
$order['amount_total'] = $order['amount_goods'];
|
||||
$order['amount_profit'] = round($order['amount_real'] - $order['amount_cost']);
|
||||
// 写入商品数据
|
||||
$model = PointsMallOrder::mk();
|
||||
$this->app->db->transaction(function () use ($order, $items, &$model) {
|
||||
$model->save($order) && PointsMallOrderItem::mk()->saveAll($items);
|
||||
// 设置收货地址
|
||||
if ($order['delivery_type']) {
|
||||
$where = ['unid' => $this->unid, 'deleted' => 0];
|
||||
$address = PointsMallAddress::mk()->where($where)->order('type desc,id desc')->findOrEmpty();
|
||||
$address->isExists() && UserOrderService::perfect($model->refresh(), $address);
|
||||
}
|
||||
});
|
||||
// 同步库存销量
|
||||
foreach (array_unique(array_column($items, 'gcode')) as $gcode) {
|
||||
GoodsService::stock($gcode);
|
||||
}
|
||||
// 清理购物车数据
|
||||
if (count($carts = str2arr($input['carts'])) > 0) {
|
||||
PointsMallOrderCart::mk()->whereIn('id', $carts)->delete();
|
||||
UserActionService::recount($this->unid);
|
||||
}
|
||||
// 触发订单创建事件
|
||||
$this->app->event->trigger('PluginWemallOrderCreate', $order);
|
||||
// 无需发货且无需支付,直接完成支付流程
|
||||
if ($order['status'] === 2 && empty($order['amount_real'])) {
|
||||
$this->success('下单成功!', $model->toArray());
|
||||
}
|
||||
// 返回处理成功数据
|
||||
$this->success('下单成功!', array_merge($order, ['items' => $items]));
|
||||
} catch (HttpResponseException $exception) {
|
||||
throw $exception;
|
||||
} catch (\Exception $exception) {
|
||||
trace_file($exception);
|
||||
$this->error("下单失败,{$exception->getMessage()}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟计算运费
|
||||
* @return void
|
||||
* @throws \think\admin\Exception
|
||||
*/
|
||||
// public function express()
|
||||
// {
|
||||
// $data = $this->_vali([
|
||||
// 'unid.value' => $this->unid,
|
||||
// 'order_no.require' => '单号不能为空!',
|
||||
// 'address_id.require' => '地址不能为空!',
|
||||
// ]);
|
||||
//
|
||||
// // 用户收货地址
|
||||
// $map = ['unid' => $this->unid, 'id' => $data['address_id']];
|
||||
// $addr = PointsMallAddress::mk()->where($map)->findOrEmpty();
|
||||
// if ($addr->isEmpty()) $this->error('地址异常!');
|
||||
//
|
||||
// // 订单状态检查
|
||||
// $map = ['unid' => $this->unid, 'order_no' => $data['order_no']];
|
||||
// $tCount = intval(PointsMallOrderItem::mk()->where($map)->sum('delivery_count'));
|
||||
//
|
||||
// // 根据地址计算运费
|
||||
// $map = ['status' => 1, 'deleted' => 0, 'order_no' => $data['order_no']];
|
||||
// $tCode = PointsMallOrderItem::mk()->where($map)->column('delivery_code');
|
||||
// [$amount, , , $remark] = ExpressService::amount($tCode, $addr['region_prov'], $addr['region_city'], $tCount);
|
||||
// $this->success('计算运费!', ['amount' => $amount, 'remark' => $remark]);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 确认收货地址
|
||||
* @return void
|
||||
* @throws \think\admin\Exception
|
||||
*/
|
||||
public function perfect()
|
||||
{
|
||||
$data = $this->_vali([
|
||||
'unid.value' => $this->unid,
|
||||
'order_no.require' => '单号不能为空',
|
||||
'address_id.require' => '地址不能为空',
|
||||
]);
|
||||
|
||||
// 用户收货地址
|
||||
$where = ['id' => $data['address_id'], 'unid' => $this->unid, 'deleted' => 0];
|
||||
$address = PointsMallAddress::mk()->where($where)->findOrEmpty();
|
||||
if ($address->isEmpty()) $this->error('地址异常!');
|
||||
|
||||
// 订单状态检查
|
||||
$where = ['unid' => $this->unid, 'order_no' => $data['order_no'], 'delivery_type' => 1];
|
||||
$order = PointsMallOrder::mk()->where($where)->whereIn('status', [1, 2])->findOrEmpty();
|
||||
if ($order->isEmpty()) $this->error('不能修改!');
|
||||
|
||||
// 更新订单收货地址
|
||||
if (UserOrderService::perfect($order, $address)) {
|
||||
$this->success('确认成功!', $order->refresh()->toArray());
|
||||
} else {
|
||||
$this->error('确认失败!');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支付通道
|
||||
* @return void
|
||||
* @throws \think\admin\Exception
|
||||
*/
|
||||
// public function channel()
|
||||
// {
|
||||
// $this->success('获取支付通道!', [
|
||||
// 'toratio' => Integral::ratio(),
|
||||
// 'channels' => Payment::typesByAccess($this->type, true),
|
||||
// ]);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 获取支付参数
|
||||
* @return void
|
||||
*/
|
||||
public function payment()
|
||||
{
|
||||
$data = $this->_vali([
|
||||
'unid.value' => $this->unid,
|
||||
'balance.default' => '0.00',
|
||||
'integral.default' => '0',
|
||||
'order_no.require' => '单号不能为空',
|
||||
'order_ps.default' => '',
|
||||
'coupon_code.default' => '', # 优惠券编号
|
||||
'channel_code.require' => '支付不能为空',
|
||||
'payment_back.default' => '', # 支付回跳地址
|
||||
'payment_image.default' => '', # 支付凭证图片
|
||||
]);
|
||||
try {
|
||||
$order = $this->getOrderModel();
|
||||
$status = intval($order->getAttr('status'));
|
||||
if ($status > 3) $this->success('已完成支付!');
|
||||
if ($status === 3) $this->error('凭证待审核!');
|
||||
if ($status !== 2) $this->error('不能发起支付!');
|
||||
|
||||
// 订单备注内容更新
|
||||
empty($data['order_ps']) || $order->save(['order_ps' => $data['order_ps']]);
|
||||
|
||||
// 无需支付,直接完成订单
|
||||
if (floatval($orderAmount = $order->getAttr('amount_real')) <= 0) {
|
||||
$order->save(['status' => 4]);
|
||||
$this->success('已支付成功!', []);
|
||||
}
|
||||
|
||||
$leaveAmount = $orderAmount;
|
||||
// 剩余支付金额
|
||||
// if (($leaveAmount = Payment::leaveAmount($data['order_no'], $orderAmount)) <= 0) {
|
||||
// $this->success('已完成支付!', PaymentResponse::mk(true, '已完成支付!')->toArray());
|
||||
// }
|
||||
|
||||
// 扣除优惠券
|
||||
// if (!empty($data['coupon_code']) && $data['coupon_code'] !== $order->getAttr('coupon_code')) try {
|
||||
// // 检查优惠券是否有效
|
||||
//// $where = ['unid' => $this->unid, 'status' => 1, 'deleted' => 0];
|
||||
//// $coupon = PluginWemallUserCoupon::mk()->where($where)->with('bindCoupon')->findOrEmpty();
|
||||
//// if ($coupon->isEmpty() || empty($coupon->getAttr('coupon_status')) || $coupon->getAttr('coupon_deleted') > 0) {
|
||||
//// $this->error('无限优惠券!');
|
||||
//// }
|
||||
//// if ($coupon->getAttr('expire') > 0 && $coupon->getAttr('expire') < time()) $this->error('优惠券无效!');
|
||||
//// if (floatval($coupon->getAttr('limit_amount')) <= $orderAmount) $this->error('未达到使用条件!');
|
||||
//// [$couponCode, $couponAmount] = [strval($coupon->getAttr('code')), strval($coupon->getAttr('coupon_amount'))];
|
||||
//// $response = Payment::mk(Payment::COUPON)->create($this->account, $data['order_no'], '优惠券抵扣', $orderAmount, $couponAmount, '', '', '', $couponCode);
|
||||
//// $order->save(['coupon_code' => $couponCode, 'coupon_amount' => $couponAmount]);
|
||||
//// $coupon->save(['used' => 1, 'status' => 2, 'used_time' => date('Y-m-d H:i:s')]);
|
||||
//// if (($leaveAmount = Payment::leaveAmount($data['order_no'], $orderAmount)) <= 0) $this->success('已完成支付!', $response->toArray());
|
||||
// } catch (HttpResponseException $exception) {
|
||||
// throw $exception;
|
||||
// } catch (\Exception $exception) {
|
||||
// $this->error($exception->getMessage());
|
||||
// }
|
||||
|
||||
// 积分抵扣处理
|
||||
// if ($leaveAmount > 0 && $data['integral'] > 0) {
|
||||
// if ($data['integral'] > $order->getAttr('allow_integral')) $this->error("超出积分抵扣!");
|
||||
// if ($data['integral'] > Integral::recount($this->unid)['usable']) $this->error('账号积分不足!');
|
||||
// $response = Payment::mk(payment::INTEGRAL)->create($this->account, $data['order_no'], '账号积分抵扣', $orderAmount, $data['integral']);
|
||||
// if (($leaveAmount = Payment::leaveAmount($data['order_no'], $orderAmount)) <= 0) $this->success('已完成支付!', $response->toArray());
|
||||
// }
|
||||
$userPoint = UserPointService::getUserPoint($this->unid);
|
||||
if ($userPoint['point'] < $leaveAmount) {
|
||||
$this->error("积分不足!");
|
||||
} else {
|
||||
$order->save(['status' => 4]);
|
||||
UserPointService::addUserPoint($this->unid, -$leaveAmount, '积分购买商品抵扣');
|
||||
$this->success('积分抵扣成功!', []);
|
||||
}
|
||||
|
||||
// 余额支付扣减
|
||||
// if ($leaveAmount > 0 && $data['balance'] > 0) {
|
||||
// if ($data['balance'] > $order->getAttr('allow_balance')) $this->error("超出余额限额!");
|
||||
// if ($data['balance'] > Balance::recount($this->unid)['usable']) $this->error('账号余额不足!');
|
||||
// $response = Payment::mk(Payment::BALANCE)->create($this->account, $data['order_no'], '账号余额支付!', $orderAmount, $data['balance']);
|
||||
// if (($leaveAmount = Payment::leaveAmount($data['order_no'], $orderAmount)) <= 0) $this->success('已完成支付!', $response->toArray());
|
||||
// }
|
||||
|
||||
// 凭证图片保存
|
||||
// if (!empty($data['payment_image'])) {
|
||||
// $data['payment_image'] = Storage::saveImage($data['payment_image'])['url'] ?? '';
|
||||
// }
|
||||
|
||||
// 创建支付订单
|
||||
// $response = Payment::mk($data['channel_code'])->create(
|
||||
// $this->account, $data['order_no'], '商城订单支付',
|
||||
// $orderAmount, strval($leaveAmount), '', $data['payment_back'], $data['payment_image']
|
||||
// );
|
||||
|
||||
// 标准化返回结果
|
||||
// if ($response->status) {
|
||||
// $this->success($response->message, $response->toArray());
|
||||
// } else {
|
||||
// $this->error($response->message, $response->toArray());
|
||||
// }
|
||||
} catch (HttpResponseException $exception) {
|
||||
throw $exception;
|
||||
} catch (\Exception $exception) {
|
||||
trace_file($exception);
|
||||
$this->error($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消未支付订单
|
||||
* @return void
|
||||
* @throws \think\admin\Exception
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function cancel()
|
||||
{
|
||||
$order = $this->getOrderModel();
|
||||
if (in_array($order->getAttr('status'), [1, 2, 3])) {
|
||||
$data = [
|
||||
'status' => 0,
|
||||
'cancel_time' => date('Y-m-d H:i:s'),
|
||||
'cancel_status' => 1,
|
||||
'cancel_remark' => '用户主动取消订单!',
|
||||
];
|
||||
if ($order->save($data) && UserOrderService::stock($order->getAttr('order_no'))) {
|
||||
// 触发订单取消事件
|
||||
Payment::refund($order->getAttr('order_no'));
|
||||
$this->app->event->trigger('PluginWemallOrderCancel', $order);
|
||||
// 返回处理成功数据
|
||||
$this->success('取消成功!');
|
||||
} else {
|
||||
$this->error('取消失败!');
|
||||
}
|
||||
} else {
|
||||
$this->error('不可取消!');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除已取消订单
|
||||
* @return void
|
||||
*/
|
||||
public function remove()
|
||||
{
|
||||
$order = $this->getOrderModel();
|
||||
if ($order->isEmpty()) $this->error('读取订单失败!');
|
||||
if ($order->getAttr('status') == 0) {
|
||||
if ($order->save([
|
||||
'status' => 0,
|
||||
'deleted_time' => date('Y-m-d H:i:s'),
|
||||
'deleted_status' => 1,
|
||||
'deleted_remark' => '用户主动删除订单!',
|
||||
])) {
|
||||
// 触发订单删除事件
|
||||
$this->app->event->trigger('PluginWemallOrderRemove', $order);
|
||||
// 返回处理成功数据
|
||||
$this->success('删除成功!');
|
||||
} else {
|
||||
$this->error('删除失败!');
|
||||
}
|
||||
} else {
|
||||
$this->error('不可删除!');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单确认收货
|
||||
* @return void
|
||||
*/
|
||||
public function confirm()
|
||||
{
|
||||
$order = $this->getOrderModel();
|
||||
if (in_array($order->getAttr('status'), [5, 6])) {
|
||||
// 触发订单确认事件
|
||||
$order->save([
|
||||
'status' => 6,
|
||||
'confirm_time' => date('Y-m-d H:i:s'),
|
||||
'confirm_remark' => '用户主动确认签收订单!',
|
||||
]);
|
||||
$this->app->event->trigger('PluginWemallOrderConfirm', $order);
|
||||
// 返回处理成功数据
|
||||
$this->success('确认成功!');
|
||||
} else {
|
||||
$this->error('确认失败!');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交订单评论
|
||||
* @return void
|
||||
*/
|
||||
// public function comment()
|
||||
// {
|
||||
// $order = $this->getOrderModel();
|
||||
// if (in_array($order->getAttr('status'), [6, 7])) try {
|
||||
// // 接收评论数据
|
||||
// $items = json_decode($this->request->post('data'), true);
|
||||
// $this->app->db->transaction(function () use ($order, $items) {
|
||||
// $order->save(['status' => 7]);
|
||||
// $order->items()->select()->map(function (PointsMallOrderItem $item) use ($items) {
|
||||
// if (!empty($input = $items[$item->getAttr('ghash')])) {
|
||||
// UserAction::comment($item, $input['rate'], $input['content'], $input['images']);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// $this->success('评论成功!');
|
||||
// } catch (HttpResponseException $exception) {
|
||||
// throw $exception;
|
||||
// } catch (\Exception $exception) {
|
||||
// $this->error($exception->getMessage());
|
||||
// } else {
|
||||
// $this->error('无需评论!');
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 订单状态统计
|
||||
* @return void
|
||||
*/
|
||||
public function total()
|
||||
{
|
||||
$data = ['t0' => 0, 't1' => 0, 't2' => 0, 't3' => 0, 't4' => 0, 't5' => 0, 't6' => 0, 't7' => 0];
|
||||
$query = PointsMallOrder::mk()->where(['unid' => $this->unid, 'refund_status' => 0, 'deleted_status' => 0]);
|
||||
foreach ($query->field('status,count(1) count')->group('status')->cursor() as $item) {
|
||||
$data["t{$item['status']}"] = $item['count'];
|
||||
}
|
||||
$this->success('获取统计!', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 物流追踪查询
|
||||
* @return void
|
||||
*/
|
||||
// public function track()
|
||||
// {
|
||||
// try {
|
||||
// $data = $this->_vali([
|
||||
// 'code.require' => '快递不能为空', 'number.require' => '单号不能为空'
|
||||
// ]);
|
||||
// $result = ExpressService::query($data['code'], $data['number']);
|
||||
// empty($result['code']) ? $this->error($result['info']) : $this->success('快递追踪!', $result);
|
||||
// } catch (HttpResponseException $exception) {
|
||||
// throw $exception;
|
||||
// } catch (\Exception $exception) {
|
||||
// $this->error($exception->getMessage());
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 获取输入订单模型
|
||||
* @return PointsMallOrder
|
||||
*/
|
||||
private function getOrderModel(): PointsMallOrder
|
||||
{
|
||||
$map = $this->_vali(['unid.value' => $this->unid, 'order_no.require' => '单号不能为空']);
|
||||
$order = PointsMallOrder::mk()->where($map)->findOrEmpty();
|
||||
if ($order->isEmpty()) $this->error('读取订单失败!');
|
||||
return $order;
|
||||
}
|
||||
}
|
46
plugs/think-plugs-points-mall/src/helper.php
Normal file
46
plugs/think-plugs-points-mall/src/helper.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | WeMall Plugin for ThinkAdmin
|
||||
// +----------------------------------------------------------------------
|
||||
// | 版权所有 2022~2024 ThinkAdmin [ thinkadmin.top ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网站: https://thinkadmin.top
|
||||
// +----------------------------------------------------------------------
|
||||
// | 免责声明 ( https://thinkadmin.top/disclaimer )
|
||||
// | 会员免费 ( https://thinkadmin.top/vip-introduce )
|
||||
// +----------------------------------------------------------------------
|
||||
// | gitee 代码仓库:https://gitee.com/zoujingli/think-plugs-wemall
|
||||
// | github 代码仓库:https://github.com/zoujingli/think-plugs-wemall
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
declare (strict_types=1);
|
||||
|
||||
if (!function_exists('show_gspec')) {
|
||||
/**
|
||||
* 商品规格过滤显示
|
||||
* @param string $spec 原规格内容
|
||||
* @return string
|
||||
*/
|
||||
function show_gspec(string $spec): string
|
||||
{
|
||||
$specs = [];
|
||||
foreach (explode(';;', $spec) as $sp) {
|
||||
$specs[] = explode('::', $sp)[1];
|
||||
}
|
||||
return join(' ', $specs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!function_exists('formatdate')) {
|
||||
/**
|
||||
* 日期格式过滤
|
||||
* @param string|null $value
|
||||
* @return string|null
|
||||
*/
|
||||
function formatdate(?string $value): ?string
|
||||
{
|
||||
return is_string($value) ? str_replace(['年', '月', '日'], ['-', '-', ''], $value) : $value;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\model;
|
||||
|
||||
use think\admin\Model;
|
||||
|
||||
class PointsMallAddress extends Model
|
||||
{
|
||||
|
||||
}
|
90
plugs/think-plugs-points-mall/src/model/PointsMallGoods.php
Normal file
90
plugs/think-plugs-points-mall/src/model/PointsMallGoods.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\model;
|
||||
|
||||
use think\admin\Model;
|
||||
|
||||
class PointsMallGoods extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* 日志名称
|
||||
* @var string
|
||||
*/
|
||||
protected $oplogName = '商品';
|
||||
|
||||
/**
|
||||
* 日志类型
|
||||
* @var string
|
||||
*/
|
||||
protected $oplogType = '分销商城管理';
|
||||
|
||||
/**
|
||||
* 关联产品规格
|
||||
* @return \think\model\relation\HasMany
|
||||
*/
|
||||
public function items()
|
||||
{
|
||||
return static::mk()
|
||||
->hasMany(PointsMallGoodsItem::class, 'gcode', 'code')
|
||||
->withoutField('id,status,create_time,update_time')
|
||||
->where(['status' => 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联商品评论数据
|
||||
* @return \think\model\relation\HasMany
|
||||
*/
|
||||
public function comments()
|
||||
{
|
||||
return $this->hasMany(PluginWemallUserActionComment::class, 'gcode', 'code')->with('bindUser');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联产品列表
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function lists(): array
|
||||
{
|
||||
$model = static::mk()->with('items')->withoutField('specs');
|
||||
return $model->order('sort desc,id desc')->where(['deleted' => 0])->select()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理商品分类数据
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
public function getCatesAttr($value): array
|
||||
{
|
||||
$ckey = 'PointsMallGoodsCateItem';
|
||||
$cates = sysvar($ckey) ?: sysvar($ckey, PointsMallGoodsCate::items(true));
|
||||
$cateids = is_string($value) ? str2arr($value) : (array)$value;
|
||||
foreach ($cates as $cate) if (in_array($cate['id'], $cateids)) return $cate;
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置轮播图片
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function setSliderAttr($value): string
|
||||
{
|
||||
return is_string($value) ? $value : (is_array($value) ? arr2str($value) : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取轮播图片
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
public function getSliderAttr($value): array
|
||||
{
|
||||
return is_string($value) ? str2arr($value, '|') : [];
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\model;
|
||||
|
||||
use think\admin\extend\DataExtend;
|
||||
use think\admin\Model;
|
||||
|
||||
class PointsMallGoodsCate extends Model
|
||||
{
|
||||
/**
|
||||
* 获取上级可用选项
|
||||
* @param int $max 最大级别
|
||||
* @param array $data 表单数据
|
||||
* @param array $parent 上级分类
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function pdata(int $max, array &$data, array $parent = []): array
|
||||
{
|
||||
$items = static::mk()->where(['deleted' => 0])->order('sort desc,id asc')->select()->toArray();
|
||||
$cates = DataExtend::arr2table(empty($parent) ? $items : array_merge([$parent], $items));
|
||||
if (isset($data['id'])) foreach ($cates as $cate) if ($cate['id'] === $data['id']) $data = $cate;
|
||||
foreach ($cates as $key => $cate) {
|
||||
$isSelf = isset($data['spt']) && isset($data['spc']) && $data['spt'] <= $cate['spt'] && $data['spc'] > 0;
|
||||
if ($cate['spt'] >= $max || $isSelf) unset($cates[$key]);
|
||||
}
|
||||
return $cates;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据树
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function dtree(): array
|
||||
{
|
||||
$query = static::mk()->where(['status' => 1, 'deleted' => 0])->order('sort desc,id desc');
|
||||
return DataExtend::arr2tree($query->withoutField('sort,status,deleted,create_time')->select()->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表数据
|
||||
* @param bool $simple 仅子级别
|
||||
* @return array
|
||||
*/
|
||||
public static function items(bool $simple = false): array
|
||||
{
|
||||
$query = static::mk()->where(['status' => 1, 'deleted' => 0])->order('sort desc,id asc');
|
||||
$cates = array_column(DataExtend::arr2table($query->column('id,pid,name', 'id')), null, 'id');
|
||||
foreach ($cates as $cate) isset($cates[$cate['pid']]) && $cates[$cate['id']]['parent'] =& $cates[$cate['pid']];
|
||||
foreach ($cates as $key => $cate) {
|
||||
$id = $cate['id'];
|
||||
$cates[$id]['ids'][] = $cate['id'];
|
||||
$cates[$id]['names'][] = $cate['name'];
|
||||
while (isset($cate['parent']) && ($cate = $cate['parent'])) {
|
||||
$cates[$id]['ids'][] = $cate['id'];
|
||||
$cates[$id]['names'][] = $cate['name'];
|
||||
}
|
||||
$cates[$id]['ids'] = array_reverse($cates[$id]['ids']);
|
||||
$cates[$id]['names'] = array_reverse($cates[$id]['names']);
|
||||
if (isset($pky) && $simple && in_array($cates[$pky]['name'], $cates[$id]['names'])) {
|
||||
unset($cates[$pky]);
|
||||
}
|
||||
$pky = $key;
|
||||
}
|
||||
foreach ($cates as &$cate) {
|
||||
unset($cate['sps'], $cate['parent']);
|
||||
}
|
||||
return array_values($cates);
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\model;
|
||||
|
||||
use think\admin\Model;
|
||||
|
||||
class PointsMallGoodsItem extends Model
|
||||
{
|
||||
/**
|
||||
* 关联商品信息
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function goods()
|
||||
{
|
||||
return $this->hasOne(PointsMallGoods::class, 'code', 'gcode');
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定商品信息
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function bindGoods()
|
||||
{
|
||||
return $this->goods()->bind([
|
||||
'gname' => 'name',
|
||||
'gcover' => 'cover',
|
||||
'gstatus' => 'status',
|
||||
'gdeleted' => 'deleted'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品规格JSON数据
|
||||
* @param string $code
|
||||
* @return string
|
||||
*/
|
||||
public static function itemsJson(string $code): string
|
||||
{
|
||||
return json_encode(self::itemsArray($code), 64 | 256);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品规格数组
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
public static function itemsArray(string $code): array
|
||||
{
|
||||
return self::mk()->where(['gcode' => $code])->column([
|
||||
'gsku' => 'gsku',
|
||||
'ghash' => 'hash',
|
||||
'gspec' => 'spec',
|
||||
'gcode' => 'gcode',
|
||||
'gimage' => 'image',
|
||||
'status' => 'status',
|
||||
'price_cost' => 'cost',
|
||||
'price_market' => 'market',
|
||||
'price_selling' => 'selling',
|
||||
'allow_balance' => 'allow_balance',
|
||||
'allow_integral' => 'allow_integral',
|
||||
'number_virtual' => 'virtual',
|
||||
'number_express' => 'express',
|
||||
'reward_balance' => 'balance',
|
||||
'reward_integral' => 'integral',
|
||||
], 'ghash');
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\model;
|
||||
|
||||
use think\admin\Model;
|
||||
|
||||
class PointsMallGoodsStock extends Model
|
||||
{
|
||||
|
||||
}
|
97
plugs/think-plugs-points-mall/src/model/PointsMallOrder.php
Normal file
97
plugs/think-plugs-points-mall/src/model/PointsMallOrder.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\model;
|
||||
|
||||
use plugin\account\model\PluginAccountUser;
|
||||
use think\admin\Model;
|
||||
|
||||
class PointsMallOrder extends Model
|
||||
{
|
||||
/**
|
||||
* 关联推荐用户
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function from()
|
||||
{
|
||||
return $this->hasOne(PluginAccountUser::class, 'id', 'puid1');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联商品数据
|
||||
* @return \think\model\relation\HasMany
|
||||
*/
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany(PointsMallOrderItem::class, 'order_no', 'order_no');
|
||||
}
|
||||
//
|
||||
// /**
|
||||
// * 关联支付数据
|
||||
// * @return \think\model\relation\HasOne
|
||||
// */
|
||||
// public function payment()
|
||||
// {
|
||||
// return $this->hasOne(PluginPaymentRecord::class, 'order_no', 'order_no')->where([
|
||||
// 'payment_status' => 1,
|
||||
// ]);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 关联支付记录
|
||||
// * @return \think\model\relation\HasMany
|
||||
// */
|
||||
// public function payments()
|
||||
// {
|
||||
// return $this->hasMany(PluginPaymentRecord::class, 'order_no', 'order_no')->order('id desc')->withoutField('payment_notify');
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 关联收货地址
|
||||
// * @return \think\model\relation\HasOne
|
||||
// */
|
||||
// public function address()
|
||||
// {
|
||||
// return $this->hasOne(PluginWemallOrderSender::class, 'order_no', 'order_no');
|
||||
// }
|
||||
|
||||
/**
|
||||
* 格式化支付通道
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
public function getPaymentAllowsAttr($value): array
|
||||
{
|
||||
$payments = is_string($value) ? str2arr($value) : [];
|
||||
return in_array('all', $payments) ? ['all'] : $payments;
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间格式处理
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function getPaymentTimeAttr($value): string
|
||||
{
|
||||
return $this->getCreateTimeAttr($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间格式处理
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function setPaymentTimeAttr($value): string
|
||||
{
|
||||
return $this->setCreateTimeAttr($value);
|
||||
}
|
||||
|
||||
public function setConfirmTimeAttr($value): string
|
||||
{
|
||||
return $this->setCreateTimeAttr($value);
|
||||
}
|
||||
|
||||
public function getConfirmTimeAttr($value): string
|
||||
{
|
||||
return $this->getCreateTimeAttr($value);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\model;
|
||||
|
||||
use think\admin\Model;
|
||||
|
||||
class PointsMallOrderCart extends Model
|
||||
{
|
||||
/**
|
||||
* 关联产品数据
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function goods()
|
||||
{
|
||||
return $this->hasOne(PointsMallGoods::class, 'code', 'gcode');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联规格数据
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function specs()
|
||||
{
|
||||
return $this->hasOne(PointsMallGoodsItem::class, 'ghash', 'ghash');
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\model;
|
||||
|
||||
use think\admin\Model;
|
||||
|
||||
class PointsMallOrderItem extends Model
|
||||
{
|
||||
/**
|
||||
* 关联订单信息
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function main()
|
||||
{
|
||||
return $this->hasOne(PointsMallOrder::class, 'order_no', 'order_no');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联商品信息
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function goods()
|
||||
{
|
||||
return $this->hasOne(PointsMallGoods::class, 'code', 'gcode');
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\model;
|
||||
|
||||
use think\admin\Model;
|
||||
|
||||
class PointsMallOrderSender extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* 关联订单数据
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function main()
|
||||
{
|
||||
return $this->hasOne(PointsMallOrder::class, 'order_no', 'order_no')->with(['items']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置发货时间
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function setExpressTimeAttr($value): string
|
||||
{
|
||||
return $this->setCreateTimeAttr($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取发货时间
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function getExpressTimeAttr($value): string
|
||||
{
|
||||
return $this->getCreateTimeAttr($value);
|
||||
}
|
||||
}
|
122
plugs/think-plugs-points-mall/src/service/GoodsService.php
Normal file
122
plugs/think-plugs-points-mall/src/service/GoodsService.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\service;
|
||||
|
||||
use Exception;
|
||||
use plugin\points_mall\model\PointsMallGoodsStock;
|
||||
use plugin\points_mall\model\PointsMallGoods;
|
||||
use plugin\points_mall\model\PointsMallGoodsItem;
|
||||
use plugin\points_mall\model\PointsMallOrder;
|
||||
use plugin\points_mall\model\PointsMallOrderCart;
|
||||
use plugin\points_mall\model\PointsMallOrderItem;
|
||||
|
||||
/**
|
||||
* 商品数据服务
|
||||
* @class GoodsService
|
||||
* @package plugin\points_mall\service
|
||||
*/
|
||||
class GoodsService
|
||||
{
|
||||
/**
|
||||
* 更新商品库存数据
|
||||
* @param string $code
|
||||
* @return boolean
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function stock(string $code): bool
|
||||
{
|
||||
// 入库统计
|
||||
$query = PointsMallGoodsStock::mk()->field('ghash,ifnull(sum(gstock),0) stock_total');
|
||||
$stockList = $query->where(['gcode' => $code])->group('gcode,ghash')->select()->toArray();
|
||||
// 销量统计
|
||||
$query = PointsMallOrder::mk()->alias('a')->field('b.ghash,ifnull(sum(b.stock_sales),0) stock_sales');
|
||||
$query->join([PointsMallOrderItem::mk()->getTable() => 'b'], 'a.order_no=b.order_no', 'left');
|
||||
$query->where([['b.gcode', '=', $code], ['a.status', '>', 0], ['a.deleted_status', '=', 0]]);
|
||||
$salesList = $query->group('b.ghash')->select()->toArray();
|
||||
// 组装数据
|
||||
$items = [];
|
||||
foreach (array_merge($stockList, $salesList) as $vo) {
|
||||
$key = $vo['ghash'];
|
||||
$items[$key] = array_merge($items[$key] ?? [], $vo);
|
||||
if (empty($items[$key]['stock_sales'])) $items[$key]['stock_sales'] = 0;
|
||||
if (empty($items[$key]['stock_total'])) $items[$key]['stock_total'] = 0;
|
||||
}
|
||||
unset($salesList, $stockList);
|
||||
// 更新商品规格销量及库存
|
||||
foreach ($items as $hash => $item) {
|
||||
PointsMallGoodsItem::mk()->where(['ghash' => $hash])->update([
|
||||
'stock_total' => $item['stock_total'], 'stock_sales' => $item['stock_sales']
|
||||
]);
|
||||
}
|
||||
// 更新商品主体销量及库存
|
||||
PointsMallGoods::mk()->where(['code' => $code])->update([
|
||||
'stock_total' => intval(array_sum(array_column($items, 'stock_total'))),
|
||||
'stock_sales' => intval(array_sum(array_column($items, 'stock_sales'))),
|
||||
'stock_virtual' => PointsMallGoodsItem::mk()->where(['gcode' => $code])->sum('number_virtual'),
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析下单数据
|
||||
* @param integer $unid 用户编号
|
||||
* @param string $rules 直接下单
|
||||
* @param string $carts 购物车下单
|
||||
* @return array
|
||||
* @throws \think\admin\Exception
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function parse(int $unid, string $rules, string $carts): array
|
||||
{
|
||||
// 读取商品数据
|
||||
[$lines, $carts] = [[], str2arr($carts)];
|
||||
if (!empty($carts)) {
|
||||
$where = [['unid', '=', $unid], ['id', 'in', $carts]];
|
||||
$field = ['ghash' => 'ghash', 'gcode' => 'gcode', 'gspec' => 'gspec', 'number' => 'count'];
|
||||
PointsMallOrderCart::mk()->field($field)->where($where)->with([
|
||||
'goods' => function ($query) {
|
||||
$query->where(['status' => 1, 'deleted' => 0]);
|
||||
$query->withoutField(['specs', 'content', 'status', 'deleted', 'create_time', 'update_time']);
|
||||
},
|
||||
'specs' => function ($query) {
|
||||
$query->where(['status' => 1]);
|
||||
$query->withoutField(['status', 'create_time', 'update_time']);
|
||||
}
|
||||
])->select()->each(function (Model $model) use (&$lines) {
|
||||
if (isset($lines[$ghash = $model->getAttr('ghash')])) {
|
||||
$lines[$ghash]['count'] += $model->getAttr('count');
|
||||
} else {
|
||||
$lines[$ghash] = $model->toArray();
|
||||
}
|
||||
});
|
||||
} elseif (!empty($rules)) {
|
||||
foreach (explode(';', $rules) as $rule) {
|
||||
[$ghash, $count] = explode(':', "{$rule}:1");
|
||||
if (isset($lines[$ghash])) {
|
||||
$lines[$ghash]['count'] += $count;
|
||||
} else {
|
||||
$lines[$ghash] = ['ghash' => $ghash, 'gcode' => '', 'gspec' => '', 'count' => $count];
|
||||
}
|
||||
}
|
||||
// 读取规格数据
|
||||
$map1 = [['status', '=', 1], ['ghash', 'in', array_column($lines, 'ghash')]];
|
||||
foreach (PointsMallGoodsItem::mk()->where($map1)->select()->toArray() as $item) {
|
||||
foreach ($lines as &$line) if ($line['ghash'] === $item['ghash']) {
|
||||
[$line['gcode'], $line['gspec'], $line['specs']] = [$item['gcode'], $item['gspec'], $item];
|
||||
}
|
||||
}
|
||||
// 读取商品数据
|
||||
$map2 = [['status', '=', 1], ['deleted', '=', 0], ['code', 'in', array_unique(array_column($lines, 'gcode'))]];
|
||||
foreach (PointsMallGoods::mk()->where($map2)->withoutField(['specs', 'content'])->select()->toArray() as $goods) {
|
||||
foreach ($lines as &$line) if ($line['gcode'] === $goods['code']) $line['goods'] = $goods;
|
||||
}
|
||||
} else {
|
||||
throw new Exception('无效参数数据!');
|
||||
}
|
||||
return array_values($lines);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\service;
|
||||
|
||||
use plugin\account\model\PluginAccountUser;
|
||||
use plugin\points_mall\model\PointsMallOrderCart;
|
||||
|
||||
class UserActionService
|
||||
{
|
||||
/**
|
||||
* 刷新用户行为统计
|
||||
* @param integer $unid 用户编号
|
||||
* @param array|null $data 非数组时更新数据
|
||||
* @return array [collect, history, mycarts]
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public static function recount(int $unid, ?array &$data = null): array
|
||||
{
|
||||
$isUpdate = !is_array($data);
|
||||
if ($isUpdate) $data = [];
|
||||
// 更新收藏及足迹数量和购物车
|
||||
$map = ['unid' => $unid];
|
||||
$data['mycarts_total'] = PointsMallOrderCart::mk()->where($map)->sum('number');
|
||||
if ($isUpdate && ($user = PluginAccountUser::mk()->findOrEmpty($unid))->isExists()) {
|
||||
$user->save(['extra' => array_merge($user->getAttr('extra'), $data)]);
|
||||
}
|
||||
return [$data['collect_total'], $data['history_total'], $data['mycarts_total']];
|
||||
}
|
||||
}
|
152
plugs/think-plugs-points-mall/src/service/UserOrderService.php
Normal file
152
plugs/think-plugs-points-mall/src/service/UserOrderService.php
Normal file
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\points_mall\service;
|
||||
|
||||
use Exception;
|
||||
use plugin\points_mall\model\PointsMallOrder;
|
||||
use plugin\points_mall\model\PointsMallOrderItem;
|
||||
use plugin\points_mall\model\PointsMallOrderSender;
|
||||
use think\admin\Library;
|
||||
|
||||
class UserOrderService
|
||||
{
|
||||
/**
|
||||
* 同步订单关联商品的库存
|
||||
* @param string $orderNo 订单编号
|
||||
* @return boolean
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function stock(string $orderNo): bool
|
||||
{
|
||||
$map = ['order_no' => $orderNo];
|
||||
$codes = PointsMallOrderItem::mk()->where($map)->column('gcode');
|
||||
foreach (array_unique($codes) as $code) GoodsService::stock($code);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单模型
|
||||
* @param PointsMallOrder|string $order
|
||||
* @param ?integer $unid 动态绑定变量
|
||||
* @param ?string $orderNo 动态绑定变量
|
||||
* @return PointsMallOrder
|
||||
* @throws \think\admin\Exception
|
||||
*/
|
||||
public static function widthOrder($order, ?int &$unid = 0, ?string &$orderNo = '')
|
||||
{
|
||||
if (is_string($order)) {
|
||||
$order = PointsMallOrder::mk()->where(['order_no' => $order])->findOrEmpty();
|
||||
}
|
||||
if ($order instanceof PointsMallOrder) {
|
||||
[$unid, $orderNo] = [intval($order->getAttr('unid')), $order->getAttr('order_no')];
|
||||
return $order;
|
||||
}
|
||||
throw new Exception("无效订单对象!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新订单支付状态
|
||||
* @param PluginWemallOrder|string $order 订单模型
|
||||
* @param PluginPaymentRecord $payment 支付行为记录
|
||||
* @return array|bool|string|void|null
|
||||
* @throws \think\admin\Exception
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @remark 订单状态(0已取消,1预订单,2待支付,3待审核,4待发货,5已发货,6已收货,7已评论)
|
||||
*/
|
||||
public static function change($order, PluginPaymentRecord $payment)
|
||||
{
|
||||
$order = self::widthOrder($order);
|
||||
if ($order->isEmpty()) return null;
|
||||
|
||||
// 同步订单支付统计
|
||||
$ptotal = Payment::totalPaymentAmount($payment->getAttr('order_no'));
|
||||
$order->appendData([
|
||||
'payment_time' => $payment->getAttr('create_time'),
|
||||
'payment_amount' => $ptotal['amount'] ?? 0,
|
||||
'amount_payment' => $ptotal['payment'] ?? 0,
|
||||
'amount_balance' => $ptotal['balance'] ?? 0,
|
||||
'amount_integral' => $ptotal['integral'] ?? 0,
|
||||
], true);
|
||||
|
||||
// 订单已经支付完成
|
||||
if ($order->getAttr('payment_amount') >= $order->getAttr('amount_real')) {
|
||||
// 已完成支付,更新订单状态
|
||||
$status = $order->getAttr('delivery_type') ? 4 : 5;
|
||||
$order->save(['status' => $status, 'payment_status' => 1]);
|
||||
// 确认完成支付,发放余额积分奖励及升级返佣
|
||||
}
|
||||
|
||||
// 退款或部分退款,仅更新订单支付统计
|
||||
if ($payment->getAttr('refund_status')) {
|
||||
return $order->save();
|
||||
}
|
||||
|
||||
// 提交支付凭证,只需更新订单状态为【待审核】
|
||||
$isVoucher = $payment->getAttr('channel_type') === Payment::VOUCHER;
|
||||
if ($isVoucher && $payment->getAttr('audit_status') === 1) {
|
||||
return $order->save(['status' => 3, 'payment_status' => 1]);
|
||||
}
|
||||
|
||||
// 凭证支付审核被拒绝,订单回滚到未支付状态
|
||||
if ($isVoucher && $payment->getAttr('audit_status') === 0) {
|
||||
if ($order->getAttr('status') === 3) $order->save(['status' => 2]);
|
||||
} else {
|
||||
$order->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新订单收货地址
|
||||
* @param PointsMallOrder $order
|
||||
* @param $address
|
||||
* @return boolean
|
||||
* @throws \think\admin\Exception
|
||||
*/
|
||||
public static function perfect(PointsMallOrder $order, $address): bool
|
||||
{
|
||||
$unid = $order->getAttr('unid');
|
||||
$orderNo = $order->getAttr('order_no');
|
||||
// 创建订单发货信息
|
||||
$data = [
|
||||
'delivery_code' => 0, 'delivery_count' => 0, 'unid' => $unid,
|
||||
'delivery_remark' => '', 'delivery_amount' => 0, 'status' => 1,
|
||||
];
|
||||
$data['order_no'] = $orderNo;
|
||||
$data['address_id'] = $address->getAttr('id');
|
||||
// 收货人信息
|
||||
$data['user_name'] = $address->getAttr('user_name');
|
||||
$data['user_phone'] = $address->getAttr('user_phone');
|
||||
$data['user_idcode'] = $address->getAttr('idcode');
|
||||
$data['user_idimg1'] = $address->getAttr('idimg1');
|
||||
$data['user_idimg2'] = $address->getAttr('idimg2');
|
||||
// 收货地址信息
|
||||
$data['region_prov'] = $address->getAttr('region_prov');
|
||||
$data['region_city'] = $address->getAttr('region_city');
|
||||
$data['region_area'] = $address->getAttr('region_area');
|
||||
$data['region_addr'] = $address->getAttr('region_addr');
|
||||
// 记录原地址信息
|
||||
$data['extra'] = $data;
|
||||
PointsMallOrderSender::mk()->where(['order_no' => $orderNo])->findOrEmpty()->save($data);
|
||||
// 组装更新订单数据, 重新计算订单金额
|
||||
$update = ['status' => 2, 'amount_express' => $data['delivery_amount']];
|
||||
$update['amount_real'] = round($order->getAttr('amount_discount') - $order->getAttr('amount_reduct'), 2);
|
||||
$update['amount_total'] = round($order->getAttr('amount_goods'), 2);
|
||||
// 支付金额不能少于零
|
||||
if ($update['amount_real'] <= 0) $update['amount_real'] = 0.00;
|
||||
if ($update['amount_total'] <= 0) $update['amount_total'] = 0.00;
|
||||
// 更新用户订单数据
|
||||
if ($order->save($update)) {
|
||||
// 触发订单确认事件
|
||||
Library::$sapp->event->trigger('PluginWemallOrderPerfect', $order);
|
||||
// 返回处理成功数据
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
349
plugs/think-plugs-points-mall/src/view/goods/form.html
Normal file
349
plugs/think-plugs-points-mall/src/view/goods/form.html
Normal file
@ -0,0 +1,349 @@
|
||||
{extend name="main"}
|
||||
|
||||
{block name="button"}
|
||||
<button data-target-submit class='layui-btn layui-btn-sm'>保存数据</button>
|
||||
<button data-target-backup class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确认要取消编辑吗?">取消编辑</button>
|
||||
{/block}
|
||||
|
||||
{block name="content"}
|
||||
{include file='goods/form_style'}
|
||||
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card">
|
||||
<div class="layui-card-body">
|
||||
|
||||
<!--{notempty name='marks'}-->
|
||||
<div class="layui-form-item">
|
||||
<span class="help-label label-required-prev"><b>商品标签</b>Goods Mark</span>
|
||||
<div class="layui-textarea help-checks">
|
||||
{foreach $marks as $mark}
|
||||
<label class="think-checkbox">
|
||||
{if isset($vo.marks) && is_array($vo.marks) && in_array($mark, $vo.marks)}
|
||||
<input name="marks[]" type="checkbox" value="{$mark}" lay-ignore checked> {$mark}
|
||||
{else}
|
||||
<input name="marks[]" type="checkbox" value="{$mark}" lay-ignore> {$mark}
|
||||
{/if}
|
||||
</label>
|
||||
{/foreach}
|
||||
</div>
|
||||
</div>
|
||||
<!--{/notempty}-->
|
||||
|
||||
<!--{notempty name='cates'}-->
|
||||
<div class="layui-form-item block relative">
|
||||
<span class="help-label label-required-prev"><b>所属分类</b>Category Name</span>
|
||||
<select class="layui-select" lay-search name="cates">
|
||||
{foreach $cates as $cate}{if in_array($cate.id, $vo.cates)}
|
||||
<option selected value="{:arr2str($cate.ids)}">{:join(' > ', $cate.names)}</option>
|
||||
{else}
|
||||
<option value="{:arr2str($cate.ids)}">{:join(' > ', $cate.names)}</option>
|
||||
{/if}{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
<!--{/notempty}-->
|
||||
|
||||
<label class="layui-form-item block relative">
|
||||
<span class="help-label"><b>商品名称</b>Product Name</span>
|
||||
<input class="layui-input" name="name" placeholder="请输入商品名称" vali-name="商品名称" required value="{$vo.name|default=''}">
|
||||
</label>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<span class="help-label label-required-prev"><b>商品封面及轮播图片</b>Cover and Pictures</span>
|
||||
<table class="layui-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">商品封面</th>
|
||||
<th class="full-width">轮播图片 <span class="color-desc font-w1">( 轮播图片推荐的宽高比为 5:3 )</span></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center text-top ta-p-0">
|
||||
<div class="help-images">
|
||||
<input name="cover" data-max-width="500" data-max-height="500" type="hidden" value="{$vo.cover|default=''}">
|
||||
<script>$('[name="cover"]').uploadOneImage();</script>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-left ta-p-0">
|
||||
<div class="help-images">
|
||||
<input name="slider" data-max-width="2048" data-max-height="1024" type="hidden" value="{$vo.slider|default=''}">
|
||||
<script>$('[name="slider"]').uploadMultipleImage();</script>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item" id="GoodsSpecsEditor">
|
||||
<span class="help-label label-required-prev">
|
||||
<b>商品规格</b><span class="color-red font-s12">( 规格填写后不允许再次增加规格分组,规格图片推荐的宽高比为 5:3 )</span>
|
||||
</span>
|
||||
<div class="ta-mb-10" v-for="(x,$index) in specs" :key="$index">
|
||||
<div class="goods-spec-box ta-pr-10" style="background:#ddd">
|
||||
<span class="text-center goods-spec-name">分组</span>
|
||||
<label class="label-required-null inline-block">
|
||||
<input v-model.trim="x.name" @change="trimSpace(x,'name')" vali-name="分组" placeholder="请输入分组名称" required>
|
||||
</label>
|
||||
<div class="pull-right flex">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" @click="addSpecVal(x.list)">增加</a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" @click="upSpecRow(specs,$index)" :class="{false:'layui-btn-disabled'}[$index>0]">上移</a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" @click="dnSpecRow(specs,$index)" :class="{false:'layui-btn-disabled'}[$index<specs.length-1]">下移</a>
|
||||
<div style="display:none" :class="{true:'layui-show'}[mode==='add' && specs.length>0]">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" @click="delSpecRow(specs,$index)" v-if="specs.length>1">删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="goods-spec-box" v-if="x.list && x.list.length>0">
|
||||
<label class="label-required-null nowrap" v-for="xx in x.list">
|
||||
<input lay-ignore @click="xx.check=checkListChecked(x.list,$event.target.checked)" v-model.trim="xx.check" type="checkbox">
|
||||
<input v-model.trim="xx.name" @change="trimSpace(xx,'name')" vali-name="规格" placeholder="请输入规格" required type="text">
|
||||
<a class="layui-icon layui-icon-close goods-spec-close" @click="delSpecVal(x.list,$index)" v-if="x.list.length>1"></a>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="mode==='add'">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" @click="addSpecRow(specs)" v-if="specs.length<3">增加规则分组</a>
|
||||
<p class="ta-mt-10"><span class="color-red">请完成属性修改后再编辑下面的规格信息,否则规格数据会丢失!</span></p>
|
||||
</div>
|
||||
<table class="layui-table goods-spec-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="layui-bg-gray" :colspan="specs.length">规格</th>
|
||||
<th colspan="3">商品价格</th>
|
||||
<th colspan="5">其他属性</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="nowrap layui-bg-gray" v-for="x in specs"><b>{{x.name}}</b></th>
|
||||
<th class="nowrap" @click="batchSet('cost',2,'请输入商品成本价格')"><b>成本价</b><i class="layui-icon"></i></th>
|
||||
<th class="nowrap" @click="batchSet('market',2,'请输入商品市场价格')"><b>市场价</b><i class="layui-icon"></i></th>
|
||||
<th class="nowrap" @click="batchSet('selling',2,'请输入商品销售积分格')"><b>销售积分</b><i class="layui-icon"></i></th>
|
||||
<th class="nowrap" @click="batchSet('virtual',0,'请输入虚拟销量数值')"><b>虚拟销量</b><i class="layui-icon"></i></th>
|
||||
<th class="nowrap" @click="batchSet('express',0,'请输入快递计费系数')"><b>快递系数</b><i class="layui-icon"></i></th>
|
||||
<th class="nowrap" width="9%" @click="batchSet('gsku',null,'请输入商品SKU代码')"><b>商品SKU</b> <i class="layui-icon"></i></th>
|
||||
<th class="nowrap" width="6%">规格图片</th>
|
||||
<th class="nowrap" width="6%"><b>销售状态</b></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item,hash) in items" :key="hash">
|
||||
<td class="layui-bg-gray nowrap text-center" v-if="s.check" v-for="s in item.s">{{s.name}}</td>
|
||||
<td><label><input class="layui-input" @blur="syncSet(hash)" v-model.trim="item.v.cost"></label></td>
|
||||
<td><label><input class="layui-input" @blur="syncSet(hash)" v-model.trim="item.v.market"></label></td>
|
||||
<td><label><input class="layui-input" @blur="syncSet(hash)" v-model.trim="item.v.selling"></label></td>
|
||||
<td><label><input class="layui-input" @blur="syncSet(hash)" v-model.trim="item.v.virtual"></label></td>
|
||||
<td><label><input class="layui-input" @blur="syncSet(hash)" v-model.trim="item.v.express"></label></td>
|
||||
<td><label><input class="layui-input font-code" v-model.trim="item.v.gsku"></label></td>
|
||||
<td class="upload-image-xs ta-p-0 text-center">
|
||||
<upload-image v-model.trim="item.v.image" :showinput="false"></upload-image>
|
||||
</td>
|
||||
<td class="layui-bg-gray"><label class="think-checkbox"><input lay-ignore v-model.trim="item.v.status" type="checkbox"></label></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="color-desc">请注意商品的 sku 在系统中仅作为显示之用,系统会根据规格生成哈希值作为商品唯一区别码!</p>
|
||||
<label class="layui-hide">
|
||||
<textarea class="layui-textarea" name="specs">{{JSON.stringify(specs)}}</textarea>
|
||||
<textarea class="layui-textarea" name="items">{{JSON.stringify(attrs)}}</textarea>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label class="layui-form-item block">
|
||||
<span class="help-label"><b>商品简介描述</b></span>
|
||||
<textarea class="layui-textarea" name="remark" placeholder="请输入商品简介描述">{$vo.remark|default=''|raw}</textarea>
|
||||
</label>
|
||||
|
||||
<div class="layui-form-item block">
|
||||
<span class="help-label label-required-prev"><b>商品富文本详情</b></span>
|
||||
<textarea class="layui-hide" name="content">{$vo.content|default=''|raw}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed ta-mt-40"></div>
|
||||
<input name="code" type="hidden" value="{$vo.code}">
|
||||
|
||||
<div class="layui-form-item text-center">
|
||||
<button class="layui-btn layui-btn-danger" type="button" data-target-backup>取消编辑</button>
|
||||
<button class="layui-btn" type="submit">保存商品</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{/block}
|
||||
|
||||
{block name='script'}
|
||||
<label class="layui-hide">
|
||||
<textarea id="GoodsSpecs">{$vo.specs|raw|default=''}</textarea>
|
||||
<textarea id="GoodsItems">{$vo.items|raw|default=''}</textarea>
|
||||
</label>
|
||||
|
||||
<script>
|
||||
/*! 加载扩展插件 */
|
||||
require(['md5', 'vue', 'ckeditor'], function (md5, Vue) {
|
||||
// 创建富文本
|
||||
window.createEditor('[name=content]', {height: 500});
|
||||
// 图片上传组件
|
||||
Vue.component('UploadImage', {
|
||||
data: () => ({eid: Math.random().toString().replace('0.', 'up')}),
|
||||
model: {prop: 'mvalue', event: 'change'}, props: {mvalue: {type: String, default: ''}},
|
||||
template: '<input class="layui-hide" v-model="mvalue" :id="eid" readonly>',
|
||||
mounted: function () {
|
||||
this.$nextTick(() => $('#' + this.eid).uploadOneImage().on('change', e => this.$emit('change', e.target.value)));
|
||||
}
|
||||
});
|
||||
// 字段格式规则
|
||||
let rules = {
|
||||
image: '_',
|
||||
cost: '(parseFloat(_)||0).toFixed(2)',
|
||||
market: '(parseFloat(_)||0).toFixed(2)',
|
||||
selling: '(parseFloat(_)||0).toFixed(2)',
|
||||
balance: '(parseFloat(_)||0).toFixed(2)',
|
||||
integral: '(parseFloat(_)||0).toFixed(0)',
|
||||
express: '(parseFloat(_)||0).toFixed(0)',
|
||||
virtual: '(parseFloat(_)||0).toFixed(0)',
|
||||
allow_balance: '(parseFloat(_)||0).toFixed(2)',
|
||||
allow_integral: '(parseFloat(_)||0).toFixed(0)',
|
||||
};
|
||||
// 历史及缓存数据
|
||||
let cache = {};
|
||||
layui.each(JSON.parse($('#GoodsItems').val() || '{}') || {}, function (k, v) {
|
||||
for (let i in v) setValue(k, i, v[i]);
|
||||
});
|
||||
// 创建 Vue2 实例
|
||||
let app = new Vue({
|
||||
el: '#GoodsSpecsEditor', data: () => ({
|
||||
mode: '{$mode|default="add"}', items: {}, attrs: {},
|
||||
specs: JSON.parse(JSON.parse($('#GoodsSpecs').val() || '[]')) || []
|
||||
}),
|
||||
created: function () {
|
||||
this.specs.length < 1 && addSpecRow(this.specs);
|
||||
},
|
||||
watch: {
|
||||
specs: {
|
||||
deep: true, immediate: true, handler: function (values) {
|
||||
// 笛卡尔积生成商品SKU多规格算法
|
||||
let items = {}, attrs = [], list = values.reduce((a, b) => {
|
||||
let res = [];
|
||||
a.map(x => b.list.map(y => y.check && res.push(x.concat(Object.assign({group: b.name}, y)))));
|
||||
return res;
|
||||
}, [[]]);
|
||||
// 初始化商品规格同步变量值
|
||||
list.map(function (cols) {
|
||||
let keys = [], specs = [], unids = [];
|
||||
cols.map(v => keys.push(v.group + '::' + v.name) && specs.push(v) && unids.push(v.unid));
|
||||
let hash = md5.hash("{$vo.code}#" + unids.sort().join(';')), values = {
|
||||
hash: hash,
|
||||
spec: keys.join(';;'),
|
||||
gsku: getValue(hash, 'gsku', withRandString(14, 'S')),
|
||||
image: getValue(hash, 'image', ''),
|
||||
status: !!getValue(hash, 'status', 1),
|
||||
cost: getValue(hash, 'cost', '0.00'),
|
||||
market: getValue(hash, 'market', '0.00'),
|
||||
selling: getValue(hash, 'selling', '0.00'),
|
||||
balance: getValue(hash, 'balance', '0.00'),
|
||||
integral: getValue(hash, 'integral', '0'),
|
||||
express: getValue(hash, 'express', '1'),
|
||||
virtual: getValue(hash, 'virtual', '0'),
|
||||
allow_balance: getValue(hash, 'allow_balance', '0.00'),
|
||||
allow_integral: getValue(hash, 'allow_integral', '0'),
|
||||
};
|
||||
items[hash] = {s: specs, v: values};
|
||||
attrs.push(values)
|
||||
})
|
||||
this.attrs = attrs;
|
||||
this.items = items;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/*! 同步格式化值 */
|
||||
syncSet: function (hash) {
|
||||
let v = this.items[hash].v;
|
||||
for (let k in v) v[k] = setValue(hash, k, v[k])
|
||||
},
|
||||
/*! 批量设置数值 */
|
||||
batchSet: function (name, fixed, title) {
|
||||
let min = (0 / Math.pow(10, parseInt(fixed))).toFixed(fixed), max = (999999).toFixed(fixed);
|
||||
layer.prompt({
|
||||
title: title || (fixed === null ? '请输入内容' : '请输入数量【 取值范围:1 - 999999 】'),
|
||||
formType: 0, value: fixed === null ? '' : min, success: function ($el) {
|
||||
$el.find('.layui-layer-input').attr({'data-value-min': min, 'data-value-max': max, 'data-blur-number': fixed});
|
||||
}
|
||||
}, function (value, index) {
|
||||
if (fixed !== null) value = (parseFloat(value) || 0).toFixed(fixed);
|
||||
for (let i in app.items) app.items[i].v[name] = value;
|
||||
layer.close(index) || app.$forceUpdate()
|
||||
});
|
||||
},
|
||||
/*! 去除空白字符 */
|
||||
trimSpace: function (x, i) {
|
||||
return x[i] = (x[i] || '').replace(/[\s,;'"]+/ig, '');
|
||||
},
|
||||
/*! 判断规则选择 */
|
||||
checkListChecked: function (data, check) {
|
||||
for (let i in data) if (data[i].check) return check;
|
||||
return true;
|
||||
},
|
||||
/*! 下移整行规格分组 */
|
||||
dnSpecRow: function (items, index) {
|
||||
index + 1 < items.length && (item => items.splice(index + 1, 1) && items.splice(index, 0, item))(items[index + 1]);
|
||||
},
|
||||
/*! 上移整行规格分组 */
|
||||
upSpecRow: function (items, index) {
|
||||
index > 0 && (item => items.splice(index - 1, 1) && items.splice(index, 0, item))(items[index - 1]);
|
||||
},
|
||||
/*! 增加整行规格分组 */
|
||||
addSpecRow: function (data) {
|
||||
addSpecRow(data);
|
||||
},
|
||||
/*! 移除整行规格分组 */
|
||||
delSpecRow: function (items, index) {
|
||||
items.splice(index, 1);
|
||||
},
|
||||
/*! 增加分组的属性 */
|
||||
addSpecVal: function (data) {
|
||||
addSpecVal(data);
|
||||
},
|
||||
/*! 移除分组的属性 */
|
||||
delSpecVal: function (data, $index) {
|
||||
data.splice($index, 1);
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
/*! 动态设置内容 */
|
||||
function setValue(hash, name, value, filter) {
|
||||
filter = filter || rules[name] || null;
|
||||
if (typeof filter === 'string' && filter.indexOf('_') > -1) {
|
||||
value = eval(filter.replace('_', "'" + value + "'"));
|
||||
}
|
||||
cache[hash] = cache[hash] || {};
|
||||
return cache[hash][name] = value;
|
||||
}
|
||||
|
||||
/*!动态读取内容 */
|
||||
function getValue(hash, name, value) {
|
||||
let _cache = cache[hash] || {};
|
||||
if (typeof _cache[name] === 'undefined') {
|
||||
setValue(hash, name, value, '_')
|
||||
_cache = cache[hash] || {};
|
||||
}
|
||||
return _cache[name];
|
||||
}
|
||||
|
||||
// 创建分组
|
||||
function addSpecRow(data) {
|
||||
data.push({name: '规格分组' + (data.length || ''), list: addSpecVal([])})
|
||||
}
|
||||
|
||||
// 创建规格
|
||||
function addSpecVal(data) {
|
||||
data.push({name: '规格属性' + (data.length || ''), unid: withRandString(16), check: true});
|
||||
return data;
|
||||
}
|
||||
|
||||
// 随机字符串
|
||||
function withRandString(length, prefix) {
|
||||
return (function (time, code) {
|
||||
code += parseInt(time.substring(0, 1)) + parseInt(time.substring(1, 2)) + time.substring(2);
|
||||
while (code.length < length) code += (Math.random()).toString().replace('.', '');
|
||||
return code.substring(0, length);
|
||||
})(Date.now().toString(), prefix || '')
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{/block}
|
185
plugs/think-plugs-points-mall/src/view/goods/form_style.html
Normal file
185
plugs/think-plugs-points-mall/src/view/goods/form_style.html
Normal file
@ -0,0 +1,185 @@
|
||||
<style>
|
||||
.upload-image-xs {
|
||||
padding: 2px !important;
|
||||
}
|
||||
|
||||
.upload-image-xs .uploadimage {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.upload-image-xs .uploadimage span:first-child {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.goods-item-box fieldset {
|
||||
width: 260px;
|
||||
height: 80px;
|
||||
padding: 15px 20px;
|
||||
display: inline-block;
|
||||
margin: 0 15px 15px 0;
|
||||
}
|
||||
|
||||
.goods-spec-box {
|
||||
position: relative;
|
||||
margin: 0 10px 10px 0;
|
||||
background: #EEEEEE;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.goods-spec-name {
|
||||
z-index: 2;
|
||||
width: 40px;
|
||||
color: #fff;
|
||||
height: 25px;
|
||||
position: absolute;
|
||||
background: #999;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
|
||||
.goods-spec-btn {
|
||||
height: 28px;
|
||||
margin-left: 5px !important;
|
||||
line-height: 28px !important;
|
||||
}
|
||||
|
||||
.goods-spec-box {
|
||||
margin: 0;
|
||||
padding: 10px 0 5px 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.goods-spec-box label {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
|
||||
.goods-spec-box input:not([type=checkbox]) {
|
||||
width: 120px;
|
||||
border: 1px solid #999;
|
||||
display: inline-block !important;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
line-height: 24px;
|
||||
padding-left: 45px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.goods-spec-box input[type=checkbox] {
|
||||
width: 40px;
|
||||
height: 26px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.goods-spec-box input[type=checkbox]:after,
|
||||
.goods-spec-box input[type=checkbox]:before {
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
width: 40px;
|
||||
height: 24px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.goods-spec-box input[type=checkbox]:before {
|
||||
content: '';
|
||||
background: #c9c9c9;
|
||||
}
|
||||
|
||||
.goods-spec-box input[type=checkbox]:after {
|
||||
color: #999;
|
||||
content: '\e63f';
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
line-height: 24px;
|
||||
font-family: 'layui-icon', serif;
|
||||
}
|
||||
|
||||
.goods-spec-box input[type=checkbox]:checked:after {
|
||||
color: #333;
|
||||
content: '\e605';
|
||||
}
|
||||
|
||||
.goods-spec-box label .goods-spec-close {
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
width: 16px;
|
||||
bottom: 3px;
|
||||
height: 16px;
|
||||
z-index: 2;
|
||||
color: white;
|
||||
display: none;
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
background: rgba(252, 24, 24, 0.6);
|
||||
line-height: 16px;;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.goods-spec-box label .goods-spec-close:hover {
|
||||
color: white;
|
||||
background: rgba(252, 24, 24, 1.0);
|
||||
}
|
||||
|
||||
.goods-spec-box label:hover .goods-spec-close {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.goods-spec-table {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.goods-spec-table tr th {
|
||||
padding: 9px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.goods-spec-table tr th .layui-icon {
|
||||
font-size: 13px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.goods-spec-table tr td {
|
||||
padding: 9px 6px;
|
||||
}
|
||||
|
||||
.goods-spec-table tr td:has(input) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.goods-spec-table tr td:last-child {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.goods-spec-table tr td:last-child label {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.goods-spec-table tr td label {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.goods-spec-table tr td label input.layui-input {
|
||||
border: none;
|
||||
width: 100%;
|
||||
height: 38px !important;
|
||||
text-align: center;
|
||||
line-height: 38px !important;
|
||||
padding-left: 0;
|
||||
}
|
||||
</style>
|
113
plugs/think-plugs-points-mall/src/view/goods/index.html
Normal file
113
plugs/think-plugs-points-mall/src/view/goods/index.html
Normal file
@ -0,0 +1,113 @@
|
||||
{extend name="table"}
|
||||
|
||||
{block name="button"}
|
||||
<!--{if auth("add")}-->
|
||||
<button class='layui-btn layui-btn-sm layui-btn-primary' data-open='{:url("add")}'>添加商品</button>
|
||||
<!--{/if}-->
|
||||
|
||||
<!--{if auth("goods_cate/index")}-->
|
||||
<button class='layui-btn layui-btn-sm layui-btn-primary' data-modal='{:url("goods_cate/index")}' data-title="分类管理" data-width="999px">分类管理</button>
|
||||
<!--{/if}-->
|
||||
|
||||
{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="layui-tab layui-tab-card think-bg-white">
|
||||
<ul class="layui-tab-title">
|
||||
{foreach ['index'=>'商品管理','recycle'=>'下架商品'] as $k=>$v}
|
||||
{if isset($type) and $type eq $k}
|
||||
<li class="layui-this" data-open="{:url('index')}?type={$k}">{$v}</li>
|
||||
{else}
|
||||
<li data-open="{:url('index')}?type={$k}">{$v}</li>
|
||||
{/if}{/foreach}
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
{include file='goods/index_search'}
|
||||
<table id="GoodsTable" data-line="2" data-url="{:request()->url()}"></table>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name='script'}
|
||||
<script>
|
||||
$(function () {
|
||||
let $table = $('#GoodsTable').layTable({
|
||||
even: true, height: 'full',
|
||||
sort: {field: 'sort desc,id', type: 'desc'},
|
||||
cols: [[
|
||||
{field: 'id', hide: true},
|
||||
{field: 'sort', title: '排序权重', width: 100, align: 'center', sort: true, templet: '#SortInputTpl'},
|
||||
{
|
||||
title: '商品名称', minWidth: 220, templet: function (d) {
|
||||
d.html = showTableImage(d.cover, false, 'sm')
|
||||
return laytpl("<div class='flex'><div>{{-d.html}}</div><div class='ta-pl-10 nowrap'>名称:{{d.name}}<br>编号:<b class='color-blue'>{{d.code}}</b></div></div>").render(d);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '价格及库存 ', width: '15%', templet: function (d) {
|
||||
let tpls = [];
|
||||
tpls.push('售价: <b>{{Number(d.price_selling)}}</b> 积分/件');
|
||||
tpls.push('总库存 <b>{{d.stock_total}}</b> 件,剩余库存 <b>{{d.stock_total-d.stock_sales}}</b> 件');
|
||||
return laytpl('<div class="sub-strong-blue nowrap">' + tpls.join('<br>') + '</div>').render(d);
|
||||
}
|
||||
},
|
||||
{field: 'status', title: '商品状态', minWidth: 110, width: '5%', align: 'center', templet: '#StatusSwitchTpl'},
|
||||
{field: 'create_time', title: '创建时间', minWidth: 200, width: '5%', templet: "<div>更新:{{d.update_time}}<br>创建:{{d.create_time}}</div>"},
|
||||
{toolbar: '#toolbar', title: '操作面板', minWidth: 155, width: '5%', align: 'center', fixed: 'right'},
|
||||
]]
|
||||
});
|
||||
|
||||
// 数据状态切换操作
|
||||
layui.form.on('switch(StatusSwitch)', function (obj) {
|
||||
let data = {code: obj.value, status: obj.elem.checked > 0 ? 1 : 0};
|
||||
$.form.load("{:url('state')}", data, 'post', function (ret) {
|
||||
let fn = () => $table.trigger('reload');
|
||||
ret.code < 1 ? $.msg.error(ret.info, 3, fn) : fn();
|
||||
return false;
|
||||
}, false);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 数据状态切换模板 -->
|
||||
<script type="text/html" id="StatusSwitchTpl">
|
||||
<div class="ta-pt-10 block relative"></div>
|
||||
<!--{if auth("state")}-->
|
||||
<input type="checkbox" value="{{d.code}}" lay-skin="switch" lay-text="已上架|已下架" lay-filter="StatusSwitch" {{-d.status>0?'checked':''}}>
|
||||
<!--{else}-->
|
||||
{{-d.status ? '<b class="color-green">已上架</b>' : '<b class="color-red">已下架</b>'}}
|
||||
<!--{/if}-->
|
||||
</script>
|
||||
|
||||
<!-- 列表排序权重模板 -->
|
||||
<script type="text/html" id="SortInputTpl">
|
||||
<label class="ta-pt-5 block relative">
|
||||
<input type="number" min="0" data-blur-number="0" data-action-blur="{:sysuri()}" data-value="id#{{d.id}};action#sort;sort#{value}" data-loading="false" value="{{d.sort}}" class="layui-input text-center">
|
||||
</label>
|
||||
</script>
|
||||
|
||||
<!-- 操控面板的模板 -->
|
||||
<script type="text/html" id="toolbar">
|
||||
|
||||
{if $type eq 'index'}
|
||||
|
||||
<!--{if auth('stock')}-->
|
||||
<a class="layui-btn layui-btn-sm layui-btn-normal" data-title="商品入库" data-modal='{:url("stock")}?code={{d.code}}'>入 库</a>
|
||||
<!--{/if}-->
|
||||
|
||||
<!--{if auth('edit')}-->
|
||||
<a class="layui-btn layui-btn-sm" data-open='{:url("edit")}?code={{d.code}}'>编 辑</a>
|
||||
<!--{/if}-->
|
||||
|
||||
{else}
|
||||
|
||||
<!--{if auth('edit')}-->
|
||||
<a class="layui-btn layui-btn-sm" data-open='{:url("edit")}?code={{d.code}}'>编 辑</a>
|
||||
<!--{/if}-->
|
||||
|
||||
<!--{if auth('remove')}-->
|
||||
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除此商品吗?" data-action="{:url('remove')}" data-value="code#{{d.code}}">删 除</a>
|
||||
<!--{/if}-->
|
||||
{/if}
|
||||
</script>
|
||||
{/block}
|
@ -0,0 +1,32 @@
|
||||
<form action="{:sysuri()}" autocomplete="off" data-table-id="GoodsTable" class="layui-form layui-form-pane form-search" method="get" onsubmit="return false">
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">商品名称</label>
|
||||
<label class="layui-input-inline">
|
||||
<input class="layui-input" name="name" placeholder="请输入编号或名称" value="{$get.name|default=''}">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!--{notempty name='cates'}-->
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">商品分类</label>
|
||||
<div class="layui-input-inline">
|
||||
<label class="layui-input-inline">
|
||||
<select class="layui-select" lay-search name="cates">
|
||||
<option value="">-- 全部分类 --</option>
|
||||
{foreach $cates as $cate}{if input('cates') eq $cate.id}
|
||||
<option selected value="{$cate.id}">{$cate.spl}{$cate.name|default=''}</option>
|
||||
{else}
|
||||
<option value="{$cate.id}">{$cate.spl}{$cate.name|default=''}</option>
|
||||
{/if}{/foreach}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!--{/notempty}-->
|
||||
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<button class="layui-btn layui-btn-primary"><i class="layui-icon"></i> 搜 索</button>
|
||||
</div>
|
||||
</form>
|
35
plugs/think-plugs-points-mall/src/view/goods/select.html
Normal file
35
plugs/think-plugs-points-mall/src/view/goods/select.html
Normal file
@ -0,0 +1,35 @@
|
||||
<div class="relative">
|
||||
{include file='shop/goods/select_search'}
|
||||
<table id="GoodsTableSelect" data-line="2" data-url="{:request()->url()}"></table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
$('#GoodsTableSelect').layTable({
|
||||
even: true, width: 'full', height: 'full', page: true,
|
||||
sort: {field: 'sort desc,id', type: 'desc'},
|
||||
cols: [[
|
||||
// {checkbox: true},
|
||||
{field: 'id', hide: true},
|
||||
{field: 'sort', hide: true},
|
||||
{field: 'cover', title: '商品封面', width: 80, align: 'center', templet: '<div>{{-showTableImage(d.cover,false,"sm")}}</div>'},
|
||||
{field: 'name', title: '商品名称', templet: "<div>商品名称:{{d.name}}<br>商品编号:<b class='color-blue'>{{d.code}}</b></div>"},
|
||||
{field: 'create_time', title: '创建时间', width: 210, templet: "<div>更新:{{d.update_time}}<br>创建:{{d.create_time}}</div>"},
|
||||
{toolbar: '#SelectToolbar', title: '操作面板', width: 80, align: 'center', fixed: 'right'},
|
||||
]]
|
||||
}).trigger('tool', function (item) {
|
||||
let attr = ['商品详情', item.data.code, item.data.name];
|
||||
window.setItemValue(item.data, attr.join('#'));
|
||||
$.msg.closeThisModal(this);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 操作工具条模板 -->
|
||||
<script type="text/html" id="SelectToolbar">
|
||||
{{# if (typeof checkItemValue !== 'function' || checkItemValue(d.id)){ }}
|
||||
<a class="layui-btn layui-btn-sm" lay-event="select">选 择</a>
|
||||
{{# }else{ }}
|
||||
<a class="layui-btn layui-btn-sm layui-btn-disabled">已 选</a>
|
||||
{{# } }}
|
||||
</script>
|
@ -0,0 +1,24 @@
|
||||
<fieldset>
|
||||
<legend>{:lang('条件搜索')}</legend>
|
||||
<form action="{:sysuri()}" autocomplete="off" data-table-id="GoodsTableSelect" class="layui-form layui-form-pane form-search" method="get" onsubmit="return false">
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">商品名称</label>
|
||||
<label class="layui-input-inline">
|
||||
<input class="layui-input" name="name" placeholder="请输入商品名称或编号" value="{$get.name|default=''}">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">创建时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" data-date-range name="create_time" placeholder="请选择创建时间" value="{$get.create_time|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<button class="layui-btn layui-btn-primary"><i class="layui-icon"></i> 搜 索</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</fieldset>
|
98
plugs/think-plugs-points-mall/src/view/goods/stock.html
Normal file
98
plugs/think-plugs-points-mall/src/view/goods/stock.html
Normal file
@ -0,0 +1,98 @@
|
||||
<form action="{:sysuri()}?code={$get.code|default=''}" data-table-id="GoodsTable" class="layui-form layui-card" data-auto="true" method="post">
|
||||
<div class="layui-card-body ta-pl-40">
|
||||
|
||||
<div class="layui-form-item relative">
|
||||
<span class="help-label"><b>商品编号</b>Goods Code</span>
|
||||
<div class="layui-input layui-bg-gray">{$vo.code|default=''}</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item relative">
|
||||
<span class="help-label"><b>商品名称</b>Goods Name</span>
|
||||
<div class="layui-input layui-bg-gray">{$vo.name|default=''}</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item relative">
|
||||
<span class="help-label"><b>库存数据</b>Goods Stock Data</span>
|
||||
<table class="layui-table border-0 ta-m-0" lay-skin="nob">
|
||||
<colgroup>
|
||||
<col style="width:auto">
|
||||
<col style="width:80px">
|
||||
<col style="width:80px">
|
||||
<col style="width:80px">
|
||||
<col style="width:80px">
|
||||
<col style="width:80px">
|
||||
<col style="width:99px">
|
||||
<col style="width:18px">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="layui-bg-cyan notselect">
|
||||
<th class="text-left nowrap">商品规格</th>
|
||||
<th class="text-center nowrap">市场价格</th>
|
||||
<th class="text-center nowrap">销售积分</th>
|
||||
<th class="text-center nowrap">库存统计</th>
|
||||
<th class="text-center nowrap">总销统计</th>
|
||||
<th class="text-center nowrap">库存剩余</th>
|
||||
<th class="text-center nowrap pointer" data-batchset data-tips-text="批量设置库存">
|
||||
<i class="layui-icon font-s10" style="color:#FFF"></i> 入库数量
|
||||
</th>
|
||||
<th class="ta-p-0"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<div style="max-height:500px;overflow-y:scroll">
|
||||
<table class="layui-table ta-m-0" lay-skin="line">
|
||||
<colgroup>
|
||||
<col style="width:auto">
|
||||
<col style="width:80px">
|
||||
<col style="width:80px">
|
||||
<col style="width:80px">
|
||||
<col style="width:80px">
|
||||
<col style="width:80px">
|
||||
<col style="width:99px">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
{foreach $vo.items as $goods}
|
||||
<tr>
|
||||
<td class="layui-bg-gray layui-elip">{$goods.gspec|show_gspec}</td>
|
||||
<td class="layui-bg-gray text-center">¥{$goods.price_market+0}</td>
|
||||
<td class="layui-bg-gray text-center">¥{$goods.price_selling+0}</td>
|
||||
<td class="layui-bg-gray text-center">{$goods.stock_total|default=0}</td>
|
||||
<td class="layui-bg-gray text-center">{$goods.stock_sales|default=0}</td>
|
||||
<td class="layui-bg-gray text-center">{$goods.stock_total-$goods.stock_sales}</td>
|
||||
<td class="ta-p-0 nowrap">
|
||||
<input name="gcode[]" type="hidden" value="{$goods.gcode|default=''}">
|
||||
<input name="gspec[]" type="hidden" value="{$goods.gspec|default=''}">
|
||||
<input name="ghash[]" type="hidden" value="{$goods.ghash|default=''}">
|
||||
<label class="relative flex flex-align-center">
|
||||
<input class="layui-input text-center border-0 flex-1" type="number" min="0" data-blur-number="0" maxlength="20" name="gstock[]" value="0">
|
||||
<span class="layui-bg-gray ta-pl-5 ta-pr-5">件</span>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="layui-form-item text-center">
|
||||
<button class="layui-btn" type='submit'>确定入库</button>
|
||||
<button class="layui-btn layui-btn-danger" data-close data-confirm="确定要取消入库吗?" type='button'>取消入库</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
$('[data-batchset]').on('click', function () {
|
||||
layer.prompt({
|
||||
title: '请输入库存数量【 取值范围:1 - 999999 】',
|
||||
formType: 0, value: 1, success: function ($ele) {
|
||||
$ele.find('.layui-layer-input').attr({'data-value-min': 1, 'data-value-max': 999999, 'data-blur-number': 0});
|
||||
}
|
||||
}, function (value, index) {
|
||||
layer.close(index) || $('[name^="gstock"]').val(parseInt(value) || 0);
|
||||
});
|
||||
});
|
||||
</script>
|
49
plugs/think-plugs-points-mall/src/view/goods_cate/form.html
Normal file
49
plugs/think-plugs-points-mall/src/view/goods_cate/form.html
Normal file
@ -0,0 +1,49 @@
|
||||
<form action="{:sysuri()}" data-table-id="CateTable" class="layui-form layui-card" data-auto="true" method="post">
|
||||
<div class="layui-card-body ta-pl-40">
|
||||
|
||||
<div class="layui-form-item label-required-prev">
|
||||
<span class="help-label"><b>绑定上级分类</b>Category Parent</span>
|
||||
<select class='layui-select' name='pid' lay-search>
|
||||
{foreach $cates as $cate}
|
||||
{eq name='cate.id' value='$vo.pid|default=0'}
|
||||
<option selected value='{$cate.id}'>{$cate.spl|raw}{$cate.name}</option>
|
||||
{else}
|
||||
<option value='{$cate.id}'>{$cate.spl|raw}{$cate.name}</option>
|
||||
{/eq}{/foreach}
|
||||
</select>
|
||||
<span class="help-block"><b>必选,</b>请选择上级分类或顶级分类(目前最多支持{$cateLevel|default=0}级分类)</span>
|
||||
</div>
|
||||
|
||||
<label class="layui-form-item relative block">
|
||||
<span class="help-label"><b>商品分类名称</b>Category Name</span>
|
||||
<input class="layui-input" name="name" placeholder="请输入分类名称" required value='{$vo.name|default=""}'>
|
||||
<span class="help-block"><b>必填,</b>请填写商品分类名称,建议字符不要太长,一般 4-6 个汉字</span>
|
||||
</label>
|
||||
|
||||
<div class="layui-form-item relative block">
|
||||
<span class="help-label"><b>商品分类图标</b>Category Cover</span>
|
||||
<div class="relative block">
|
||||
<label>
|
||||
<input class="layui-input think-bg-gray" data-tips-hover data-tips-image readonly name="cover" placeholder="请上传商品分类图标" value='{$vo.cover|default=""}'>
|
||||
</label>
|
||||
<a class="input-right-icon layui-icon layui-icon-upload" data-field="cover" data-file data-type="png,jpg,gif"></a>
|
||||
</div>
|
||||
<span class="help-block"><b>可选,</b>请上传商品分类图标,需要是 http 可访问的图片资源链接</span>
|
||||
</div>
|
||||
|
||||
<label class="layui-form-item relative block">
|
||||
<span class="color-green font-w7">商品分类描述</span>
|
||||
<span class="color-desc ta-ml-5">Category Remark</span>
|
||||
<textarea class="layui-textarea" name="remark" placeholder="请输入分类描述">{$vo.remark|default=''}</textarea>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{notempty name='vo.id'}<input name='id' type='hidden' value='{$vo.id}'>{/notempty}
|
||||
|
||||
<div class="layui-form-item text-center">
|
||||
<button class="layui-btn" type='submit'>保存数据</button>
|
||||
<button class="layui-btn layui-btn-danger" data-close type='button' data-confirm="确定要取消编辑吗?">取消编辑</button>
|
||||
</div>
|
||||
|
||||
</form>
|
78
plugs/think-plugs-points-mall/src/view/goods_cate/index.html
Normal file
78
plugs/think-plugs-points-mall/src/view/goods_cate/index.html
Normal file
@ -0,0 +1,78 @@
|
||||
<div class="think-box-notify">
|
||||
<b>注意:</b>商品分类需要在上传商品前添加,当商品分类关联有商品时不建议进行 <b class="color-blue">移动</b> 或 <b class="color-blue">删除</b> 操作!
|
||||
<div class="pull-right" style="margin-top:-8px">
|
||||
<!--{if auth("add")}-->
|
||||
<button class='layui-btn layui-btn-sm layui-btn-primary' data-table-id="CateTable" data-modal='{:url("add")}' data-title="添加分类">添加分类</button>
|
||||
<!--{/if}-->
|
||||
<!--{if auth("remove")}-->
|
||||
<button class='layui-btn layui-btn-sm layui-btn-primary' data-table-id="CateTable" data-action='{:url("remove")}' data-rule="id#{sps}">删除分类</button>
|
||||
<!--{/if}-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="think-box-shadow shadow-none" style="padding-top:0!important;">
|
||||
<table id="CateTable" data-url="{:request()->url()}"></table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
let $table = $('#CateTable').layTable({
|
||||
even: true, height: 'full', page: false,
|
||||
sort: {field: 'sort desc,id', type: 'asc'},
|
||||
cols: [[
|
||||
{checkbox: true, fixed: true},
|
||||
{field: 'sort', title: '排序权重', width: 100, align: 'center', sort: true, templet: '#SortInputTplCate'},
|
||||
{field: 'name', title: '分类名称', minWidth: 220, templet: '<div><span class="color-desc">{{d.spl}}</span>{{d.name}}</div>'},
|
||||
{field: 'status', title: '分类状态', width: 110, align: 'center', templet: '#StatusSwitchTplCate'},
|
||||
{field: 'create_time', title: '创建时间', width: 170, align: 'center'},
|
||||
{toolbar: '#ToolBarCate', title: '操作面板', width: 220, align: 'center', fixed: 'right'},
|
||||
]]
|
||||
});
|
||||
|
||||
// 数据状态切换操作
|
||||
layui.form.on('switch(StatusSwitch)', function (object) {
|
||||
object.data = {status: object.elem.checked > 0 ? 1 : 0};
|
||||
object.data.id = object.value.split('|')[object.data.status] || object.value;
|
||||
$.form.load("{:url('state')}", object.data, 'post', function (ret) {
|
||||
let fn = () => $table.trigger('reload')
|
||||
ret.code < 1 ? $.msg.error(ret.info, 3, fn) : fn()
|
||||
return false;
|
||||
}, false);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 数据状态切换模板 -->
|
||||
<script type="text/html" id="StatusSwitchTplCate">
|
||||
<!--{if auth("state")}-->
|
||||
<input type="checkbox" value="{{d.sps}}|{{d.spp}}" lay-text="已激活|已禁用" lay-filter="StatusSwitch" lay-skin="switch" {{-d.status>0?'checked':''}}>
|
||||
<!--{else}-->
|
||||
{{-d.status ? '<b class="color-green">已激活</b>' : '<b class="color-red">已禁用</b>'}}
|
||||
<!--{/if}-->
|
||||
</script>
|
||||
|
||||
<!-- 列表排序权重模板 -->
|
||||
<script type="text/html" id="SortInputTplCate">
|
||||
<input type="number" min="0" data-blur-number="0" data-action-blur="{:sysuri()}" data-value="id#{{d.id}};action#sort;sort#{value}" data-loading="false" value="{{d.sort}}" class="layui-input text-center">
|
||||
</script>
|
||||
|
||||
<!-- 操控面板的模板 -->
|
||||
<script type="text/html" id="ToolBarCate">
|
||||
|
||||
<!--{if auth('add')}-->
|
||||
{{# if(d.spt<'{$maxLevel-1}'){ }}
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" data-title="添加商品分类" data-modal='{:url("add")}?pid={{d.id}}'>添 加</a>
|
||||
{{# }else{ }}
|
||||
<a class="layui-btn layui-btn-sm layui-btn-disabled">添 加</a>
|
||||
{{# } }}
|
||||
<!--{/if}-->
|
||||
|
||||
<!--{if auth('edit')}-->
|
||||
<a class="layui-btn layui-btn-sm" data-title="编辑商品分类" data-modal='{:url("edit")}?id={{d.id}}'>编 辑</a>
|
||||
<!--{/if}-->
|
||||
|
||||
<!--{if auth('remove')}-->
|
||||
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除此分类吗?" data-action="{:url('remove')}" data-value="id#{{d.sps}}">删 除</a>
|
||||
<!--{/if}-->
|
||||
|
||||
</script>
|
@ -0,0 +1,32 @@
|
||||
<div class="relative">
|
||||
<table id="CateTableSelect" data-url="{:request()->url()}" data-target-search="form.form-search"></table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
$('#CateTableSelect').layTable({
|
||||
even: true, height: 'full', page: false, width: 'full',
|
||||
sort: {field: 'sort desc,id', type: 'asc'},
|
||||
cols: [[
|
||||
{checkbox: true, fixed: true, hide: true},
|
||||
{field: 'sort', hide: true},
|
||||
{field: 'name', title: '分类名称', minWidth: 220, templet: '<div><span class="color-desc">{{d.spl}}</span>{{d.name}}</div>'},
|
||||
{field: 'create_time', title: '创建时间', width: 170, align: 'center'},
|
||||
{toolbar: '#SelectToolbar', title: '操作面板', width: 160, align: 'center', fixed: 'right'},
|
||||
]]
|
||||
}).trigger('tool', function (item) {
|
||||
let attr = ['商品分类', item.data.id, item.data.name];
|
||||
window.setItemValue(item.data, attr.join('#'));
|
||||
$.msg.closeThisModal(this);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 操作工具条模板 -->
|
||||
<script type="text/html" id="SelectToolbar">
|
||||
{{# if (typeof checkItemValue !== 'function' || checkItemValue(d.id)){ }}
|
||||
<a class="layui-btn layui-btn-sm" lay-event="select">选 择</a>
|
||||
{{# }else{ }}
|
||||
<a class="layui-btn layui-btn-sm layui-btn-disabled">已 选</a>
|
||||
{{# } }}
|
||||
</script>
|
167
plugs/think-plugs-points-mall/src/view/order/index.html
Normal file
167
plugs/think-plugs-points-mall/src/view/order/index.html
Normal file
@ -0,0 +1,167 @@
|
||||
{extend name="main"}
|
||||
|
||||
{block name="button"}
|
||||
{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="layui-tab layui-tab-card">
|
||||
<ul class="layui-tab-title notselect">
|
||||
{foreach $types as $k=>$v}{if isset($type) and 't'.$type eq $k}
|
||||
<li class="layui-this" data-open="{:url('index')}?type={$k}">{$v}<sup class="layui-badge border-radius">{$total[$k]??0}</sup></li>
|
||||
{else}
|
||||
<li data-open="{:url('index')}?type={$k}">{$v}<sup class="layui-badge border-radius">{$total[$k]??0}</sup></li>
|
||||
{/if}{/foreach}
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
{include file='order/index_search'}
|
||||
<table id="OrderTable" data-line="3" data-url="{:request()->url()}" data-target-search="form.form-search"></table>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name='script'}
|
||||
<script>
|
||||
function str2num(v) {
|
||||
return parseFloat(v);
|
||||
}
|
||||
|
||||
function str2name(v) {
|
||||
let _ = [];
|
||||
v.split(';;').forEach(s => _.push(s.split('::').pop()));
|
||||
return _.join(' ');
|
||||
}
|
||||
|
||||
let ostatus = ['已取消', '预订单', '待支付', '待审核', '待发货', '已发货', '已收货', '已评论'];
|
||||
let ostyles = ['layui-bg-gray', 'layui-bg-red', 'layui-bg-orange', 'layui-bg-black', 'layui-bg-blue', 'layui-bg-blue', 'layui-bg-green', 'layui-bg-green'];
|
||||
|
||||
let rstatus = ['未售后', '预订单', '待审核', '待退货', '已退货', '待退款', '已退货', '已完成'];
|
||||
let rstyles = ['layui-bg-gray', 'layui-bg-gray', 'layui-bg-blue', 'layui-bg-blue', 'layui-bg-blue', 'layui-bg-blue', 'layui-bg-blue', 'layui-bg-green'];
|
||||
|
||||
$(function () {
|
||||
$('#OrderTable').layTable({
|
||||
even: true, height: 'full', sort: {field: 'id', type: 'desc'},
|
||||
cols: [[
|
||||
{field: 'headimg', title: '头 像', width: 90, align: 'center', templet: '<div>{{-showTableImage(d.user.headimg,true,"md")}}</div>'},
|
||||
{
|
||||
title: '会员用户', width: 170, templet: function (d) {
|
||||
let tpls = [];
|
||||
if (d.user) {
|
||||
tpls.push('<div>用户昵称:{{d.user.nickname||d.user.username||"-"}}</div>');
|
||||
tpls.push('<div>用户手机:<b class="font-code">{{d.user.phone}}</b></div>');
|
||||
} else {
|
||||
tpls.push('<div class="color-desc ta-pt-10">无用户账号</div>')
|
||||
}
|
||||
return laytpl("<div class='nowrap ta-pt-10'>" + tpls.join('') + "</div>").render(d);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '推广用户', width: 170, templet: function (d) {
|
||||
let tpls = [];
|
||||
if (d.from) {
|
||||
tpls.push('<div>用户昵称:{{d.from.nickname||d.from.username||"-"}}</div>');
|
||||
tpls.push('<div>用户手机:<b class="font-code">{{d.from.phone}}</b></div>');
|
||||
} else {
|
||||
tpls.push('<div class="color-desc ta-pt-10">无推荐人</div>')
|
||||
}
|
||||
return laytpl("<div class='nowrap ta-pt-10'>" + tpls.join('') + "</div>").render(d);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '订单信息', minWidth: 250, templet: function (d) {
|
||||
d.showPayments = "{:url('plugin-payment/record/index')}"
|
||||
let tpls = ' <a data-tips-text="查看支付信息" data-title="查看支付信息" class="layui-icon layui-icon-rmb font-s12 ta-mr-5" data-width="999px" data-close-refresh="OrderTable" data-modal="{{d.showPayments}}?orderinfo={{d.order_no}}"></a>';
|
||||
tpls += '订单号 <b class="font-code">{{d.order_no}}</b>';
|
||||
if (d.amount_real > 0) {
|
||||
if (d.payment_status > 0) {
|
||||
tpls += '<br>已支付 <b class="font-code" data-width="1024px" data-title="查看支付详情">{{str2num(d.amount_real)}}</b> 元';
|
||||
} else {
|
||||
tpls += '<br>需支付 <b class="font-code" data-width="1024px" data-title="查看支付详情">{{str2num(d.amount_real)}}</b> 元';
|
||||
}
|
||||
} else {
|
||||
tpls += '<br>无需支付';
|
||||
}
|
||||
if (d.amount_express > 0) {
|
||||
tpls += ' ( 随减 <b class="font-code">{{str2num(d.amount_reduct)}}</b> 元,含邮费 <b class="font-code">{{str2num(d.amount_express)}}</b> 元)';
|
||||
} else {
|
||||
tpls += ' ( 随减 <b class="font-code">{{str2num(d.amount_reduct)}}</b> 元,包邮免费 )';
|
||||
}
|
||||
tpls += '<br>'
|
||||
if (d.amount_balance > 0) {
|
||||
tpls += "余额 " + d.amount_balance + " 元,"
|
||||
} else {
|
||||
tpls += '未使用余额,'
|
||||
}
|
||||
if (d.amount_integral > 0) {
|
||||
tpls += "积分 " + d.amount_balance + ","
|
||||
} else {
|
||||
tpls += '未使用积分,'
|
||||
}
|
||||
if (d.coupon_code) {
|
||||
tpls += "优惠券 " + d.coupon_amount + "元,"
|
||||
} else {
|
||||
tpls += '未使用优惠券。'
|
||||
}
|
||||
|
||||
let status = laytpl('<span class="layui-badge layui-badge-middle flex-center {{d.style}}" >{{d.status}}</span>').render({
|
||||
status: ostatus[d.status], style: ostyles[d.status]
|
||||
});
|
||||
let refund = laytpl('<span class="layui-badge layui-badge-middle flex-center {{d.style}}">{{d.status}}</span>').render({
|
||||
status: rstatus[d.refund_status], style: rstyles[d.refund_status]
|
||||
});
|
||||
return '<div class="flex" style="margin-top:-4px">' + status + refund + '<div class="nowrap sub-strong-blue">' + laytpl(tpls).render(d) + '</div></div>';
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '商品详情', minWidth: 220, templet: function (d) {
|
||||
let tpls = [];
|
||||
d.items.map(function (v) {
|
||||
tpls.push(laytpl(
|
||||
'<div class="flex">' +
|
||||
' <div style="padding-top:3px">{{-showTableImage(d.gcover,false,"md")}}</div>' +
|
||||
' <div class="ta-pl-5"></div>' +
|
||||
' <div>' +
|
||||
' <div>{{d.gcode}}</div>' +
|
||||
' <div>' +
|
||||
' <span>{{d.gname}}</span>' +
|
||||
' <span class="ta-pl-5 color-desc">{{str2name(d.gspec)}}</span><br>' +
|
||||
' <span>{{d.stock_sales}}件 x {{str2num(d.price_selling)}}元/件,计 {{str2num(d.total_price_selling)}}元</span> ' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
'</div>'
|
||||
).render(v));
|
||||
});
|
||||
return tpls.join('<br>');
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '收货地址', templet: function (d) {
|
||||
if (d.address) {
|
||||
let tpls = [];
|
||||
if (d.address.status > 1) {
|
||||
tpls.push('<b>发货物流:</b><span class="ta-mr-5">{{d.company_name}}</span><span class="color-blue font-code">{{d.express_code}}</span>');
|
||||
} else {
|
||||
tpls.push('<b>发货物流:</b><span class="color-desc">未发货</span>');
|
||||
}
|
||||
tpls.push('<b>联系方式:</b><span class="ta-mr-5">{{d.user_name}}</span><span class="color-blue font-code">{{d.user_phone}}</span>');
|
||||
tpls.push('<b>收货地址:</b>{{d.region_prov}} {{d.region_city}} {{d.region_area}} {{d.region_addr}}');
|
||||
return laytpl(tpls.join('<br>')).render(d.address);
|
||||
} else {
|
||||
return '<div class="ta-pt-20 color-desc">无收货信息</div>';
|
||||
}
|
||||
}
|
||||
},
|
||||
{field: 'id', sort: true, title: '创建时间', minWidth: 170, templet: "下单时间:{{d.create_time}}<br><div>支付时间:{{d.payment_time}}<br>签收时间:{{d.confirm_time}}</div>"},
|
||||
{toolbar: '#toolbar', hide: true, title: '操作面板', width: 120, align: 'center', fixed: 'right'},
|
||||
]]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<!-- 操控面板的模板 -->
|
||||
<script type="text/html" id="toolbar">
|
||||
<!--{if auth('remove')}-->
|
||||
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除此商品吗?" data-action="{:url('remove')}" data-value="code#{{d.code}}">删 除</a>
|
||||
<!--{/if}-->
|
||||
</script>
|
||||
{/block}
|
@ -0,0 +1,93 @@
|
||||
<form action="{:sysuri()}" autocomplete="off" class="layui-form layui-form-pane form-search" method="get" onsubmit="return false">
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">会员用户</label>
|
||||
<label class="layui-input-inline">
|
||||
<input class="layui-input" name="user_keys" placeholder="请输入手机或昵称" value="{$get.user_keys|default=''}">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">订单单号</label>
|
||||
<label class="layui-input-inline">
|
||||
<input class="layui-input" name="order_no" placeholder="请输入订单单号" value="{$get.order_no|default=''}">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">发货单号</label>
|
||||
<label class="layui-input-inline">
|
||||
<input class="layui-input" name="delivery_express_code" placeholder="请输入发货单号" value="{$get.delivery_express_code|default=''}">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">订单状态</label>
|
||||
<label class="layui-input-inline">
|
||||
<select class="layui-select" name="status">
|
||||
<option value=''>- 全部订单 -</option>
|
||||
{foreach ['1'=>'预购订单','2'=>'等待支付','3'=>'等待审核','4'=>'等待发货','5'=>'已经发货','6'=>'已经完成','7'=>'已经评论','0'=>'已经取消'] as $k=>$v}
|
||||
{if input('status') eq $k.''}
|
||||
<option selected value="{$k}">{$v}</option>
|
||||
{else}
|
||||
<option value="{$k}">{$v}</option>
|
||||
{/if}{/foreach}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">下单时间</label>
|
||||
<label class="layui-input-inline">
|
||||
<input class="layui-input" data-date-range name="create_time" placeholder="请选择下单时间" value="{$get.create_time|default=''}">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">支付时间</label>
|
||||
<label class="layui-input-inline">
|
||||
<input class="layui-input" data-date-range name="payment_time" placeholder="请选择支付时间" value="{$get.payment_time|default=''}">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">收货信息</label>
|
||||
<label class="layui-input-inline">
|
||||
<input class="layui-input" name="address" placeholder="请输入收货信息" value="{$get.address|default=''}">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<button class="layui-btn layui-btn-primary" type="submit"><i class="layui-icon"></i> 搜 索</button>
|
||||
<button class="layui-btn layui-btn-primary" data-form-export="{:url('index')}?type={$type|default=''}" type="button">
|
||||
<i class="layui-icon layui-icon-export"></i> 导 出
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
require(['excel'], function (excel) {
|
||||
excel.bind(function (data, items) {
|
||||
data.forEach(function (order) {
|
||||
items.push([
|
||||
order.order_no,
|
||||
order.user.phone,
|
||||
order.user.username || order.user.nickname || '',
|
||||
order.delivery_type ? '虚拟商品' : '实物商品',
|
||||
order.payment_trade || '',
|
||||
order.payment_name || order.payment_type || '',
|
||||
order.payment_status ? '已支付' : '未支付',
|
||||
order.payment_amount || '0.00',
|
||||
order.payment_time || '',
|
||||
]);
|
||||
});
|
||||
|
||||
// 设置表头内容
|
||||
items.unshift(['订单号', '用户手机', '用户姓名', '订单类型', '支付单号', '支付方式', '支付状态', '支付金额', '支付时间']);
|
||||
|
||||
// 应用表格样式
|
||||
return this.withStyle(items, {I: 120});
|
||||
|
||||
}, '用户订单记录' + layui.util.toDateString(Date.now(), '_yyyyMMdd_HHmmss'));
|
||||
});
|
||||
</script>
|
Reference in New Issue
Block a user