增加商品管理

This commit is contained in:
Anyon 2020-09-08 16:28:07 +08:00
parent ea0e4cf47d
commit 9de81664ba
9 changed files with 958 additions and 26 deletions

View File

@ -2,7 +2,10 @@
namespace app\data\controller;
use app\data\service\GoodsService;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
use think\admin\extend\DataExtend;
/**
* 商品数据管理
@ -17,6 +20,194 @@ class ShopGoods extends Controller
*/
private $table = 'ShopGoods';
/**
* 商品数据管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '商品数据管理';
$query = $this->_query($this->table);
$query->like('name')->equal('status,cate');
// 加载对应数据
$this->type = $this->request->get('type', 'index');
if ($this->type === 'index') $query->where(['deleted' => 0]);
elseif ($this->type === 'recycle') $query->where(['deleted' => 1]);
else $this->error("无法加载 {$this->type} 数据列表!");
// 列表排序并显示
$query->order('sort desc,id desc')->page();
}
/**
* 商品选择器
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function select()
{
$query = $this->_query($this->table)->equal('status,cate')->like('name');
$query->where(['deleted' => '0'])->order('sort desc,id desc')->page();
}
/**
* 数据列表处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _page_filter(&$data)
{
$query = $this->app->db->name('ShopGoodsCate');
$query->where(['deleted' => 0, 'status' => 1])->order('sort desc,id desc');
$this->clist = DataExtend::arr2table($query->select()->toArray());
foreach ($data as &$vo) {
[$vo['list'], $vo['cate']] = [[], []];
foreach ($this->clist as $cate) if ($cate['id'] === $vo['cate_id']) $vo['cate'] = $cate;
}
}
/**
* 商品库存入库
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function stock()
{
if ($this->request->isGet()) {
$code = $this->request->get('code');
$goods = $this->app->db->name('ShopGoods')->where(['code' => $code])->find();
empty($goods) && $this->error('无效的商品信息,请稍候再试!');
$map = ['goods_code' => $code, 'status' => 1];
$goods['list'] = $this->app->db->name('ShopGoodsItem')->where($map)->select()->toArray();
$this->fetch('', ['vo' => $goods]);
} else {
[$post, $data] = [$this->request->post(), []];
if (isset($post['id']) && isset($post['goods_code']) && is_array($post['goods_code'])) {
foreach (array_keys($post['goods_id']) as $key) if ($post['goods_number'][$key] > 0) array_push($data, [
'goods_code' => $post['goods_code'][$key],
'goods_spec' => $post['goods_spec'][$key],
'stock_total' => $post['goods_number'][$key],
]);
if (!empty($data)) {
$this->app->db->name('ShopGoodsStock')->insertAll($data);
GoodsService::instance()->syncStock($post['code']);
$this->success('商品信息入库成功!');
}
}
$this->error('没有需要商品入库的数据!');
}
}
/**
* 添加商品信息
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add()
{
$this->title = '添加商品信息';
$this->isAddMode = '1';
$this->_form($this->table, 'form');
}
/**
* 编辑商品信息
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function edit()
{
$this->title = '编辑商品信息';
$this->isAddMode = '0';
$this->_form($this->table, 'form');
}
/**
* 表单数据处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _form_filter(&$data)
{
if (empty($data['code'])) {
$data['code'] = CodeExtend::uniqidNumber(12, 'G');
}
if ($this->request->isGet()) {
// 商品分类数据
$this->cates = GoodsService::instance()->getCateList('arr2table');
// 商品默认规格
$fields = 'goods_sku,goods_code,goods_spec,price_selling,price_market,number_virtual,number_express express,status';
$this->items = $this->app->db->name('ShopGoodsItem')->where(['goods_code' => $data['code']])->column($fields, 'goods_spec');
} elseif ($this->request->isPost()) {
if (empty($data['cover'])) $this->error('商品图片不能为空!');
if (empty($data['slider'])) $this->error('轮播图不能为空!');
// 商品规格保存
[$specs, $count] = [json_decode($data['lists'], true), 0];
foreach ($specs as $item) {
$count += intval($item[0]['status']);
if (empty($data['price_market'])) $data['price_market'] = $item[0]['market'];
}
if (empty($count)) $this->error('无可用的商品规格!');
$this->app->db->name('ShopGoodsItem')->where(['goods_code' => $data['code']])->update(['status' => '0']);
foreach ($specs as $item) data_save('ShopGoodsItem', [
'goods_sku' => $item[0]['sku'],
'goods_code' => $item[0]['code'],
'goods_spec' => $item[0]['spec'],
'price_market' => $item[0]['market'],
'price_selling' => $item[0]['selling'],
'number_virtual' => $item[0]['virtual'],
'number_express' => $item[0]['express'],
'status' => $item[0]['status'] ? 1 : 0,
], 'goods_spec', ['goods_id' => $data['id']]);
}
}
/**
* 表单结果处理
* @param boolean $result
*/
protected function _form_result($result)
{
if ($result && $this->request->isPost()) {
$this->success('商品编辑成功!', 'javascript:history.back()');
}
}
/**
* 上下架商品管理
* @auth true
* @throws \think\db\exception\DbException
*/
public function state()
{
$this->_save($this->table, $this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除商品信息
* @auth true
* @throws \think\db\exception\DbException
*/
public function remove()
{
$this->_delete($this->table);
}
}

View File

@ -13,20 +13,62 @@ use think\admin\Service;
class GoodsService extends Service
{
/**
* 更新商品库存数据
* @param string $code
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function syncStock($code)
{
// 商品入库统计
$query = $this->app->db->name('ShopGoodsStock');
$query->field('goods_code,goods_spec,ifnull(sum(number_stock),0) number_stock');
$stockList = $query->where(['code' => $code])->group('goods_id,goods_spec')->select()->toArray();
// 商品销量统计
$query = $this->app->db->table('shop_order a')->field('b.goods_code,b.goods_spec,ifnull(sum(b.stock_sales),0) stock_sales');
$query->leftJoin('shop_order_item b', 'a.order_no=b.order_no')->where([['b.code', '=', $code], ['a.status', 'in', [1, 2, 3, 4, 5]]]);
$salesList = $query->group('b.goods_id,b.goods_spec')->select()->toArray();
// 组装更新数据
$dataList = [];
foreach (array_merge($stockList, $salesList) as $vo) {
$key = "{$vo['goods_code']}@@{$vo['goods_spec']}";
$dataList[$key] = isset($dataList[$key]) ? array_merge($dataList[$key], $vo) : $vo;
if (empty($dataList[$key]['stock_sales'])) $dataList[$key]['stock_sales'] = 0;
if (empty($dataList[$key]['stock_total'])) $dataList[$key]['stock_total'] = 0;
}
unset($salesList, $stockList);
// 更新商品规格销量及库存
foreach ($dataList as $vo) {
$map = ['goods_code' => $code, 'goods_spec' => $vo['goods_spec']];
$set = ['stock_total' => $vo['stock_total'], 'stock_sales' => $vo['stock_sales']];
$this->app->db->name('ShopGoodsItem')->where($map)->update($set);
}
// 更新商品主体销量及库存
$this->app->db->name('ShopGoods')->where(['code' => $code])->update([
'stock_total' => intval(array_sum(array_column($dataList, 'stock_total'))),
'stock_sales' => intval(array_sum(array_column($dataList, 'stock_sales'))),
]);
return true;
}
/**
* 获取分类数据
* @param string $type 数据类型
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getCateList(): array
public function getCateList($type = 'arr2tree'): array
{
$map = ['deleted' => 0, 'status' => 1];
$query = $this->app->db->name('ShopGoodsCate');
$query->where($map)->order('sort desc,id desc');
$query->withoutField('sort,status,deleted,create_at');
return DataExtend::arr2tree($query->select()->toArray());
return DataExtend::$type($query->select()->toArray());
}
/**

View File

@ -1,10 +1,319 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{extend name="../../admin/view/main"}
</body>
</html>
{block name="content"}
{include file='shop_goods/form_style'}
<form onsubmit="return false;" id="GoodsForm" data-auto="true" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body think-box-shadow padding-left-40">
<label class="layui-form-item block relative">
<span class="color-green font-w7 label-required-prev">所属分类</span>
<select class="layui-select" name="cate" lay-search>
{foreach $cates as $cate}
{if isset($vo.cate) and $vo.cate 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>
<label class="layui-form-item block relative">
<span class="color-green font-w7">商品名称</span>
<input name="title" required class="layui-input" placeholder="请输入商品名称" value="{$vo.title|default=''}">
</label>
<div class="layui-form-item">
<span class="color-green font-w7 label-required-prev">商品图片及轮播展示图片</span>
<table class="layui-table">
<thead>
<tr>
<th style="width:90px" class="text-center">LOGO</th>
<th class="text-left">展示图片</th>
</tr>
<tr>
<td class="text-center">
<input name="image_logo" type="hidden" value="{$vo.image_logo|default=''}">
<script>$('[name="image_logo"]').uploadOneImage();</script>
</td>
<td class="text-left">
<input name="image_slider" type="hidden" value="{$vo.image_slider|default=''}">
<script>$('[name="image_slider"]').uploadMultipleImage();</script>
</td>
</tr>
</thead>
</table>
</div>
<div class="layui-clear goods-item-box">
<fieldset>
<legend class="layui-bg-gray">入会礼包配置</legend>
<div class="layui-form-item">
{foreach [0=>'非入会礼包,购买后不会影响等级',1=>'入会员礼包,购买后升级会员级别'] as $k=>$v}
{if (isset($vo.vip_mod) and $vo.vip_mod eq $k) or (empty($vo.vip_mod) and $k eq 0)}
<input type="radio" name="vip_mod" value="{$k}" title="{$v}" checked lay-filter="vip_mod">
{else}
<input type="radio" name="vip_mod" value="{$k}" title="{$v}" lay-filter="vip_mod">
{/if}{/foreach}
</div>
</fieldset>
<fieldset>
<legend class="layui-bg-gray">商品限购设置</legend>
<label class="layui-form-item">
<input class="layui-input" data-blur-number="0" name="number_limit" value="{$vo.number_limit|default=0}" placeholder="请输入商品限购数量">
<span class="help-block">限制每人可购买数量为0时不限制</span>
</label>
</fieldset>
</div>
<div class="layui-form-item">
<span class="color-green font-w7 label-required-prev">商品规格及商品SKU绑定<span class="color-red font-s12">(规格填写后不允许再次修改)</span></span>
<div ng-repeat="x in specs track by $index" style="display:none" class="margin-bottom-10" ng-class="{true:'layui-show'}[isAddMode&&specs.length>0]">
<div class="goods-spec-box padding-10 margin-0 relative" style="background:#ddd">
<span class="text-center goods-spec-title">分组</span>
<label class="label-required-null inline-block"><input ng-blur="x.name=trimSpace(x.name)" ng-model="x.name" required placeholder="请输入分组名称"></label>
<div class="pull-right">
<a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" ng-click="addSpecVal(x.list)">增加</a>
<a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" ng-class="{false:'layui-bg-gray'}[$index>0]" ng-click="upSpecRow(specs,$index)">上移</a>
<a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" ng-class="{false:'layui-bg-gray'}[$index<specs.length-1]" ng-click="dnSpecRow(specs,$index)">下移</a>
<a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" ng-click="delSpecRow(specs,$index)" ng-if="specs.length>1">删除</a>
</div>
</div>
<div class="goods-spec-box padding-10 margin-0 layui-bg-gray block relative" ng-if="x.list && x.list.length > 0">
<label class="label-required-null inline-block margin-right-10 margin-bottom-5 relative nowrap" ng-repeat="xx in x.list">
<input type="checkbox" lay-ignore ng-model="xx.check" ng-click="xx.check=checkListChecked(x.list,$event.target.checked)">
<input type="text" ng-blur="xx.name=trimSpace(xx.name)" ng-model="xx.name" ng-keyup="xx.name=$event.target.value" required placeholder="请输入规格">
<a ng-if="x.list.length>1" ng-click="x.list=delSpecVal(x.list,$index)" class="layui-icon layui-icon-close font-s12 goods-spec-close"></a>
</label>
</div>
</div>
<a ng-if="isAddMode&&specs.length<3" class="layui-btn layui-btn-sm layui-btn-primary" ng-click="addSpecRow(specs)">增加分组</a>
<table class="layui-table margin-top-10">
<thead>
<tr>
<th ng-repeat="x in specsTreeNava track by $index" class="nowrap" ng-bind="x"></th>
<th width="10%" class="text-center nowrap">商品SKU <a ng-click="batchSet('sku',0)" data-tips-text="批量设置" class="layui-icon">&#xe63c;</a></th>
<th width="10%" class="text-center nowrap">市场价格 <a ng-click="batchSet('market',2)" data-tips-text="批量设置" class="layui-icon">&#xe63c;</a></th>
<th width="10%" class="text-center nowrap">销售价格 <a ng-click="batchSet('selling',2)" data-tips-text="批量设置" class="layui-icon">&#xe63c;</a></th>
<th width="10%" class="text-center nowrap">虚拟销量 <a ng-click="batchSet('virtual',0)" data-tips-text="批量设置" class="layui-icon">&#xe63c;</a></th>
<th width="10%" class="text-center nowrap">快递计件 <a ng-click="batchSet('express',0)" data-tips-text="批量设置" class="layui-icon">&#xe63c;</a></th>
<th width="10%" class="text-center nowrap">销售状态</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="rows in specsTreeData track by $index">
<td class="layui-bg-gray" ng-if="td.show" rowspan="{{td.span}}" ng-repeat="td in rows" ng-bind="td.name"></td>
<td class="padding-0">
<label class="padding-0 margin-0">
<input ng-blur="rows[0].sku=setValue(rows[0].key,'sku',$event.target.value,'_')" class="layui-input border-0 padding-left-0 text-center" ng-model="rows[0].sku">
</label>
</td>
<td class="padding-0">
<label class="padding-0 margin-0">
<input ng-blur="rows[0].market=setValue(rows[0].key,'market',$event.target.value,'(parseFloat(_)||0).toFixed(2)')" class="layui-input border-0 padding-left-0 text-center" ng-model="rows[0].market">
</label>
</td>
<td class="padding-0">
<label class="padding-0 margin-0">
<input ng-blur="rows[0].market=setValue(rows[0].key,'selling',$event.target.value,'(parseFloat(_)||0).toFixed(2)')" class="layui-input border-0 padding-left-0 text-center" ng-model="rows[0].selling">
</label>
</td>
<td class="padding-0">
<label class="padding-0 margin-0">
<input ng-blur="rows[0].virtual=setValue(rows[0].key,'virtual',$event.target.value,'(parseInt(_)||0)')" class="layui-input border-0 padding-left-0 text-center" ng-model="rows[0].virtual">
</label>
</td>
<td class="padding-0">
<label class="padding-0 margin-0">
<input ng-blur="rows[0].express=setValue(rows[0].key,'express',$event.target.value,'(parseInt(_)||0)')" class="layui-input border-0 padding-left-0 text-center" ng-model="rows[0].express">
</label>
</td>
<td class="text-center layui-bg-gray">
<label class="think-checkbox margin-0 full-width full-height block"><input lay-ignore type="checkbox" ng-model="rows[0].status"></label>
</td>
</tr>
</tbody>
</table>
<p class="color-desc">请注意商品SKU与商品条码尽量不要重复也不能产生订单后再修改</p>
<textarea class="layui-textarea layui-hide" name="specs">{{specs}}</textarea>
<textarea class="layui-textarea layui-hide" name="lists">{{specsTreeData}}</textarea>
</div>
<div class="layui-form-item block">
<span class="label-required-prev font-w7 color-green">商品富文本内容</span>
<textarea name="content">{$vo.content|default=''|raw}</textarea>
</div>
<div class="layui-form-item text-center">
{notempty name='vo.id'}<input type="hidden" name="id" value="{$vo.id}">{/notempty}
<button class="layui-btn layui-btn-danger" ng-click="hsitoryBack()" type="button">取消编辑</button>
<button class="layui-btn" type="submit">保存商品</button>
</div>
</div>
</form>
{/block}
{block name='script'}
<textarea class="layui-hide" id="goods-specs">{$vo.specs|raw|default=''}</textarea>
<textarea class="layui-hide" id="goods-value">{$defaultValues|raw|default=''}</textarea>
<script>
/*! 表单初始化 */
window.form.render();
window.form.on('radio(vip_mod)', (function set_vip_mod(data) {
this.selecter = $('select[name="vip_level"]');
if (parseInt(data.value)) {
this.selecter.removeClass('layui-disabled').removeAttr('disabled');
} else {
this.selecter.addClass('layui-disabled').attr('disabled', 'disabled');
}
return form.render('select'), set_vip_mod;
})({value: ('{$vo.vip_mod|default="0"}')}));
/*! 加载扩展插件 */
require(['ckeditor', 'angular'], function () {
window.createEditor('[name="content"]', {height: 500});
var app = angular.module("GoodsForm", []).run(callback);
angular.bootstrap(document.getElementById(app.name), [app.name]);
function callback($rootScope) {
$rootScope.isAddMode = parseInt('{$isAddMode|default=0}');
$rootScope.maps = JSON.parse(angular.element('#goods-value').val() || '[]') || {};
$rootScope.specs = JSON.parse(angular.element('#goods-specs').val() || '[{"name":"默认分组","list":[{"name":"默认规格","check":true}]}]');
// 批量设置数值
$rootScope.batchSet = function (type, fixed) {
layer.prompt({title: '请输入数值', formType: 0}, function (value, index) {
$rootScope.$apply(function () {
var val = (parseFloat(value) || 0).toFixed(fixed);
for (var i in $rootScope.specsTreeData) for (var j in $rootScope.specsTreeData[i]) {
$rootScope.specsTreeData[i][j][type] = val;
}
});
layer.close(index);
});
};
// 返回商品列表
$rootScope.hsitoryBack = function () {
$.msg.confirm('确定要取消编辑吗?', function (index) {
history.back(), $.msg.close(index);
});
};
// 设置默认值
$rootScope.setValue = function (key, type, value, call) {
$rootScope.maps[key] || ($rootScope.maps[key] = {});
return $rootScope.maps[key][type] = eval(call.replace('_', "'" + value + "'"));
};
// 读取默认值
$rootScope.getValue = function (key, callback) {
if (typeof callback === 'function') {
return callback($rootScope.maps[key] || {});
}
return {};
};
// 去除空白字符
$rootScope.trimSpace = function (value) {
return (value + '').replace(/\s*/ig, '');
};
// 生成交叉表格数据
$rootScope.specsTreeData = [];
$rootScope.specsTreeNava = [];
// 当前商品规格发生变化时重新计算规格列表
$rootScope.$watch('specs', function () {
var data = $rootScope.specs, list = [], navs = [], table = [[]];
// 过滤无效记录
for (var i in data) {
var tmp = [];
for (var j in data[i].list) if (data[i].list[j].check && data[i].list[j].name.length > 0) {
data[i].list[j].span = 1, data[i].list[j].show = true, data[i].list[j].group = data[i].name;
tmp.push(data[i].list[j]);
}
list.push(tmp), navs.push(data[i].name);
}
$rootScope.specsTreeNava = navs;
// 表格交叉
for (var i in list) {
var tmp = [];
for (var j in table) for (var k in list[i]) tmp.push(table[j].concat(list[i][k]));
table = tmp;
}
// 表格合并
list = angular.fromJson(angular.toJson(table));
for (var i in list) {
var key = [], _key = '';
for (var td in list[i]) key.push(list[i][td].group + '::' + list[i][td].name);
for (var td in list[i]) if (_key.length === 0) {
list[i][0].key = _key = key.join(';;');
list[i][0].sku = $rootScope.getValue(_key, function (data) {
return data.sku || '0';
});
list[i][0].market = $rootScope.getValue(_key, function (data) {
return data.market || '0.00';
});
list[i][0].selling = $rootScope.getValue(_key, function (data) {
return data.selling || '0.00';
});
list[i][0].virtual = $rootScope.getValue(_key, function (data) {
return data.virtual || '0';
});
list[i][0].express = $rootScope.getValue(_key, function (data) {
return data.express || '1';
});
list[i][0].status = $rootScope.getValue(_key, function (data) {
return !!(typeof data.status !== 'undefined' ? data.status : true);
});
}
}
$rootScope.specsTreeData = list;
}, true);
// 判断规则是否能取消选择
$rootScope.checkListChecked = function (list, check) {
for (var i in list) if (list[i].check) return check;
return true;
};
// 增加整行规格分组
$rootScope.addSpecRow = function (data) {
data.push({name: '规格分组', list: [{name: '规格属性', check: true}]})
};
// 下移整行规格分组
$rootScope.dnSpecRow = function (data, $index) {
var tmp = [], cur = data[$index];
if ($index > data.length - 2) return false;
for (var i in data) {
(parseInt(i) !== parseInt($index)) && tmp.push(data[i]);
(parseInt(i) === parseInt($index) + 1) && tmp.push(cur);
}
return $rootScope.specs = tmp;
};
// 上移整行规格分组
$rootScope.upSpecRow = function (data, $index) {
var tmp = [], cur = data[$index];
if ($index < 1) return false;
for (var i in data) {
(parseInt(i) === parseInt($index) - 1) && tmp.push(cur);
(parseInt(i) !== parseInt($index)) && tmp.push(data[i]);
}
return $rootScope.specs = tmp;
};
// 移除整行规格分组
$rootScope.delSpecRow = function (data, $index) {
var tmp = [];
for (var i in data) if (parseInt(i) !== parseInt($index)) tmp.push(data[i]);
return $rootScope.specs = tmp;
};
// 增加分组的属性
$rootScope.addSpecVal = function (list) {
list.push({name: '规格属性', check: true});
};
// 移除分组的属性
$rootScope.delSpecVal = function (data, $index) {
var temp = [];
for (var i in data) if (parseInt(i) !== parseInt($index)) temp.push(data[i]);
return temp;
};
}
});
</script>
{/block}

View File

@ -0,0 +1,94 @@
<style>
.goods-item-box fieldset {
width: 260px;
height: 100px;
padding: 15px 20px;
display:inline-block;
margin: 0 15px 15px 0;
}
.inner-input {
width: 80px;
height: 14px;
padding: 1px 5px;
line-height: 12px;
}
.goods-spec-box {
position: relative;
margin: 0 10px 10px 0;
vertical-align: middle;
}
.goods-spec-title {
z-index: 2;
width: 40px;
color: #fff;
height: 28px;
position: absolute;
background: #999;
line-height: 28px;
}
.goods-spec-close {
right: 8px;
z-index: 2;
line-height: 28px;
position: absolute;
display: inline-block
}
.goods-spec-btn {
height: 28px;
margin-left: 5px !important;
line-height: 26px !important;
}
.goods-spec-box input {
z-index: 1;
width: 120px;
position: relative;
border: 1px solid #999;
padding: 5px 0 5px 45px;
display: inline-block !important;
}
.goods-spec-box input[type=checkbox] {
z-index: 2;
width: 40px;
height: 28px;
border: none;
cursor: pointer;
appearance: none;
position: absolute;
-webkit-appearance: none;
}
.goods-spec-box input[type=checkbox]:before {
top: 1px;
left: 1px;
width: 40px;
height: 26px;
content: ' ';
position: absolute;
background: #c9c9c9;
}
.goods-spec-box input[type=checkbox]:after {
top: 1px;
left: 1px;
color: #999;
width: 40px;
height: 26px;
content: '\e63f';
font-size: 16px;
line-height: 26px;
position: absolute;
text-align: center;
font-family: 'layui-icon';
}
.goods-spec-box input[type=checkbox]:checked:after {
color: #333;
content: '\e605';
}
</style>

View File

@ -1,10 +1,141 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{extend name="../../admin/view/main"}
</body>
</html>
{block name="button"}
{if auth("add")}
<button data-open='{:url("add")}' data-title="添加商品" class='layui-btn layui-btn-sm layui-btn-primary'>添加商品</button>
{/if}
{if $type eq 'index'}
<!--{if auth("state")}-->
<button data-action='{:url("state")}' data-rule="id#{key};is_deleted#1" data-csrf="{:systoken('state')}" class='layui-btn layui-btn-sm layui-btn-primary'>删除商品</button>
<!--{/if}-->
{else}
<!--{if auth("state")}-->
<button data-action='{:url("state")}' data-rule="id#{key};is_deleted#0" data-csrf="{:systoken('state')}" data-confirm="确定要恢复这些数据吗??" class='layui-btn layui-btn-sm layui-btn-primary'>恢复商品</button>
<!--{/if}-->
{/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 $type eq $k}
<li data-open="{:url('index')}?type={$k}" class="layui-this">{$v}</li>
{else}
<li data-open="{:url('index')}?type={$k}">{$v}</li>
{/if}
{/foreach}
</ul>
<div class="layui-tab-content think-box-shadow">
{include file='shop_goods/index_search'}
<table class="layui-table margin-top-10" lay-skin="line">
{notempty name='list'}
<thead>
<tr>
<th class='list-table-check-td think-checkbox'>
<label><input data-auto-none data-check-target='.list-check-box' type='checkbox'></label>
</th>
<th class='list-table-sort-td'>
<button type="button" data-reload class="layui-btn layui-btn-xs"> </button>
</th>
<th class='text-left nowrap' style="width:400px">商品信息</th>
<th class='text-left nowrap' style="width:150px"></th>
<th class='text-left nowrap' style="width:200px">商品状态</th>
<th></th>
</tr>
</thead>
{/notempty}
<tbody>
{foreach $list as $key=>$vo}
<tr data-dbclick>
<td class='list-table-check-td think-checkbox'>
<label><input class="list-check-box" value='{$vo.id}' type='checkbox'></label>
</td>
<td class='list-table-sort-td'>
<label><input data-action-blur="{:request()->url()}" data-value="id#{$vo.id};action#sort;sort#{value}" data-loading="false" value="{$vo.sort}" class="list-sort-input"></label>
</td>
<td class='nowrap'>
{notempty name='vo.cover'}
<img data-tips-image style="width:auto;height:40px" src="{$vo.cover|default=''}" class="margin-right-5" alt="img">
{/notempty}
<div class="inline-block text-top sub-span-blue">
商品编号:<span>{$vo.code|default='--'}</span>
{if auth("state") and $vo.hot_state eq 1}
<a class="layui-badge-rim color-red margin-left-5" data-action="{:url('state')}" data-value="id#{$vo.id};hot_state#0">热推</a>
{elseif auth('state')}
<a class="layui-badge-rim color-desc margin-left-5" data-action="{:url('state')}" data-value="id#{$vo.id};hot_state#1">热推</a>
{/if}
<a class="layui-badge-rim color-desc margin-left-5" data-copy="/pages/goods/detail?g={$vo.id}">复制链接</a>
<br>
商品名称:<span>{$vo.name|default='--'}</span><br>
</div>
</td>
<td class='nowrap'>
入会礼包:{if empty($vo.vip_mod)}<span class=" color-red"></span>{else}<span class="color-blue"></span> [ <span class="color-blue">{$vo.vip_level|default='0'}</span> ]{/if}<br>
所属分类:{$vo.cate.title|default='&#45;&#45;'}<br>
</td>
<td class='nowrap'>
销售状态:{eq name='vo.status' value='0'}<span class="layui-badge">已下架</span>{else}<span class="layui-badge layui-bg-green">销售中</span>{/eq}<br>
剩余库存:<span class="color-blue">{$vo.number_stock-$vo.number_sales} ( 已售 {$vo.number_sales} )</span><br>
</td>
<td class='nowrap'>
{if auth("edit")}
<a data-dbclick class="layui-btn layui-btn-sm" data-open='{:url("edit")}?id={$vo.id}'> </a>
{else}
<a data-tips-text="您没有编辑商品的权限哦!" class="layui-btn layui-btn-sm layui-btn-primary layui-disabled"> </a>
{/if}
{if $type eq 'index'}
{if isset($vo.status) and $vo.status eq 1}
<!--{if auth("forbid")}-->
<a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('forbid')}" data-value="id#{$vo.id};status#0"> </a>
<!--{else}-->
<a data-tips-text="您没有下架商品的权限哦!" class="layui-btn layui-btn-sm layui-btn-primary layui-disabled"> </a>
<!--{/if}-->
{else}
<!--{if auth("resume")}-->
<a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('resume')}" data-value="id#{$vo.id};status#1"> </a>
<!--{else}-->
<a data-tips-text="您没有上架商品的权限哦!" class="layui-btn layui-btn-sm layui-btn-primary layui-disabled"> </a>
<!--{/if}-->
{/if}
{if auth("stock")}
<a class="layui-btn layui-btn-sm layui-btn-normal" data-title="商品入库" data-modal='{:url("stock")}?id={$vo.id}'> </a>
{else}
<a data-tips-text="您没有商品入库的权限哦!" class="layui-btn layui-btn-sm layui-btn-primary layui-disabled"> </a>
{/if}
{if auth("state")}
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要移入回收站吗?" data-action="{:url('state')}" data-value="id#{$vo.id};is_deleted#1" data-csrf="{:systoken('state')}"> </a>
{/if}
{else}
{if auth("state")}
<a class="layui-btn layui-btn-sm layui-btn-normal" data-action="{:url('state')}" data-value="id#{$vo.id};is_deleted#0" data-csrf="{:systoken('state')}"> </a>
{/if}
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
</div>
</div>
{/block}
{block name='script'}
<script>form.render()</script>
{/block}

View File

@ -0,0 +1,41 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">商品名称</label>
<label class="layui-input-inline">
<input name="title" value="{:input('title','')}" placeholder="请输入商品名称" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">商品分类</label>
<div class="layui-input-inline">
<select class="layui-select" name="cate_id" lay-search>
<option value="">-- 全部分类 --</option>
{foreach $clist as $cate}{if input('cate_id','') eq $cate.id}
<option selected value="{$cate.id}">{$cate.spl}{$cate.name}</option>
{else}
<option value="{$cate.id}">{$cate.spl}{$cate.name}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">销售状态</label>
<div class="layui-input-inline">
<select class="layui-select" name="status">
{foreach [''=>'- 全部状态 -','1'=>'销售中商品','0'=>'已下架商品'] as $k=>$v}
{if input('status','-') eq $k.''}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}
{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>
</fieldset>

View File

@ -0,0 +1,58 @@
{extend name="../../admin/view/full"}
{block name="content"}
<div class="padding-25">
{include file='shop_goods/index_search'}
<table class="layui-table margin-top-10" lay-skin="line">
{notempty name='list'}
<thead>
<tr>
<th class='text-left nowrap'>商品信息</th>
<th class='text-left nowrap'></th>
<th class='text-left nowrap'>商品状态</th>
<th></th>
</tr>
</thead>
{/notempty}
<tbody>
{foreach $list as $key=>$vo}
<tr>
<td class='nowrap'>
{notempty name='vo.logo'}
<img data-tips-image style="width:auto;height:60px" src="{$vo.logo|default=''}" class="margin-right-5" alt="img">
{/notempty}
<div class="inline-block text-top">
商品编号:{$vo.id|default='--'}<br>
商品名称:{$vo.title|default='--'}<br>
</div>
</td>
<td class='nowrap'>
入会礼包:{$vo.vip_mod?"":""}<br>
所属分类:{$vo.cate.title|default='&#45;&#45;'}<br>
</td>
<td class='nowrap'>
剩余库存:{$vo.number_stock|default='0'} <br>
销售状态:{eq name='vo.status' value='0'}<span class="layui-badge">已下架</span>{else}<span class="layui-badge layui-bg-green">销售中</span>{/eq}<br>
</td>
<td class='nowrap'>
<a class="layui-btn layui-btn-sm layui-btn-normal" data-goods="{$vo.id}">选择商品</a>
</td>
</tr>
{/foreach}
</tbody>
</table>
{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
</div>
{/block}
{block name='script'}
<script>
layui.form.render();
$('[data-goods]').on('click', function () {
top.setGoodsInfo(this.getAttribute('data-goods') || '');
parent.layer.close(parent.layer.getFrameIndex(window.name));
})
</script>
{/block}

View File

@ -0,0 +1,66 @@
<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
<div class="layui-card-body padding-left-40">
<div class="layui-form-item relative block">
<span class="color-green font-w7">商品名称</span>
<span class="color-desc margin-left-5">Goods name</span>
<div class="layui-input layui-bg-gray">{$vo.title}</div>
</div>
<div class="layui-form-item">
<div class="relative block">
<span class="color-green font-w7">规格数据</span>
<span class="color-desc margin-left-5">Specification data</span>
<table class="layui-table">
<thead>
<tr>
<th class="text-left">商品规格</th>
<th class="text-center">销售价格</th>
<th class="text-center">库存统计</th>
<th class="text-center">总销统计</th>
<th class="text-center">库存剩余</th>
<th class="text-center">入库数量</th>
</tr>
</thead>
<tbody>
{foreach $vo.list as $goods}
<tr>
<td class="padding-0" width="40%">
<input class="layui-input layui-bg-gray border-0" disabled value="{$goods.goods_spec|show_goods_spec}">
</td>
<td class="padding-0" width="12%">
<input class="layui-input text-center layui-bg-gray border-0 padding-left-0" disabled value="{$goods.price_market}">
</td>
<td class="padding-0" width="12%">
<input class="layui-input text-center layui-bg-gray border-0 padding-left-0" disabled value="{$goods.number_stock}">
</td>
<td class="padding-0" width="12%">
<input class="layui-input text-center layui-bg-gray border-0 padding-left-0" disabled value="{$goods.number_sales} ">
</td>
<td class="padding-0" width="12%">
<input class="layui-input text-center layui-bg-gray border-0 padding-left-0" disabled value="{$goods.number_stock-$goods.number_sales} ">
</td>
<td class="padding-0" width="12%">
<input type="hidden" name="goods_id[]" value="{$goods.goods_id|default=''}">
<input type="hidden" name="goods_spec[]" value="{$goods.goods_spec|default=''}">
<input class="layui-input text-center border-0 padding-left-0" onblur="this.value=parseInt(this.value)||0" name="goods_number[]" value="0">
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>确定入库</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消入库吗?" data-close>取消入库</button>
</div>
</form>

View File

@ -36,7 +36,7 @@ class Test extends Controller
*/
public function jsapi_qrc()
{
$this->url = url('wechat/api.test/jsapi', [], false, true);
$this->url = sysuri('wechat/api.test/jsapi', [], false, true);
return $this->showQrc($this->url);
}
@ -49,7 +49,7 @@ class Test extends Controller
*/
public function oauth_qrc()
{
$this->url = url('wechat/api.test/oauth', [], false, true);
$this->url = sysuri('wechat/api.test/oauth', [], false, true);
return $this->showQrc($this->url);
}
@ -62,7 +62,7 @@ class Test extends Controller
*/
public function jssdk_qrc()
{
$this->url = url('wechat/api.test/jssdk', [], false, true);
$this->url = sysuri('wechat/api.test/jssdk', [], false, true);
return $this->showQrc($this->url);
}
@ -94,7 +94,7 @@ class Test extends Controller
'body' => '测试商品',
'total_fee' => '1',
'trade_type' => 'NATIVE',
'notify_url' => url('wechat/api.test/notify', [], false, true)->build(),
'notify_url' => sysuri('wechat/api.test/notify', [], false, true),
'out_trade_no' => CodeExtend::uniqidNumber(18),
'spbill_create_ip' => $this->request->ip(),
]);
@ -152,7 +152,7 @@ class Test extends Controller
'body' => "测试商品产品ID{$notify['product_id']}",
'total_fee' => '1',
'trade_type' => 'NATIVE',
'notify_url' => url('wechat/api.test/notify', [], false, true)->build(),
'notify_url' => sysuri('wechat/api.test/notify', [], false, true),
'out_trade_no' => CodeExtend::uniqidDate(18),
'spbill_create_ip' => $this->request->ip(),
];
@ -197,7 +197,7 @@ class Test extends Controller
'openid' => $user['openid'],
'total_fee' => '1',
'trade_type' => 'JSAPI',
'notify_url' => url('wechat/api.test/notify', [], false, true),
'notify_url' => sysuri('wechat/api.test/notify', [], false, true),
'out_trade_no' => CodeExtend::uniqidDate(18),
'spbill_create_ip' => $this->request->ip(),
]);