初始上传

This commit is contained in:
2026-04-04 17:27:12 +08:00
parent 4d80d28eb4
commit b7e11774ee
11191 changed files with 1588469 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 上海牛之云网络科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* 这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和使用。
* 任何企业和个人不允许对程序代码以任何形式任何目的再发布。
* =========================================================
*/
namespace addon\stock\shop\controller;
use addon\stock\dict\StockDict;
use addon\stock\model\stock\Allot;
use addon\stock\model\stock\Document;
use addon\stock\model\stock\Export;
use addon\stock\model\stock\Import;
use addon\stock\model\stock\Inventory;
use addon\stock\model\stock\Stock as StockModel;
use addon\stock\model\Store;
use app\dict\goods\GoodsDict;
use app\model\goods\GoodsCategory;
use app\model\goods\GoodsCategory as GoodsCategoryModel;
use app\model\goods\GoodsLabel;
use app\model\upload\Upload as UploadModel;
use app\shop\controller\BaseShop;
use app\model\goods\Goods;
use think\App;
/**
* 库存管理
* Class Stock
* @package addon\stock\shop\controller
*/
class Base extends BaseShop
{
public function __construct(App $app = null)
{
$this->replace = [
'ADDON_STOCK_CSS' => __ROOT__ . '/addon/stock/shop/view/public/css',
'ADDON_STOCK_JS' => __ROOT__ . '/addon/stock/shop/view/public/js',
'ADDON_STOCK_IMG' => __ROOT__ . '/addon/stock/shop/view/public/img',
'ADDON_STOCK_FILE' => __ROOT__ . '/addon/stock/shop/view/public/file',
];
parent::__construct($app);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,98 @@
<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 上海牛之云网络科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* 这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和使用。
* 任何企业和个人不允许对程序代码以任何形式任何目的再发布。
* =========================================================
*/
namespace addon\stock\shop\controller;
use addon\stock\model\stock\Transform as TransformModel;
/**
* 库存转换
* Class Transform
* @package addon\stock\shop\controller
*/
class Transform extends Base
{
/**
* 列表
*/
public function lists()
{
if (request()->isJson()) {
$page = input('page', 1);
$page_size = input('page_size', PAGE_LIST_ROWS);
$search_text = input('search_text', ''); // 名称或编码
$condition = [];
if(!empty($search_text)){
$condition[] = ['name', 'like', '%'.$search_text.'%'];
}
$transform_model = new TransformModel();
$res = $transform_model->getTransformPageList($condition, $page, $page_size, 'create_time desc', '*');
$res['data']['list'] = $transform_model->getTransformGoodsData($res['data']['list']);
return $res;
} else {
return $this->fetch('transform/lists');
}
}
/**
* 添加
*/
public function add()
{
if(request()->isJson()){
$data = [
'name' => input('name', ''),
'goods_list' => json_decode(input('goods_list', ''), true),
];
$transform_model = new TransformModel();
return $transform_model->addTransform($data);
}else{
return $this->fetch('transform/add_or_edit');
}
}
/**
* 编辑
*/
public function edit()
{
$transform_id = input('transform_id', 0);
$transform_model = new TransformModel();
if(request()->isJson()){
$data = [
'transform_id' => $transform_id,
'name' => input('name', ''),
'goods_list' => json_decode(input('goods_list', ''), true),
];
return $transform_model->editTransform($data);
}else{
$transform_info = $transform_model->getTransformInfo([['transform_id', '=', $transform_id]], '*')['data'];
if(empty($transform_info)) $this->error('转换组信息有误');
$transform_info = $transform_model->getTransformGoodsData([$transform_info])[0];
$this->assign('transform_info', $transform_info);
return $this->fetch('transform/add_or_edit');
}
}
/**
* 删除
*/
public function delete()
{
if(request()->isJson()){
$transform_ids = input('transform_ids', '');
$transform_model = new TransformModel();
return $transform_model->deleteTransform($transform_ids);
}
}
}

View File

@@ -0,0 +1,52 @@
.stock-body tr:first-child:hover td {
background-color: #FFF;
}
.stock-body, .stock-body tr, .stock-body tr td {
background-color: #FFF;
}
.stock-view {
padding: 20px;
}
.stock-search-block {
position: relative;
}
.action-btn {
cursor: pointer;
}
.empty-data {
text-align: center;
padding: 30px !important;
color: rgba(0, 0, 0, .25);
}
.total-data {
padding: 15px !important;
background: #fafafa;
color: #333;
}
.goods-money {
color: #ff4d4f;
}
.store-view {
margin-top: 10px;
}
.store-view .layui-form-label {
width: 97px;
text-align: center;
}
.store-view .layui-input-block {
margin-left: 97px;
}
.tips {
margin-bottom: 20px;
}

Binary file not shown.

View File

@@ -0,0 +1,230 @@
// 商品选择弹出框
var form, laytpl, element, table;
var goodsSelectObj = {
store_id: 0,
selectList: [], // 选中商品所有数据res
maxNum: 0, // 最大商品数量
minNum: 0, // 最小商品数量
disabled: 0, // 不可选中
cols: [], // 列名数据源
filterData: { goods_name: '' }, //筛选数据
goodsIdArr: []
};
$(function () {
$('.select-goods input[type="hidden"]').each(function () {
goodsSelectObj[$(this).attr('name')] = $(this).val();
});
setCols();
layui.use(['form', 'laytpl', 'element'], function () {
form = layui.form, laytpl = layui.laytpl, element = layui.element;
element.init();
var where = {
goods_class: goodsSelectObj.goods_class,
search_text: goodsSelectObj.search_text,
store_id: goodsSelectObj.store_id,
callback: function () {
// goodsSelectObj.selectList = [];
// goodsSelectObj.goodsIdArr = [];
$('div[lay-id="goods_list"] th[data-field="0"] input[type="checkbox"]').prop('checked', false);
$('div[lay-id="goods_list"] th[data-field="0"] .layui-unselect').removeClass('layui-form-checked');
}
}
table = new Table({
elem: '#goods_list',
url: ns.url('stock://shop/stock/goodsSelect'),
cols: goodsSelectObj.cols,
where
});
//修改一级分类箭头切换
element.on('collapse(oneCategory)', function (data) {
$(".layui-colla-title").removeClass("active");
console.log(data.show)
if (data.show) {
$(data.title).addClass("active");
}
});
//修改二级分类箭头切换
element.on('collapse(twoCategory)', function (data) {
$(".select-goods-classification .select-goods-classification .layui-colla-title").removeClass("active");
if (data.show) {
$(data.title).addClass("active");
}
});
//搜索商品名称或编码
form.on('submit(search)', function (data) {
formSearch();
});
// 勾选商品
form.on('checkbox(goods_checkbox_all)', function (data) {
var all_checked = data.elem.checked;
$("input[name='goods_checkbox']").each(function () {
var checked = $(this).prop('checked');
if (all_checked != checked) {
$(this).next().click();
}
});
dealWithTableSelectedNum();
});
// 勾选商品
form.on('checkbox(goods_checkbox)', function (data) {
var sku_id = $(data.elem).attr("data-sku-id"),
json = {};
form.render();
var spuLen = $("input[name='goods_checkbox'][data-sku-id=" + sku_id + "]:checked").length;
if (spuLen) {
json = JSON.parse($("input[name='goods_json'][data-sku-id=" + sku_id + "]").val());
delete json.LAY_INDEX;
delete json.LAY_TABLE_INDEX;
goodsSelectObj.selectList.push(json);
goodsSelectObj.goodsIdArr.push(sku_id);
} else {
for (var i = 0; i < goodsSelectObj.selectList.length; i++) {
if (goodsSelectObj.selectList[i].sku_id == sku_id) {
goodsSelectObj.selectList.splice(i, 1);
break;
}
}
for (var i = 0; i < goodsSelectObj.goodsIdArr.length; i++) {
if (goodsSelectObj.goodsIdArr[i] == sku_id) {
goodsSelectObj.goodsIdArr.splice(i, 1);
break;
}
}
}
$.unique(goodsSelectObj.goodsIdArr);
dealWithTableSelectedNum();
});
$(".select-goods .select-goods-left dd").hover(function () {
$(this).addClass("active");
}, function () {
$(this).removeClass("active");
});
$("body").off("click", ".select-goods-left dl").on("click", ".select-goods-left dl", function () {
if ($(this).hasClass("fold")) {
$(this).removeClass("fold");
} else {
$(this).addClass("fold");
}
});
$("body").off("click", ".select-goods-left dd").on("click", ".select-goods-left dd", function (event) {
$(this).parents("dl").removeClass("fold");
$(this).parents("dl").siblings().addClass("fold");
event.stopPropagation();
});
//分类切换
$("body").off("click", ".classification-item").on("click", ".classification-item", function (event) {
var categoryId = $(this).attr("data-category_id");
$(".classification-item").removeClass("text-color border-after-color");
$(this).addClass("text-color border-after-color");
$("input[name='category_id']").val(categoryId);
formSearch();
event.stopPropagation();
});
});
});
// 设置列名
function setCols() {
goodsSelectObj.cols = [
[
{
title: '<input type="checkbox" name="goods_checkbox_all" lay-skin="primary" lay-filter="goods_checkbox_all">',
unresize: 'false',
width: '8%',
templet: '#checkbox',
},
{
title: '商品',
unresize: 'false',
width: '62%',
templet: '#goods_info'
},
{
templet: `<span>{{d.real_stock||0}}</span>`,
title: '库存',
unresize: 'false',
width: '15%'
},
{
title: '单位',
unresize: 'false',
width: '15%',
templet: `<span>{{d.unit||'件'}}</span>`
},
]
];
}
//公共搜索方法
function formSearch() {
var data = {};
data.search_text = $("input[name='search_text']").val();
data.label_id = $("select[name='label_id']").val();
data.goods_class = $("select[name='goods_class']").val();
data.category_id = $("input[name='category_id']").val();
data.goods_ids = goodsSelectObj.goodsIdArr.toString();
table.reload({
page: {
curr: 1
},
where: data
});
}
//在表格底部增加了一个容器
function dealWithTableSelectedNum() {
$(".layui-table-bottom-left-container").html('已选择 ' + goodsSelectObj.goodsIdArr.length + ' 个商品');
}
function selectGoodsListener(callback) {
var res = goodsSelectObj.selectList;
var num = goodsSelectObj.goodsIdArr.length;
if (num == 0) {
layer.msg('请选择商品');
return;
}
if (goodsSelectObj.maxNum && goodsSelectObj.maxNum > 0 && num > goodsSelectObj.maxNum) {
layer.msg("所选商品数量不能超过" + goodsSelectObj.maxNum + '件');
return;
}
if (goodsSelectObj.minNum && goodsSelectObj.minNum > 0 && num < goodsSelectObj.minNum) {
layer.msg("所选商品数量不能少于" + goodsSelectObj.minNum + '件');
return;
}
callback(res);
}
// 清除选中项
function clearSelection() {
table.reload({
selected: false
});
goodsSelectObj.selectList = [];
goodsSelectObj.goodsIdArr = [];
dealWithTableSelectedNum()
}

View File

@@ -0,0 +1,447 @@
var laytpl, form, repeat_flag = false, laydate;
layui.use(['form', 'laytpl', 'table', 'util', 'laydate'], function () {
form = layui.form, laytpl = layui.laytpl, table = layui.table, util = layui.util, laydate = layui.laydate;
form.render();
fetch()
$('.stock-search').focus()
//门店选择
form.on('select(store_list)', function (data) {
var store_id = data.value;
if (defaultStoreId > 0) {
layer.confirm('更改门店,将清除已录入的单报明细,确定吗?\n', {
title: '操作提示',
btn: ['是', '否'],
closeBtn: 0,
yes: function () {
defaultStoreId = store_id;
reset();
layer.closeAll()
stockData = []
fetch()
},
btn2: function () {
form.val("formTest", {store_id: defaultStoreId})
}
});
} else {
defaultStoreId = store_id
}
});
form.render('select');
var timeTemplate = 'yyyy-MM-dd HH:mm:ss'
laydate.render({
elem: '#date_time'
, type: 'datetime'
, btns: ['now', 'confirm']
, max: util.toDateString(new Date(), timeTemplate)
, value: $('#date_time').val() ? $('#date_time').val() : util.toDateString(new Date(), timeTemplate)
});
form.on('submit(save)', function (data) {
if (stockData.length === 0) {
layer.msg('请选择产品');
return;
}
var check_return = false;
for (var i = 0; i < stockData.length; i++) {
if (stockData[i].goods_num <= 0) {
check_return = true;
layer.msg('产品:' + stockData[i].sku_name + '数量不能为空');
break;
}
}
if (check_return) return;
if (stockConfig.is_audit == 1) {
var temp_index = layer.confirm('单据保存后将处于"待审核"状态,只有经办人可以编辑或删除等操作!是否确认保存?', {
title: '操作提示',
btn: ['确定', '取消'],
yes: function () {
layer.close(temp_index);
save();
}
});
} else {
save();
}
});
});
function backStockAction() {
location.hash = ns.hash("stock://shop/stock/" + stockAction.listRoute)
}
$(".stock-search").on('keyup', function (e) {//空白行回车
if (e.keyCode == 13) {
var val = $(this).val();
$('.stock-search').blur()
if (carriage(-1, val)) {
goodsSelectByStockAction(function (res) {
res.forEach(el => {
el.goods_num = 1
if (stockAction.listRoute === 'check') {
el.goods_num = el.real_stock ? el.real_stock + 0 : 0
}
el.goods_price = el.price || 0
//库存盘点空白行无需判断是否替换某行,只需判断是否存在
var index = stockData.length ? stockData.findIndex(v => v.sku_id === el.sku_id) : -1
if (index != -1) {
stockData[index].goods_num += 1
} else {
stockData.push(el)
}
});
fetch()
}, [], {minNum: 1, search_text: val, store_id: defaultStoreId,})
}
}
});
//数据渲染(任何来源)
function fetch() {
//重新渲染
var template = $("#stock_goods_info").html();
$('.stock-body tr').not('.stock-search-line').remove();
if (ns.checkIsNotNull(stockData)) {
$.each(stockData, function (index, value) {
value.index = index
laytpl(template).render(value, function (html) {
$('.stock-search-line').before(html);
$(".stock-search-" + value.sku_id).on('keyup', function (e) {//更新dom事件需要重新绑定
if (e.keyCode == 13) {
var val = $(this).val();
$('.stock-search-' + value.sku_id).blur()
$('.stock-search').blur()
if (carriage(index, val)) {
goodsSelectByStockAction(function (res) {
res.forEach((el, resIndex) => {
el.goods_num = 1
if (stockAction.listRoute === 'check') {
el.goods_num = el.real_stock ? el.real_stock + 0 : 0
}
el.goods_price = el.price || 0
//库存盘点
var indexs = stockData.findIndex(v => v.sku_id === el.sku_id)
if (indexs != -1) {//库存不可出现相同类目
stockData[indexs].goods_num += 1//列表已有数量加一
} else if (!resIndex) {//选择的数据第一条在没有相同类目的情况下才替换列表选中行
stockData.splice(index, 1, el)
} else {
stockData.push(el)//非第一条并且列表不存在直接加入列表
}
});
fetch()
}, [], {minNum: 1, search_text: val, store_id: defaultStoreId,})
}
}
});
$('.stock-search').val('').focus()
form.render();
})
})
}
form.render();
syncData();
}
//输入回车后的处理,查询到单条的处理
function carriage(index, val) {
var num = true
$.ajax({
url: ns.url("stock://shop/stock/getskulist"),
data: {search: val, store_id: defaultStoreId},
dataType: 'JSON',
type: 'POST',
async: false,
success: function (res) {
if (res.data.length != 1) {//不是一条数据返回true打开弹框
num = true
return false
}
num = false
var data = res.data[0]
data.goods_num = 1
data.goods_price = data.price || 0
var indexs = stockData.length ? stockData.findIndex(v => v.sku_id === data.sku_id) : -1
if (index != -1) {//数据行
if (indexs != -1) {//库存盘点/先判断是否存在
stockData[indexs].goods_num += 1//存在数量累加
} else {
stockData.splice(index, 1, data)
}
} else {//空白行
var indexs = stockData.length ? stockData.findIndex(v => v.sku_id === data.sku_id) : -1
if (indexs != -1) {//库存盘点/先判断是否存在
stockData[indexs].goods_num += 1//存在数量累加
} else {
stockData.push(data)
}
}
fetch()
}
})
return num
}
function dataChange(obj) {
syncData();
}
function syncData() {
var count_num = 0, goods_money = 0;
var goods_up = 0, goods_down = 0, goods_same = 0;
var kinds_data = [];
$('.stock-tr').each(function (index) {
var obj = $(this);
var goods_sku_id = stockData[index].sku_id;
var goods_num = parseFloat(obj.find('input[name=goods_num]').val()) || 0;
var goods_price = parseFloat(obj.find('input[name=goods_price]').val()) || 0;
if (kinds_data.indexOf(goods_sku_id) == -1) {
kinds_data.push(goods_sku_id)
}
//重新采集数据
stockData[index].goods_num = goods_num;//库存数量
stockData[index].goods_price = goods_price;//库存价格
count_num += goods_num;
goods_money += goods_num * goods_price;
obj.find('.total-cost-money').text(parseFloat(goods_num * goods_price).toFixed(2));
if (stockAction.listRoute === 'check') {
$('.compare-num').eq(index).html(`<span style="color:${stockData[index].goods_num - stockData[index].real_stock > 0 ? '#15eb26' : stockData[index].goods_num - stockData[index].real_stock < 0 ? 'red' : ''}">${parseInt(stockData[index].goods_num - stockData[index].real_stock)}</span>`)
if (stockData[index].goods_num - stockData[index].real_stock > 0) goods_up++
if (stockData[index].goods_num - stockData[index].real_stock < 0) goods_down++
if (stockData[index].goods_num - stockData[index].real_stock == 0) goods_same++
}
});
$(".kinds-num").text(parseInt(kinds_data.length));
$(".count-num").text(parseFloat(count_num));
$(".goods-money").text(parseFloat(goods_money).toFixed(2));
$(".goods-up").text(parseInt(goods_up));
$(".goods-down").text(parseInt(goods_down));
$(".goods-same").text(parseInt(goods_same));
}
function reset() {
stockData = [];
fetch();
syncData();
}
function delTr(obj) {
var parent = $(obj).parents('.stock-tr');
// parent.remove();
var key = parent.data('key');//唯一值 (sku_id不承担)
stockData.splice(key, 1);//由于key使用indexindex不会随dom操作变换移除行会出错需要在删除时重新渲染
fetch()
}
function editBtn(val) {
goodsSelectByStockAction(function (res) {
if (val === 'btn') {//空白行btn选择
res.forEach(el => {
el.goods_num = 1
if (stockAction.listRoute === 'check') {
el.goods_num = el.real_stock ? el.real_stock + 0 : 0
}
el.goods_price = el.price || 0
var index = stockData.length ? stockData.findIndex(v => v.sku_id === el.sku_id) : -1
if (index != -1) {//库存盘点/先判断是否存在
//stockData[index].goods_num += 1//存在数量累加
} else {
stockData.push(el)
}
});
} else {//数据行btn选择
var parent = $(val).parents('.stock-tr');
var key = parent.data('key');//唯一值 (sku_id不承担)
res.forEach((el, index) => {//循环选中的数据
el.goods_num = 1
if (stockAction.listRoute === 'check') {
el.goods_num = el.real_stock ? el.real_stock + 0 : 0
}
el.goods_price = el.price || 0
//库存盘点
var indexs = stockData.length ? stockData.findIndex(v => v.sku_id === el.sku_id) : -1
if (indexs != -1) {//优先判断是否存在
//stockData[indexs].goods_num += 1
} else if (!index) {//不存在选中数据第一条替换btn点击行
stockData.splice(key, 1, el)
} else {
stockData.push(el)//其它直接加入
}
});
}
fetch()
}, [], {minNum: 1, search_text: '', store_id: defaultStoreId,})
}
function save() {
let obj = {}
let stock_check = true;
stockData.forEach((el,key) => {
if (ns.checkIsNotNull(obj[el.sku_id])) {
obj[el.sku_id].goods_num += el.goods_num
obj[el.sku_id].goods_price += el.goods_price
} else {
obj[el.sku_id] = el
obj[el.sku_id].goods_sku_id = el.sku_id
}
//出库库存检测
var error_msg = '';
var goods_class = obj[el.sku_id].goods_class;
if(goods_class == 6 && !(ns.getRegexp('>0float3')).test(obj[el.sku_id].goods_num)){
error_msg = '数量必须为正数且最多保留三位小数';
}else if(goods_class != 6 && !(ns.getRegexp('>0num')).test(obj[el.sku_id].goods_num)){
error_msg = '数量必须为正整数';
}else if(stockAction.saveRoute == 'stockout' && obj[el.sku_id].goods_num > obj[el.sku_id].real_stock){
error_msg = '['+obj[el.sku_id].sku_name+']库存不足';
}
if(error_msg){
stock_check = false;
$("tbody.stock-body tr[data-key='"+key+"'] input[name='goods_num']").focus();
layer.msg(error_msg);
}
})
if(stock_check === false) return false;
var data = {
stock_json: JSON.stringify(obj),
store_id: defaultStoreId,
};
data[stockAction.id] = $('input[name="' + stockAction.id + '"]').val() || 0;
if (stockAction.params) {
$.each(stockAction.params, (i, e) => {
data[i] = $(e).val();
})
}
if (repeat_flag) return false;
repeat_flag = true;
var btn = $('button[lay-filter="save"]')
btn.addClass('layui-btn-disabled');
btn.find('.layui-icon').addClass('layui-icon-loading');
btn.prop('disabled', true);
$.ajax({
type: 'post',
dataType: 'JSON',
url: ns.url("stock://shop/stock/" + stockAction.saveRoute),
async: true,
data: data,
success: function (res) {
if (res.code >= 0) {
repeat_flag = false;
btn.removeClass('layui-btn-disabled');
btn.find('.layui-icon').removeClass('layui-icon-loading');
btn.prop('disabled', false);
layer.confirm($('input[name="' + stockAction.id + '"]').val() ? '编辑成功' : '添加成功', {
title: '操作提示',
btn: ['返回列表', $('input[name="' + stockAction.id + '"]').val() ? '继续编辑' : '继续添加'],
closeBtn: 0,
yes: function (index, layero) {
location.hash = ns.hash("stock://shop/stock/" + stockAction.listRoute);
layer.close(index);
},
btn2: function (index, layero) {
repeat_flag = false;
listenerHash(); // 刷新页面
layer.close(index);
}
});
} else {
repeat_flag = false;
btn.removeClass('layui-btn-disabled');
btn.find('.layui-icon').removeClass('layui-icon-loading');
btn.prop('disabled', false);
layer.msg(res.message);
}
return false
}
})
}
/**
* 商品选择器
* @param callback 回调函数
* @param selectId 已选商品id
* @param params mode模式(spu、sku), max_num最大数量min_num 最小数量, is_virtual 是否虚拟 0 1, disabled: 开启禁用已选 0 1promotion营销活动标识 pintuan、groupbuy、fenxiao module 表示组件) goods_class: 1 实物商品 2虚拟商品 3电子商品 不传查全部
*/
function goodsSelectByStockAction(callback, selectId, params = {}) {
layui.use(['layer'], function () {
localStorage.removeItem('goods_select_id'); // 删除选中id 本地缓存
if (selectId.length) {
localStorage.setItem('goods_select_id', selectId.toString());
}
params.mode = params.mode ? params.mode : 'spu';
if (params.disabled == undefined || params.disabled == 0) {
params.disabled = 0;
} else {
params.disabled = 1;
}
params.site_id = ns_url.siteId;
params.app_module = ns_url.appModule;
params.goods_class = params.goods_class || "";
params.max_num = params.max_num || 200; // 最多选择数量
params.search_text = params.search_text || ''
// if(!params.post) params.post = 'shop';
// if (params.post == 'store') params.post += '://store';
var url = ns.url("stock://shop/stock/goodsSelect?request_mode=iframe", params);
layer.open({
title: "商品选择",
type: 2,
area: ['1000px', '720px'],
fixed: false, //不固定
btn: ['选中', '返回'],
content: url,
btn1: function (index, layero) {
var iframeWin = document.getElementById(layero.find('iframe')[0]['name']).contentWindow;//得到iframe页的窗口对象执行iframe页的方法
iframeWin.selectGoodsListener(function (obj) {
if (typeof callback == "string") {
try {
eval(callback + '(obj)');
if (!obj.length) return false
layer.close(index);
} catch (e) {
console.error('回调函数' + callback + '未定义');
}
} else if (typeof callback == "function") {
callback(obj);
if (!obj.length) return false
layer.close(index);
}
});
return false
},
btn2: function (index, layero) {
layer.close(index);
return false
}
});
});
}

View File

@@ -0,0 +1,264 @@
<div class="main-wrap">
<div class="single-filter-box">
<button type="button" class="layui-btn bg-color" onclick="add()">添加调拨单</button>
</div>
<!-- 搜索框 -->
<div class="screen layui-collapse search-nav" lay-filter="selection_panel">
<div class="layui-colla-item">
<form class="layui-colla-content layui-form layui-show">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">调拨单号:</label>
<div class="layui-input-inline">
<input type="text" name="allot_no" placeholder="请输入调拨单号" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">出库门店:</label>
<div class="layui-input-inline">
<select name="output_store_id" class="len-mid">
<option value="">全部</option>
{foreach $store_list as $store_k => $store_v}
<option value="{$store_v.store_id}">{$store_v.store_name}</option>
{/foreach}
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">入库门店:</label>
<div class="layui-input-inline">
<select name="input_store_id" class="len-mid">
<option value="">全部</option>
{foreach $store_list as $store_k => $store_v}
<option value="{$store_v.store_id}">{$store_v.store_name}</option>
{/foreach}
</select>
</div>
</div>
</div>
<div class="form-row">
<button class="layui-btn bg-color" lay-submit lay-filter="search">筛选</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</form>
</div>
</div>
<div class="layui-tab table-tab" lay-filter="doc_tab">
<div class="layui-tab-content">
<!-- 列表 -->
<table id="doc_list" lay-filter="doc_list"></table>
</div>
</div>
</div>
<!-- 操作 -->
<script type="text/html" id="operation">
<div class="table-btn">
<a class="layui-btn" lay-event="detail">查看</a>
<!-- 待审核状态下进行审核操作 -->
{{# if(d.status == 1 && {$is_audit} == 0){ }}
<!-- 只有管理员和拥有调拨单审核权限的才能审核 -->
<a class="layui-btn" lay-event="audit_agree">审核通过</a>
<a class="layui-btn" lay-event="audit_refuse">审核拒绝</a>
{{# } }}
{{# if(d.status == -1){ }}
<a class="layui-btn" lay-event="detail_refuse">拒绝理由</a>
{{# } }}
<!-- 只有经办人才能操作入库单 -->
{{# if((d.status == 1 || d.status == -1) && d.operater == {$user_info['uid']} ){ }}
<a class="layui-btn" lay-event="edit">编辑</a>
<a class="layui-btn" lay-event="delete">删除</a>
{{# } }}
</div>
</script>
<script>
var table, form, laytpl, element, layer_pass;
layui.use(['form', 'laytpl', 'element'], function() {
form = layui.form;
laytpl = layui.laytpl;
element = layui.element;
form.render();
table = new Table({
elem: '#doc_list',
url: ns.url("stock://shop/stock/allocate"),
cols: [
[{
field: 'allot_no',
title: '调拨单号',
width: '20%',
}, {
field: 'output_store_name',
title: '出库门店',
width: '15%',
}, {
field: 'input_store_name',
title: '入库门店',
width: '15%',
}, {
field: 'goods_money',
title: '商品金额',
width: '10%',
}, {
field: 'allot_time',
title: '调拨时间',
width: '20%',
templet: function(data) {
return ns.time_to_date(data.allot_time); //创建时间转换方法
}
}, {
title: '操作',
align: 'right',
toolbar: '#operation',
}]
]
});
/**
* 监听工具栏操作
*/
table.tool(function(obj) {
var data = obj.data;
switch (obj.event) {
case 'audit_agree':
// 审核通过
agree(data.allot_id);
break;
case 'audit_refuse':
// 审核拒绝
refuse(data.allot_id);
break;
case 'edit':
// 编辑
edit(data.allot_id);
break;
case 'delete':
// 删除
deleteAllot(data.allot_id);
break;
case 'detail': //查看
window.open(ns.href("stock://shop/stock/allotrecords?allot_id="+ data.allot_id));
break;
case 'detail_refuse':
layer.open({
title: '拒绝理由',
content: data.refuse_reason,
})
break;
}
});
/**
* 搜索功能
*/
form.on('submit(search)', function(data){
table.reload({
page: {
curr: 1
},
where: data.field
});
return false;
});
});
function add() {
location.hash = ns.hash("stock://shop/stock/editallocate");
}
function edit(allot_id) {
location.hash = ns.hash("stock://shop/stock/editallocate",{allot_id});
}
// 同意
var agree_repeat_flag = false;
function agree(allot_id) {
layer.confirm('确定要通过该调拨单吗?', function(index) {
if(agree_repeat_flag) return;
agree_repeat_flag = true;
layer.close(index);
$.ajax({
url: ns.url("stock://shop/stock/allocateAgree"),
data: {allot_id},
dataType: 'JSON',
type: 'POST',
success: function(res) {
agree_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
} else {
layer.msg(res.message);
}
}
});
});
}
// 拒绝
var refuse_repeat_flag = false;
function refuse(allot_id) {
layer.prompt({
title: '拒绝理由',
formType: 2,
yes: function (index, layero) {
var refuse_reason = layero.find(".layui-layer-input").val();
if (!refuse_reason) {
layer.msg('请输入拒绝理由!', {icon: 5, anim: 6});
return;
}
if (refuse_repeat_flag) return;
refuse_repeat_flag = true;
$.ajax({
url: ns.url("stock://shop/stock/allocateRefuse"),
data: {allot_id, refuse_reason},
dataType: 'JSON',
type: 'POST',
success: function (res) {
layer.msg(res.message);
refuse_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
}
}
});
layer.close(index);
}
});
}
// 删除调拨单
var delete_repeat_flag = false;
function deleteAllot(allot_id) {
layer.confirm('确定要删除该调拨单吗?', function(index) {
if(delete_repeat_flag) return;
delete_repeat_flag = true;
layer.close(index);
$.ajax({
url: ns.url("stock://shop/stock/allocateDelete"),
data: {allot_id},
dataType: 'JSON',
type: 'POST',
success: function(res) {
delete_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
} else {
layer.msg(res.message);
}
}
});
});
}
</script>

View File

@@ -0,0 +1,193 @@
<style>
.layui-table .layui-btn {
justify-content: flex-end;
padding-right: 0px;
}
.name {
display: flex;
align-content: center;
}
.name img {
max-width: inherit;
width: 60px;
height: 60px;
margin-right: 10px;
}
</style>
<div class="layui-form" lay-filter="storeform">
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">基本信息</span>
</div>
<div class="layui-card-body">
<div class="layui-row">
<div class="layui-col-md3">
<div class="layui-form-item">
<label class="layui-form-label">操作人:</label>
<div class="layui-input-block">{$detail.operater_name}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">调拨时间:</label>
<div class="layui-input-block">{:time_to_date($detail.allot_time)}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">调拨单号:</label>
<div class="layui-input-block">{$detail.allot_no}</div>
</div>
{if $detail.status == -1}
<div class="layui-form-item">
<label class="layui-form-label">拒绝理由:</label>
<div class="layui-input-block">{$detail.refuse_reason}</div>
</div>
{/if}
</div>
<div class="layui-col-md3">
<div class="layui-form-item">
<label class="layui-form-label">出库门店:</label>
<div class="layui-input-block">{$detail.output_store_name}</div>
</div>
{notempty name="$detail.out_info"}
<div class="layui-form-item">
<label class="layui-form-label">出库时间:</label>
<div class="layui-input-block">{$detail.out_info.create_time}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">经办人:</label>
<div class="layui-input-block">{$detail.out_info.operater_name}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态:</label>
<div class="layui-input-block">{$detail.out_info.status_name}</div>
</div>
{if $detail.out_info.verifier_name }
<div class="layui-form-item">
<label class="layui-form-label">审核人:</label>
<div class="layui-input-block">{$detail.out_info.verifier_name}</div>
</div>
{/if}
{if $detail.out_info.audit_time }
<div class="layui-form-item">
<label class="layui-form-label">审核时间:</label>
<div class="layui-input-block">{$detail.out_info.audit_time}</div>
</div>
{/if}
{if $detail.out_info.status == -1}
<div class="layui-form-item">
<label class="layui-form-label">拒绝理由:</label>
<div class="layui-input-block">{$detail.out_info.refuse_reason}</div>
</div>
{/if}
{/notempty}
</div>
<div class="layui-col-md3">
<div class="layui-form-item">
<label class="layui-form-label">入库门店:</label>
<div class="layui-input-block">{$detail.input_store_name}</div>
</div>
{notempty name="$detail.input_info"}
<div class="layui-form-item">
<label class="layui-form-label">入库时间:</label>
<div class="layui-input-block">{$detail.input_info.create_time}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">经办人:</label>
<div class="layui-input-block">{$detail.input_info.operater_name}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态:</label>
<div class="layui-input-block">{$detail.input_info.status_name}</div>
</div>
{if $detail.input_info.verifier_name }
<div class="layui-form-item">
<label class="layui-form-label">审核人:</label>
<div class="layui-input-block">{$detail.input_info.verifier_name}</div>
</div>
{/if}
{if $detail.input_info.audit_time }
<div class="layui-form-item">
<label class="layui-form-label">审核时间:</label>
<div class="layui-input-block">{$detail.input_info.audit_time}</div>
</div>
{/if}
{if $detail.input_info.status == -1}
<div class="layui-form-item">
<label class="layui-form-label">拒绝理由:</label>
<div class="layui-input-block">{$detail.input_info.refuse_reason}</div>
</div>
{/if}
{/notempty}
</div>
</div>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">商品明细</span>
</div>
<div class="layui-card-body">
<table class="layui-table order_goods_list" lay-filter="order_goods" lay-skin="line" lay-filter="order_goods_list">
<colgroup>
<col width="30%"/>
<col width="10%"/>
<col width="10%"/>
<col width="10%"/>
<col width="10%"/>
<col width="10%"/>
</colgroup>
<thead>
<tr>
<th>商品名称/条形码</th>
<th>商品规格</th>
<th>单位</th>
<th>数量</th>
<th>成本价(元)</th>
<th>金额(元)</th>
</tr>
</thead>
</table>
<table class="layui-table order_goods_list order_goods_list-bottom" lay-filter="order_goods" lay-skin="line" lay-filter="order_goods_list">
<colgroup>
<col width="30%"/>
<col width="10%"/>
<col width="10%"/>
<col width="10%"/>
<col width="10%"/>
<col width="10%"/>
</colgroup>
<tbody>
{foreach $detail.goods_sku_list_array as $k => $v}
<tr class="table-tr">
<td class="name">
<img src="{:img($v.goods_sku_img,'small')}" alt="">
<span>{$v.goods_sku_name}</span>
</td>
{if $v.goods_sku_spec && $v.goods_sku_spec !=''}
<td>{$v.goods_sku_spec}</td>
{else/}
<td>-</td>
{/if}
{if $v.goods_unit && $v.goods_unit !=''}
<td>{$v.goods_unit}</td>
{else/}
<td></td>
{/if}
<td>{$v.goods_num}</td>
<td>{$v.goods_price}</td>
<td>{$v.total_goods_money}</td>
</tr>
{/foreach}
</tbody>
</table>
<label style="display: flex;justify-content: flex-end;padding-right: 13px;">合计:共{$detail.goods_count}种商品{$detail.goods_price}件,合计金额:<span style="color: #ff0000;">{$detail.goods_total_price}</span></label>
</div>
</div>
</div>

View File

@@ -0,0 +1,269 @@
<div class="main-wrap">
<div class="single-filter-box">
<button type="button" class="layui-btn bg-color" onclick="add()">添加盘点单</button>
</div>
<!-- 搜索框 -->
<div class="screen layui-collapse search-nav" lay-filter="selection_panel">
<div class="layui-colla-item">
<form class="layui-colla-content layui-form layui-show">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">盘点单号:</label>
<div class="layui-input-inline">
<input type="text" name="search_text" placeholder="请输入入库单号" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">门店:</label>
<div class="layui-input-inline">
<select name="store_id" class="len-mid">
<option value="">全部</option>
{foreach $store_list as $store_k => $store_v}
<option value="{$store_v.store_id}">{$store_v.store_name}</option>
{/foreach}
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">审核状态:</label>
<div class="layui-input-inline">
<select name="status" lay-filter="status" class="len-mid">
<option value="">全部</option>
{foreach name="$status_list" item="vo"}
<option value="{$vo.status}">{$vo.name}</option>
{/foreach}
</select>
</div>
</div>
</div>
<div class="form-row">
<button class="layui-btn bg-color" lay-submit lay-filter="search">筛选</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</form>
</div>
</div>
<div class="layui-tab table-tab">
<div class="layui-tab-content">
<table id="doc_list" lay-filter="doc_list"></table>
</div>
</div>
</div>
<!-- 操作 -->
<script type="text/html" id="operation">
<div class="table-btn">
<a class="layui-btn" lay-event="detail">查看</a>
<!-- 待审核状态下进行审核操作 -->
{{# if(d.status == 1 && {$is_audit} == 0){ }}
<!-- 只有管理员和拥有盘点单审核权限的才能审核 -->
<a class="layui-btn" lay-event="audit_agree">审核通过</a>
<a class="layui-btn" lay-event="audit_refuse">审核拒绝</a>
{{# } }}
{{# if(d.status == -1){ }}
<a class="layui-btn" lay-event="detail_refuse">拒绝理由</a>
{{# } }}
<!-- 只有经办人才能操作入库单 -->
{{# if((d.status == 1 || d.status == -1) && d.operater == {$user_info['uid']} ){ }}
<a class="layui-btn" lay-event="edit">编辑</a>
<a class="layui-btn" lay-event="delete">删除</a>
{{# } }}
</div>
</script>
<script>
var table, form, laytpl, element, layer_pass;
layui.use(['form', 'laytpl', 'element'], function() {
form = layui.form;
laytpl = layui.laytpl;
element = layui.element;
form.render();
table = new Table({
elem: '#doc_list',
url: ns.url("stock://shop/stock/check"),
cols: [
[{
field: 'inventory_no',
title: '盘点单号',
width: '20%',
}, {
field: 'store_name',
title: '盘点门店',
}, {
field: 'status_name',
title: '审核状态',
width: '10%',
}, {
title: '操作人',
width: '15%',
templet: function(data) {
var html = '';
html += '盘点人:' + data.operater_name + '<br/>';
if(data.verifier_name) html += '审核人:' + data.verifier_name;
return html;
}
}, {
title: '操作时间',
width: '15%',
templet: function(data) {
var html = '';
html += '制单时间:' + ns.time_to_date(data.create_time) + '<br/>';
if(data.action_time) html += '盘点时间:' + ns.time_to_date(data.action_time) + '<br/>';
if (data.audit_time) html += '审核时间:' + ns.time_to_date(data.audit_time);
return html;
}
}, {
title: '操作',
toolbar: '#operation',
align: 'right',
}]
]
});
/**
* 监听工具栏操作
*/
table.tool(function(obj) {
var data = obj.data;
switch (obj.event) {
case 'audit_agree':
// 审核通过
agree(data.inventory_id);
break;
case 'audit_refuse':
// 审核拒绝
refuse(data.inventory_id);
break;
case 'edit':
// 编辑
edit(data.inventory_id);
break;
case 'delete':
// 删除
deleteInventory(data.inventory_id);
break;
case 'detail': //查看
location.hash = ns.hash("stock://shop/stock/inventorydetail?inventory_no="+ data.inventory_no);
break;
case 'detail_refuse':
layer.open({
title: '拒绝理由',
content: data.refuse_reason,
})
break;
}
});
// 搜索功能
form.on('submit(search)', function(data){
table.reload({
page: {
curr: 1
},
where: data.field
});
return false;
});
});
function add() {
location.hash = ns.hash("stock://shop/stock/editcheck");
}
function edit(inventory_id) {
location.hash = ns.hash("stock://shop/stock/editcheck",{inventory_id});
}
// 同意
var agree_repeat_flag = false;
function agree(inventory_id) {
layer.confirm('确定要通过该盘点单吗?', function(index) {
if(agree_repeat_flag) return;
agree_repeat_flag = true;
layer.close(index);
$.ajax({
url: ns.url("stock://shop/stock/inventoryAgree"),
data: {inventory_id},
dataType: 'JSON',
type: 'POST',
success: function(res) {
agree_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
} else {
layer.msg(res.message);
}
}
});
});
}
// 拒绝
var refuse_repeat_flag = false;
function refuse(inventory_id) {
layer.prompt({
title: '拒绝理由',
formType: 2,
yes: function (index, layero) {
var refuse_reason = layero.find(".layui-layer-input").val();
if (!refuse_reason) {
layer.msg('请输入拒绝理由!', {icon: 5, anim: 6});
return;
}
if (refuse_repeat_flag) return;
refuse_repeat_flag = true;
$.ajax({
url: ns.url("stock://shop/stock/inventoryRefuse"),
data: {inventory_id, refuse_reason},
dataType: 'JSON',
type: 'POST',
success: function (res) {
layer.msg(res.message);
refuse_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
}
}
});
layer.close(index);
}
});
}
// 删除盘点单
var delete_repeat_flag = false;
function deleteInventory(inventory_id) {
layer.confirm('确定要删除该盘点单吗?', function(index) {
if(delete_repeat_flag) return;
delete_repeat_flag = true;
layer.close(index);
$.ajax({
url: ns.url("stock://shop/stock/inventoryDelete"),
data: {inventory_id},
dataType: 'JSON',
type: 'POST',
success: function(res) {
delete_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
} else {
layer.msg(res.message);
}
}
});
});
}
</script>

View File

@@ -0,0 +1,40 @@
<div class="layui-form form-wrap">
<div class="layui-form-item">
<label class="layui-form-label">是否开启单据审核:</label>
<div class="layui-input-block">
<input type="radio" name="is_audit" value="1" title="是" {if $stock_config.is_audit eq '1'}checked{/if} >
<input type="radio" name="is_audit" value="0" title="否" {if $stock_config.is_audit eq '0'}checked{/if}>
</div>
<div class="word-aux">开启后,如果存在盘点单据,实物、称重商品将无法编辑库存、规格项(可以新增规格值),操作出入库、调拨、盘点等操作将会进行审核流程</div>
</div>
<div class="form-row">
<button class="layui-btn" lay-submit lay-filter="save">保存</button>
</div>
</div>
<script>
layui.use(['form'], function() {
var form = layui.form,
repeat_flag = false; //防重复标识
form.render();
form.on('submit(save)', function(data) {
if (repeat_flag) return;
repeat_flag = true;
$.ajax({
url: ns.url("stock://shop/stock/config"),
data: data.field,
dataType: 'JSON',
type: 'POST',
success: function(res) {
repeat_flag = false;
layer.msg(res.message);
}
});
});
});
</script>

View File

@@ -0,0 +1,661 @@
<style>
.stock-body tr:first-child:hover td {
background-color: #fff
}
.stock-body,
.stock-body tr,
.stock-body tr td {
background-color: #fff
}
.stock-view {
padding: 20px
}
.stock-search-block {
position: relative
}
.action-btn {
cursor: pointer
}
.total-data {
padding: 15px !important;
background: #fafafa;
color: #333
}
.goods-money {
color: #ff4d4f;
}
.store-view {
margin-top: 10px
}
.store-view .layui-form-label {
width: 100px;
text-align: center
}
.store-view .layui-input-block {
margin-left: 100px
}
.stock-title-body {
position: relative;
}
.stock-title-body span {
position: absolute;
top: 5px;
right: 5px;
background-color: #fff;
z-index: 10;
cursor: pointer;
}
.stock-title-body input {
padding-right: 25px;
}
input.stock-search {
border-width: 0;
}
input.stock-search:focus {
border-width: 1px;
}
.layui-table th,
.layui-table td {
padding: 7px 30px !important;
}
.layui-table .layui-input {
height: 28px !important;
}
button[lay-filter='save'] .layui-icon-loading {
animation: loding-rotate 1s linear infinite; /* 设置动画效果 */
transform-origin: center;
display: inline-block;
}
.remark{
width: 614px;
}
@keyframes loding-rotate {
0% { transform: rotate(0); } /* 起始位置 */
100% { transform: rotate(360deg); } /* 结束位置,旋转一周 */
}
</style>
<div class="layui-form form" lay-filter="formTest">
<div class="stock-view">
<div class="store-view">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">调拨单号:</label>
<div class="layui-input-block len-mid">
{if isset($allot_info)}
<input type="text" value="{$allot_info['allot_no']}" name="allot_no" class="layui-input len-mid">
{else /}
<input type="text" value="{$allot_no}" name="allot_no" class="layui-input len-mid">
{/if}
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label"><span class="required">*</span>出库门店:</label>
<div class="layui-input-block len-mid">
<select name="output_store_id" lay-verify="required" lay-filter="store_list" class="len-mid">
{foreach $store_list as $store_k => $store_v}
{if isset($allot_info)}
<option value="{$store_v.store_id}" {if $allot_info['output_store_id']==$store_v['store_id']} {php} $default_store_id=$store_v['store_id']; {/php} selected {/if}>{$store_v.store_name}</option>
{else /}
<option value="{$store_v.store_id}" {if $store_k==0} {php} $default_store_id=$store_v['store_id']; {/php} selected {/if}>{$store_v.store_name}</option>
{/if}
{/foreach}
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">当前操作人:</label>
<div class="layui-input-block len-mid">
<span>{$user_info['username']}</span>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label"><span class="required">*</span>入库门店:</label>
<div class="layui-input-block len-mid">
<select name="input_store_id" class="len-mid"></select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label"><span class="required">*</span>调拨时间:</label>
<div class="layui-input-block len-mid">
<input type="text" name="allot_time" class="layui-input" id="allot_time" placeholder="调拨日期" value="{$allot_info ? time_to_date($allot_info['allot_time']) : date('Y-m-d H:i:s')}">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label"><span class="required"></span>备注:</label>
<div class="layui-input-block remark">
<textarea class="layui-textarea" maxlength="100" name="remark" placeholder="请输入备注">{$allot_info['remark'] ?? ''}</textarea>
</div>
</div>
</div>
</div>
<table class="layui-table" lay-size="lg">
<colgroup>
<col width="350">
<col width="120">
<col width="90">
<col width="110">
<col width="110">
<col width="120">
<col width="90">
</colgroup>
<thead>
<tr>
<th>产品名称/规格/编码</th>
<th>当前库存</th>
<th>单位</th>
<th>数量</th>
<th>成本价</th>
<th>总金额</th>
<th>操作</th>
</tr>
</thead>
<tbody class="stock-body">
<tr class="stock-search-line">
<td class="stock-search-block">
<div class="stock-title-body">
<input type="text" class="layui-input stock-search" placeholder="请输入产品名称/规格/编码" />
<span class="iconfont icontuodong" onclick="editBtn('btn')"></span>
</div>
</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="7" class="total-data">合计: 共<span class="kinds-num">0</span>种,<span class="count-num">0</span>件产品,合计金额:<span class="goods-money">0</span></td>
</tr>
</tfoot>
</table>
{notempty name="$allot_info"}
<input type="hidden" name="allot_id" value="{$allot_info['allot_id']}">
<input type="hidden" name="allot_goods_list" value='{:json_encode($allot_info["goods_list"])}'>
{/notempty}
<div class="form-row">
<button class="layui-btn" lay-submit lay-filter="save"><span class="layui-icon"></span>确认调拨</button>
<button class="layui-btn layui-btn-primary" onclick="backStockAllocate()">返回</button>
</div>
</div>
</div>
<script type="text/html" id="stock_goods_info">
<tr class="stock-tr" data-key='{{ d.index }}' >
<td>
{{d.sku_name}}
</td>
<!-- 库存 -->
<td>{{ d.real_stock || 0 }}</td>
<!-- 单位 -->
<td>{{ d.unit || '件' }}</td>
<!-- 数量 -->
<td>
<input type="number" class="layui-input stock-num" name="goods_num" value="{{ d.goods_num || 0 }}" placeholder="0" onchange="dataChange(this)"/>
</td>
<!-- 成本价 -->
<td>
<span>{{ d.cost_price || 0 }}</span>
</td>
<!-- 成本总价 -->
<td>
<span class="total-cost-money">{{ d.goods_money || 0 }}</span>
</td>
<td>
<a class="text-color action-btn" onclick="delTr(this)">删除</a>
</td>
</tr>
</script>
<script>
var count = 0;
var stockDataObj = JSON.parse($("input[name='allot_goods_list']").val() || '{}');// 库存数据
var stockData = Object.values(stockDataObj)
var laytpl, form, laydate;
var defaultStoreId = {$default_store_id ?? 0};
var store_list = {:json_encode($store_list, true) };
layui.use(['form', 'laytpl', 'table', 'laydate'], function () {
form = layui.form, laytpl = layui.laytpl, table = layui.table, laydate = layui.laydate;
form.render();
fetch()
var repeat_flag = false;
laydate.render({
elem: '#allot_time'
, type: 'datetime'
, max: '{$start_time}'
, value: $('#allot_time').val() ? $('#allot_time').val() : '{$default_time}'
});
setStore();
{if isset($allot_info)}
$('[name="input_store_id"]').val("{$allot_info['input_store_id']}");
{/if}
$('.stock-search').focus()
form.render('select');
//门店选择
form.on('select(store_list)', function (data) {
var store_id = data.value;
if (defaultStoreId > 0) {
layer.confirm('更改门店,将清除已录入的单报明细,确定吗?\n', {
title: '操作提示',
btn: ['是', '否'],
closeBtn: 0,
yes: function () {
defaultStoreId = store_id;
reset();
layer.closeAll()
stockData = []
fetch()
setStore()
},
btn2: function () {
form.val("formTest", { output_store_id: defaultStoreId })
}
});
} else {
defaultStoreId = store_id
}
});
form.render('select');
form.on('submit(save)', function (data) {
var field = data.field;
if (!field.input_store_id) {
layer.msg('请选择入库门店');
return false;
}
var stock_json = [];
var check_return = true;
if ($('.stock-tr').length <= 0) {
layer.msg('请选择产品');
return false;
}
$('.stock-tr').each(function (index) {
var obj = $(this);
var goods_num = Number(obj.find('input[name=goods_num]').val() || 0);
var real_stock = Number(stockData[index].real_stock);
var goods_class = stockData[index].goods_class;
var error_msg = '';
if(goods_class == 6 && !(ns.getRegexp('>0float3')).test(goods_num)){
error_msg = '称重商品调拨数量必须为正数且最多保留三位小数';
}else if(goods_class != 6 && !(ns.getRegexp('>0num')).test(goods_num)){
error_msg = '调拨数量必须为正整数';
}else if (goods_num > real_stock) {
error_msg = '可调拨数量不足';
}
if(error_msg){
check_return = false;
obj.find('input[name=goods_num]').focus();
layer.msg(error_msg);
return false;
}
stockData[index].goods_sku_id = stockData[index].sku_id;
});
if (!check_return) return false;
if (repeat_flag) return false;
repeat_flag = true;
field.goods_sku_list = JSON.stringify(stockData);
var btn = $('button[lay-filter="save"]')
btn.addClass('layui-btn-disabled');
btn.find('.layui-icon').addClass('layui-icon-loading');
btn.prop('disabled', true);
$.ajax({
type: 'post',
dataType: 'JSON',
url: ns.url("stock://shop/stock/editallocate"),
async: true,
data: field,
success: function (res) {
if (res.code >= 0) {
location.hash = ns.hash("stock://shop/stock/allocate");
} else {
repeat_flag = false;
btn.removeClass('layui-btn-disabled');
btn.find('.layui-icon').removeClass('layui-icon-loading');
btn.prop('disabled', false);
layer.msg(res.message);
}
return false;
}
})
});
});
function backStockAllocate() {
location.hash = ns.hash("stock://shop/stock/allocate")
}
$(".stock-search").on('keyup', function (e) {
//空白行回车
if (e.keyCode == 13) {
var val = $(this).val();
$('.stock-search').blur()
if (carriage(-1, val)) {
goodsSelectByAllocate(function (res) {
res.forEach(el => {
el.goods_num = 1
el.goods_price = el.cost_price || 0
//库存盘点空白行无需判断是否替换某行,只需判断是否存在
var index = stockData.length ? stockData.findIndex(v => v.sku_id === el.sku_id) : -1
if (index != -1) {
stockData[index].goods_num += 1
} else {
stockData.push(el)
}
});
fetch()
}, [], { minNum: 1, search_text: val, store_id: defaultStoreId, })
}
}
});
//数据渲染(任何来源)
function fetch() {
//重新渲染
var template = $("#stock_goods_info").html();
$('.stock-body tr').not('.stock-search-line').remove();
if (ns.checkIsNotNull(stockData)) {
$.each(stockData, function (index, value) {
value.index = index
laytpl(template).render(value, function (html) {
$('.stock-search-line').before(html);
$(".stock-search-" + value.sku_id).on('keyup', function (e) {
//更新dom事件需要重新绑定
if (e.keyCode == 13) {
var val = $(this).val();
if (val != '') {
$('.stock-search').blur()
if (carriage(index, val)) {
goodsSelectByAllocate(function (res) {
res.forEach((el, resIndex) => {
el.goods_num = 1
el.goods_price = el.cost_price || 0
//库存盘点
var indexs = stockData.findIndex(v => v.sku_id === el.sku_id)
if (indexs != -1) {
//库存不可出现相同类目
stockData[indexs].goods_num += 1
//列表已有数量加一
} else if (!resIndex) {
//选择的数据第一条在没有相同类目的情况下才替换列表选中行
stockData.splice(index, 1, el)
} else {
stockData.push(el)
//非第一条并且列表不存在直接加入列表
}
});
fetch()
}, [], { minNum: 1, search_text: val, store_id: defaultStoreId, })
}
} else {
layer.msg('请输入内容');
}
}
});
$('.stock-search').val('').focus()
form.render();
})
})
}
form.render();
syncData();
}
//输入回车后的处理,查询到单条的处理
function carriage(index, val) {
var num = true
$.ajax({
url: ns.url("stock://shop/stock/getskulist"),
data: { search: val, store_id: defaultStoreId },
dataType: 'JSON',
type: 'POST',
async: false,
success: function (res) {
if (res.data.length != 1) {
//不是一条数据返回true打开弹框
num = true
return false
}
num = false
var data = res.data[0]
data.goods_num = 1
data.goods_price = data.cost_price || 0
var indexs = stockData.length ? stockData.findIndex(v => v.sku_id === data.sku_id) : -1
if (index != -1) {
//数据行
if (indexs != -1) {
//库存盘点/先判断是否存在
stockData[indexs].goods_num += 1
//存在数量累加
} else {
stockData.splice(index, 1, data)
}
} else {
//空白行
var indexs = stockData.length ? stockData.findIndex(v => v.sku_id === data.sku_id) : -1
if (indexs != -1) {
//库存盘点/先判断是否存在
stockData[indexs].goods_num += 1
//存在数量累加
} else {
stockData.push(data)
}
}
fetch()
}
})
return num
}
function dataChange(obj) {
syncData();
}
function syncData() {
var count_num = 0, goods_money = 0;
var kinds_data = [];
$('.stock-tr').each(function (index) {
var obj = $(this);
var goods_sku_id = stockData[index].sku_id;
var goods_num = parseFloat(obj.find('input[name=goods_num]').val()) || 0;
if (kinds_data.indexOf(goods_sku_id) == -1) {
kinds_data.push(goods_sku_id)
}
//重新采集数据
//库存数量
stockData[index].goods_num = goods_num;
//库存价格
var goods_price = stockData[index].cost_price;
count_num += goods_num;
goods_money += goods_num * goods_price;
obj.find('.total-cost-money').text(parseFloat(goods_num * goods_price).toFixed(2));
});
$(".kinds-num").text(parseInt(kinds_data.length));
$(".count-num").text(parseFloat(count_num));
$(".goods-money").text(parseFloat(goods_money).toFixed(2));
}
function reset() {
stockData = [];
fetch();
syncData();
}
function delTr(obj) {
var parent = $(obj).parents('.stock-tr');
// parent.remove();
var key = parent.data('key');
//唯一值 (sku_id不承担)
stockData.splice(key, 1);
//由于key使用indexindex不会随dom操作变换移除行会出错需要在删除时重新渲染
fetch()
}
function editBtn(val) {
goodsSelectByAllocate(function (res) {
if (val === 'btn') {
//空白行btn选择
res.forEach(el => {
el.goods_num = 1
el.goods_price = el.price || 0
var index = stockData.length ? stockData.findIndex(v => v.sku_id === el.sku_id) : -1
if (index != -1) {
//库存盘点/先判断是否存在
stockData[index].goods_num += 1
//存在数量累加
} else {
stockData.push(el)
}
});
} else {
//数据行btn选择
var parent = $(val).parents('.stock-tr');
var key = parent.data('key');
//唯一值 (sku_id不承担)
res.forEach((el, index) => {
//循环选中的数据
el.goods_num = 1
el.goods_price = el.price || 0
//库存盘点
var indexs = stockData.length ? stockData.findIndex(v => v.sku_id === el.sku_id) : -1
if (indexs != -1) {
//优先判断是否存在
stockData[indexs].goods_num += 1
} else if (!index) {
//不存在选中数据第一条替换btn点击行
stockData.splice(key, 1, el)
} else {
stockData.push(el)
//其它直接加入
}
});
}
fetch()
}, [], { minNum: 1, search_text: '', store_id: defaultStoreId, })
}
/**
* 商品选择器
* @param callback 回调函数
* @param selectId 已选商品id
* @param params mode模式(spu、sku), max_num最大数量min_num 最小数量, is_virtual 是否虚拟 0 1, disabled: 开启禁用已选 0 1promotion营销活动标识 pintuan、groupbuy、fenxiao module 表示组件) is_disabled_goods_type: 1表示关闭商品类型筛选 0表示开启商品类型筛选 goods_type: 1 实物商品 2虚拟商品 3电子商品 不传查全部
*/
function goodsSelectByAllocate(callback, selectId, params = {}) {
layui.use(['layer'], function () {
localStorage.removeItem('goods_select_id'); // 删除选中id 本地缓存
if (selectId.length) {
localStorage.setItem('goods_select_id', selectId.toString());
}
params.mode = params.mode ? params.mode : 'spu';
if (params.disabled == undefined || params.disabled == 0) {
params.disabled = 0;
} else {
params.disabled = 1;
}
params.site_id = ns_url.siteId;
params.app_module = ns_url.appModule;
params.is_disabled_goods_type = params.is_disabled_goods_type || 0;
params.goods_type = params.goods_type || "";
params.max_num = params.max_num || 200; // 最多选择数量
params.search_text = params.search_text || ''
// if(!params.post) params.post = 'shop';
// if (params.post == 'store') params.post += '://store';
var url = ns.url("stock://shop/stock/goodsSelect?request_mode=iframe", params);
layer.open({
title: "商品选择",
type: 2,
area: ['1000px', '720px'],
fixed: false, //不固定
btn: ['选中', '返回'],
content: url,
btn1: function (index, layero) {
var iframeWin = document.getElementById(layero.find('iframe')[0]['name']).contentWindow;//得到iframe页的窗口对象执行iframe页的方法
iframeWin.selectGoodsListener(function (obj) {
if (typeof callback == "string") {
try {
eval(callback + '(obj)');
if (!obj.length) return false
layer.close(index);
} catch (e) {
console.error('回调函数' + callback + '未定义');
}
} else if (typeof callback == "function") {
callback(obj);
if (!obj.length) return false
layer.close(index);
}
});
return false
},
btn2: function (index, layero) {
layer.close(index);
return false
}
});
});
}
function setStore() {
var output_store_id = $('[name="output_store_id"]').val();
let html = '';
$.each(store_list, function (i, e) {
if (e.store_id != output_store_id) {
html += '<option value="' + e.store_id + '">' + e.store_name + '</option>';
}
});
$('[name="input_store_id"]').html(html);
form.render();
}
</script>

View File

@@ -0,0 +1,204 @@
<link rel="stylesheet" type="text/css" href="ADDON_STOCK_CSS/stock.css" />
<style>
.stock-title-body{
position: relative;
}
.stock-title-body span{
position: absolute;
top:5px;
right:5px;
background-color: #fff;
z-index: 10;
cursor: pointer;
}
.stock-title-body input{
padding-right: 25px;
}
input.stock-search{
border-width: 0;
}
input.stock-search:focus{
border-width: 1px;
}
.layui-table th,.layui-table td{
padding: 7px 30px !important;
}
.layui-table .layui-input{
height: 28px !important;
}
/* input.stock-search:focus+span{
display: block;
} */
.goods-up{
color: #15eb26;
}
.goods-down{
color: red;
}
button[lay-filter='save'] .layui-icon-loading {
animation: loding-rotate 1s linear infinite; /* 设置动画效果 */
transform-origin: center;
display: inline-block;
}
.remark{
width: 611px;
}
@keyframes loding-rotate {
0% { transform: rotate(0); } /* 起始位置 */
100% { transform: rotate(360deg); } /* 结束位置,旋转一周 */
}
</style>
<div class="layui-form form" lay-filter="formTest">
<div class="stock-view">
{if $stock_config.is_audit == 1}
<div class="tips text-color">说明:待审核状态下只有经办人允许修改,只有变为已审核状态后才会使库存发生变化,已审核状态的单据不允许再修改。</div>
{/if}
<div class="store-view">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">盘点单号:</label>
<div class="layui-input-block len-mid">
{if isset($inventory_info)}
<input type="text" value="{$inventory_info['inventory_no']}" name="inventory_no" class="layui-input len-mid">
{else /}
<input type="text" value="{$inventory_no}" name="inventory_no" class="layui-input len-mid">
{/if}
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label"><span class="required">*</span>门店:</label>
<div class="layui-input-block len-mid">
<select name="store_id" lay-verify="required" lay-filter="store_list" class="len-mid" >
<option value="">请选择</option>
{foreach $store_list as $store_k => $store_v}
{if isset($inventory_info)}
<option value="{$store_v.store_id}" {if $inventory_info['store_id']==$store_v['store_id']}selected {php} $default_store_id=$store_v['store_id']; {/php}{/if}>{$store_v.store_name}</option>
{else /}
<option value="{$store_v.store_id}" {if $store_k == 0}selected {php} $default_store_id = $store_v['store_id']; {/php}{/if}>{$store_v.store_name}</option>
{/if}
{/foreach}
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">盘点时间:</label>
<div class="layui-input-block len-mid">
<input type="text" class="layui-input" name="date_time" value="{$inventory_info ? time_to_date($inventory_info['action_time']) : date('Y-m-d H:i:s')}" placeholder="盘点时间" id="date_time" readonly>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">当前操作人:</label>
<div class="layui-input-block len-mid">
<span>{$user_info['username']}</span>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label"><span class="required"></span>备注:</label>
<div class="layui-input-block remark">
<textarea class="layui-textarea" maxlength="100" name="remark" placeholder="请输入备注">{$inventory_info['remark'] ?? ''}</textarea>
</div>
</div>
</div>
</div>
<table class="layui-table" lay-size="lg">
<colgroup>
<col width="450">
<col width="120">
<col width="120">
<col>
<col width="200">
<col width="120">
<col width="90">
</colgroup>
<thead>
<tr>
<th>商品名称/规格/编码</th>
<th>当前库存</th>
<th>销售库存</th>
<th>单位</th>
<th>实盘数量</th>
<th>盈亏数量</th>
<th>操作</th>
</tr>
</thead>
<tbody class="stock-body">
<tr class="stock-search-line">
<td class="stock-search-block">
<div class="stock-title-body">
<input type="text" class="layui-input stock-search" placeholder="请输入产品名称/规格/编码" />
<span class="iconfont icontuodong" onclick="editBtn('btn')"></span>
</div>
</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="8" class="total-data">合计: 共<span class="kinds-num">0</span>种商品, 盘盈:<span class="goods-up">0</span>种, 盘亏:<span class="goods-down">0</span>种, 持平:<span class="goods-same">0</span></td>
</tr>
</tfoot>
</table>
{notempty name="$inventory_info"}
<input type="hidden" name="inventory_id" value="{$inventory_info['inventory_id']}">
<input type="hidden" name="inventory_goods_list" value='{:json_encode($inventory_info["goods_list"])}'>
{/notempty}
<div class="form-row">
<button class="layui-btn" lay-submit lay-filter="save"><span class="layui-icon"></span>提交</button>
<button class="layui-btn layui-btn-primary" onclick="backStockAction()">返回</button>
</div>
</div>
</div>
<script type="text/html" id="stock_goods_info">
<tr class="stock-tr" data-key='{{ d.index }}'>
<td>
{{d.sku_name}}
</td>
<!-- 库存 -->
<td>{{ d.real_stock || 0 }}</td>
<td>{{ d.stock || 0 }}</td>
<!-- 单位 -->
<td>{{ d.unit || '件' }}</td>
<!-- 数量 -->
<td>
<input type="number" class="layui-input stock-num" name="goods_num" value="{{ d.goods_num || '' }}" placeholder="0" onchange="dataChange(this)"/>
</td>
<!-- 成本总价 -->
<td>
<span class="compare-num">0</span>
</td>
<td>
<a class="text-color action-btn" onclick="delTr(this)">删除</a>
</td>
</tr>
</script>
<script>
var stockDataObj = JSON.parse($("input[name='inventory_goods_list']").val() || '{}');// 库存数据
var stockData = Object.values(stockDataObj)
var defaultStoreId = {$default_store_id ?? 0};
var stockConfig = {:json_encode($stock_config)};
var stockAction = {
id:'inventory_id',
listRoute: 'check', // 库存操作标识storage入库wastage出库
saveRoute: 'editcheck', // 保存地址
params:{
'inventory_no':$('input[name="inventory_no"]'),
'time':$('input[name="date_time"]'),
'remark':$('textarea[name="remark"]')
}
};
</script>
<script src="ADDON_STOCK_JS/stock_action.js?time=20250111"></script>

View File

@@ -0,0 +1,201 @@
<style>
.layui-card-header{background-color:#f8f8f8}
.apply-time{
float:left;
}
.export-select{float:left;}
.download-button{
float:right;
}
.export-list-view{
font-size:12px;
}
.export-foot-operation{overflow:hidden;margin-top:15px;}
.export-page{
float:right;
}
.export-content-bar{
float:left;
padding-top: 6px;
margin-left: 15px;
}
.export-foot-operation .layui-btn {
padding: 0px 5px;
font-size: 12px;
line-height: 2 !important;
height: auto;
display: inline-block;
}
.layui-unselect.layui-form-checkbox{
margin-top:-5px;
}
</style>
<div class="layui-layout layui-layout-admin">
<div class="body-content">
<div id="export_list"></div>
<div class="export-foot-operation">
<div class="export-content-bar layui-form bg-color-light-gray">
<input type="checkbox" name="export_select" lay-filter="allChoose" lay-skin="primary" title="全选">
</div>
<button class="layui-btn layui-btn-primary" onclick="deleteExport()">批量删除</button>
<div class='export-page' id="export_page"></div>
</div>
</div>
</div>
<script type="text/html" id="exportHtml">
{{# layui.each(d.data.list, function(index, item){ }}
<div class="layui-card export-list-view">
<div class="layui-card-header">
<div class="layui-form export-select">
<input type="checkbox" name="check[]" value="{{item.export_id}}" lay-skin="primary" title="">
</div>
<div class="apply-time">序号{{ item.export_id }}&nbsp;&nbsp;&nbsp;导出时间{{ ns.time_to_date(item.create_time) }}</div>
<div class="download-button">
{{# if(item.status == 0){ }}
<span>正在导出中请耐心等待</span>
{{# }else{ }}
{{# if(item.path != ''){ }}
<a class="text-color" href="{{ ns.img(item.path) }}" target="_blank">下载</a>
{{#}}}
{{#}}}
&nbsp;&nbsp;<a class="text-color" href="javascript:void(0)" data-export_id ="{{item.export_id}}" onclick="deleteExport(this)">删除</a>
</div>
</div>
<div class="layui-card-body">
<div class="layui-row layui-col-space10">
{{# layui.each(JSON.parse(item.condition), function(condition_index, condition_item){ }}
<div class="layui-col-md3">
{{condition_item.name}}{{condition_item.value || '-'}}
</div>
{{# }); }}
</div>
</div>
</div>
{{# }); }}
{{# if(d.data.list.length === 0){ }}
<div class="layui-card export-list-view">
<div class="layui-card-header">
<div class="apply-time">商品导出记录</div>
</div>
<div class="layui-card-body">
<div class="layui-row layui-col-space10">
<div class="layui-col-md3">暂无导出记录</div>
</div>
</div>
</div>
{{# } }}
</script>
<script>
var laypage,form;
layui.use(['form', 'laytpl', 'laypage'], function() {
form = layui.form;
laytpl = layui.laytpl;
form.render();
exportList(1,10);
laypage = layui.laypage;
/**
* 全选
*/
form.on("checkbox(allChoose)", function(data) {
$("input[name='check[]']").each(function() {
this.checked = data.elem.checked;
});
form.render('checkbox');
})
});
function exportList(page, limit){
$.ajax({
url: '{:addon_url("stock://shop/stock/export")}',
data: {
limit,
page
},
dataType: 'JSON',
type: 'POST',
success: function(res) {
var export_template = $("#exportHtml").html();
if(res.code >= 0){
laytpl(export_template).render(res, function (html) {
$("#export_list").html(html);
})
}
laypage.render({
elem: 'export_page',
count: res.data.count,
curr: page, //当前页
limit: limit,
jump: function(obj, first){
//obj包含了当前分页的所有参数比如
//首次不执行
if(!first){
exportList(obj.curr, obj.limit);
form.render();
}
}
});
form.render();
}
});
}
/**
* 删除导出记录
*/
var flag_delete = false;
function deleteExport(data) {
var export_ids = [];
if (!data) {
$("input[name='check[]']:checked").each(function (index, item) {
export_ids.push($(item).val());
});
} else {
export_ids.push($(data).attr("data-export_id"));
}
if (export_ids.length == 0) {
layer.msg('请选择要操作的数据');
return;
}
export_ids = export_ids.toString();
layer.confirm('确定要删除选择的商品导出记录吗?', {
btn: ['确定', '取消']
}, function (index) {
if (flag_delete) return;
flag_delete = true;
layer.close(index);
$.ajax({
type: "POST",
async: true,
url: ns.url("stock://shop/stock/deleteExport"),
data: {
export_ids: export_ids,
},
dataType: "JSON",
success: function (data) {
layer.msg(data.message);
if (data.code == 0) {
listenerHash(); // 刷新页面
} else {
flag_delete = false;
}
}
});
}, function () {
layer.close();
});
}
</script>

View File

@@ -0,0 +1,84 @@
<link rel="stylesheet" href="SHOP_CSS/goods_select.css">
<div class="select-goods">
<!-- 左侧固定展示商品分类 -->
<div class="select-goods-left">
<div class="select-goods-classification layui-collapse" lay-accordion lay-filter="oneCategory">
<div class="layui-colla-item">
<h2 class="layui-colla-title classification-item text-color" data-category_id="">全部分类</h2>
</div>
{foreach $category_list as $category_one_item}
<div class="layui-colla-item">
<h2 class="layui-colla-title classification-item {notempty name="$category_one_item.children"}arrow{/notempty}" data-category_id="{$category_one_item.category_id}">{$category_one_item.title}</h2>
{notempty name="category_one_item.children"}
{foreach $category_one_item.children as $category_two_item}
<div class="layui-colla-content">
<div class="select-goods-classification layui-collapse" lay-accordion lay-filter="twoCategory">
<div class="layui-colla-item">
<h2 class="layui-colla-title classification-item {notempty name="category_two_item.children"}arrow{/notempty}" data-category_id="{$category_two_item.category_id}">{$category_two_item.title}</h2>
{notempty name="category_two_item.children"}
{foreach $category_two_item.children as $category_three_item}
<div class="layui-colla-content classification-item" data-category_id="{$category_three_item.category_id}">{$category_three_item.title}</div>
{/foreach}
{/notempty}
</div>
</div>
</div>
{/foreach}
{/notempty}
</div>
{/foreach}
</div>
</div>
<!-- 右侧固定展示筛选和商品列表 -->
<div class="select-goods-right">
<!-- 筛选 -->
<div class="single-filter-box">
<div></div>
<div class="layui-form">
<div class="layui-input-inline">
<input type="text" value="{$search_text}" name="search_text" placeholder="请输入商品名称或编码" autocomplete="off" class="layui-input len-mid">
<button type="button" class="layui-btn layui-btn-primary" lay-filter="search" lay-submit>
<i class="layui-icon">&#xe615;</i>
</button>
</div>
<!-- 分类id -->
<input type="hidden" name="category_id" value=""/>
</div>
</div>
<!-- 列表 -->
<table id="goods_list" lay-filter="goods_list"></table>
</div>
<input type="hidden" name="maxNum" value="{$max_num}" title="最大商品数量" />
<input type="hidden" name="minNum" value="{$min_num}" title="最小商品数量" />
<input type="hidden" name="disabled" value="{$disabled}" title="不可选中" />
<input type="hidden" name="search_text" value="{$search_text}" title="请输入商品名称或编码" />
<input type="hidden" name="store_id" value="{$store_id}" title="store_id" />
<input type="hidden" name="goods_class" value="{$goods_class}" title="商品类型" />
</div>
<script type="text/html" id="checkbox">
<input type="checkbox" data-sku-id="{{d.sku_id}}" name="goods_checkbox" lay-skin="primary" lay-filter="goods_checkbox" {{goodsSelectObj.goodsIdArr.indexOf(d.sku_id.toString()) > -1 ? 'checked' : ''}}>
<input type="hidden" data-sku-id="{{d.sku_id}}" name="goods_json" value='{{ JSON.stringify(d) }}' />
</script>
<!-- 商品信息 -->
<script type="text/html" id="goods_info">
<div class="table-title">
<div class="title-pic" id="goods_img_{{d.goods_id}}">
<img layer-src src="{{ns.img(d.sku_image, 'small')}}"/>
</div>
<div class="title-content">
<a href="javascript:;" class="multi-line-hiding text-color" title="{{d.sku_name}}">{{d.sku_name}}</a>
</div>
</div>
</script>
<script src="ADDON_STOCK_JS/goods_select.js?time=2"></script>

View File

@@ -0,0 +1,153 @@
<style>
.layui-table .layui-btn{
justify-content: flex-end;
padding-right: 0px;
}
.name{
display: flex;
align-content: center;
}
.name img{
max-width: inherit;
width: 60px;
height: 60px;
margin-right: 10px;
}
</style>
<div class="layui-form" lay-filter="storeform">
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">基本信息</span>
</div>
<div class="layui-card-body">
<div class="layui-row">
<div class="layui-col-md3">
<div class="layui-form-item">
<label class="layui-form-label">制单人:</label>
<div class="layui-input-block">{$document_detail.operater_name}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">关联单据:</label>
<div class="layui-input-block">{$document_detail.type_name}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">制单时间:</label>
<div class="layui-input-block">{$document_detail.create_time}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">备注:</label>
<div class="layui-input-block">{$document_detail.remark}</div>
</div>
</div>
<div class="layui-col-md3">
<div class="layui-form-item">
<label class="layui-form-label">状态:</label>
<div class="layui-input-block">{$document_detail.status_data.name}</div>
</div>
{if !empty($document_detail.verifier_name) }
<div class="layui-form-item">
<label class="layui-form-label">审核人:</label>
<div class="layui-input-block">{$document_detail.verifier_name}</div>
</div>
{/if}
{if !empty($document_detail.audit_time) }
<div class="layui-form-item">
<label class="layui-form-label">审核时间:</label>
<div class="layui-input-block">{$document_detail.audit_time}</div>
</div>
{/if}
{if $document_detail.status == -1}
<div class="layui-form-item">
<label class="layui-form-label">拒绝理由:</label>
<div class="layui-input-block">{$document_detail.refuse_reason}</div>
</div>
{/if}
</div>
<div class="layui-col-md3">
<div class="layui-form-item">
<label class="layui-form-label">入库门店:</label>
<div class="layui-input-block">{$document_detail.store_name}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">入库单号:</label>
<div class="layui-input-block">{$document_detail.document_no}</div>
</div>
{if $document_detail.time > 0}
<div class="layui-form-item">
<label class="layui-form-label">入库时间:</label>
<div class="layui-input-block">{$document_detail.time}</div>
</div>
{/if}
</div>
</div>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">商品明细</span>
</div>
<div class="layui-card-body">
<table class="layui-table order_goods_list" lay-filter="order_goods" lay-skin="line">
<colgroup>
<col width="30%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
</colgroup>
<thead>
<tr>
<th>商品名称/条形码</th>
<th>规格</th>
<th>单位</th>
<th>数量</th>
<th>成本价(元)</th>
<th>金额(元)</th>
</tr>
</thead>
</table>
<table class="layui-table order_goods_list order_goods_list-bottom" lay-skin="line" lay-filter="order_goods_list">
<colgroup>
<col width="30%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
</colgroup>
<tbody>
{foreach $document_detail.goods_sku_list_array as $k => $v}
<tr class="table-tr">
<td class="name">
<img src="{:img($v.goods_sku_img,'small')}" alt="">
<span>{$v.goods_sku_name}</span>
</td>
{if $v.goods_sku_spec && $v.goods_sku_spec !=''}
<td>{$v.goods_sku_spec}</td>
{else/}
<td>-</td>
{/if}
{if $v.goods_unit && $v.goods_unit !=''}
<td>{$v.goods_unit}</td>
{else/}
<td></td>
{/if}
<td>{$v.goods_num}</td>
<td>{$v.goods_price}</td>
<td>{$v.goods_sum}</td>
</tr>
{/foreach}
</tbody>
</table>
<label style="display: flex;justify-content: flex-end;padding-right: 13px;">合计:共{$document_detail.goods_count}种商品{$document_detail.goods_price}件,合计金额:<span style="color: #ff0000;">{$document_detail.goods_total_price}</span></label>
</div>
</div>
</div>

View File

@@ -0,0 +1,190 @@
<style>
.name {
display: flex;
align-content: center;
}
.name img {
max-width: inherit;
width: 60px;
height: 60px;
margin-right: 10px;
}
</style>
<div class="layui-form" lay-filter="storeform">
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">基本信息</span>
</div>
<div class="layui-card-body">
<div class="layui-row">
<div class="layui-col-md6">
<div class="layui-form-item">
<label class="layui-form-label">制单人:</label>
<div class="layui-input-block">{$inventory_detail.operater_name}</div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-form-item">
<label class="layui-form-label">状态:</label>
<div class="layui-input-block">{$inventory_detail.status_name}</div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-form-item">
<label class="layui-form-label">盘点单号:</label>
<div class="layui-input-block">{$inventory_detail.inventory_no}</div>
</div>
</div>
{if $inventory_detail.verifier_name }
<div class="layui-col-md6">
<div class="layui-form-item">
<label class="layui-form-label">审核人:</label>
<div class="layui-input-block">{$inventory_detail.verifier_name}</div>
</div>
</div>
{/if}
<div class="layui-col-md6">
<div class="layui-form-item">
<label class="layui-form-label">制单时间:</label>
<div class="layui-input-block">{$inventory_detail.create_time}</div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-form-item">
<label class="layui-form-label">盘点时间:</label>
<div class="layui-input-block">{$inventory_detail.action_time}</div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-form-item">
<label class="layui-form-label">备注:</label>
<div class="layui-input-block">{$inventory_detail.remark}</div>
</div>
</div>
{if $inventory_detail.audit_time }
<div class="layui-col-md6">
<div class="layui-form-item">
<label class="layui-form-label">审核时间:</label>
<div class="layui-input-block">{$inventory_detail.audit_time}</div>
</div>
</div>
{/if}
{if $inventory_detail.status == -1 }
<div class="layui-col-md6">
<div class="layui-form-item">
<label class="layui-form-label">拒绝理由:</label>
<div class="layui-input-block">{$inventory_detail.refuse_reason}</div>
</div>
</div>
{/if}
</div>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">商品明细</span>
</div>
<div class="layui-card-body">
<table class="layui-table order_goods_list" lay-filter="order_goods" lay-skin="line" lay-filter="order_goods_list">
<div class="layui-tab-content layui-tab" lay-filter="list_tab">
<ul class="layui-tab-title tab-status">
<li id="all" data-type="state" class="layui-this">全部</li>
<li id="1" data-type="state">盘盈</li>
<li id="-1" data-type="state">盘亏</li>
<li id="0" data-type="state">持平</li>
</ul>
</div>
<colgroup>
<col width="20%"/>
<col width="8%"/>
<col width="8%"/>
<col width="8%"/>
<col width="8%"/>
<col width="8%"/>
<col width="10%"/>
<!--<col width="10%" />-->
</colgroup>
<thead>
<tr>
<th>商品名称/条形码</th>
<th style="text-align: right;">商品规格</th>
<th style="text-align: right;">单位</th>
<th style="text-align: right;">实物库存</th>
<th style="text-align: right;">实盘数量</th>
<th style="text-align: right;">盈亏数量</th>
<th style="text-align: right;">盈亏成本总额(元)</th>
<!--<th style="text-align: right;">盈亏销售总额(元)</th>-->
</tr>
</thead>
</table>
<table class="layui-table order_goods_list order_goods_list-bottom" lay-skin="line" lay-filter="order_goods_list">
<colgroup>
<col width="20%"/>
<col width="8%"/>
<col width="8%"/>
<col width="8%"/>
<col width="8%"/>
<col width="8%"/>
<col width="10%"/>
<!--<col width="10%" />-->
</colgroup>
<tbody>
{foreach $inventory_detail.goods_sku_list_array as $k => $v}
<tr class="table-tr" data-state="{if $v.profitloss_num == 0}0{/if}{if $v.profitloss_num > 0}1{/if}{if $v.profitloss_num < 0}-1{/if}">
<td class="name">
<img src="{:img($v.goods_img,'small')}" alt="">
<span>{$v.goods_sku_name}</span>
</td>
{if $v.goods_sku_spec && $v.goods_sku_spec !=''}
<td>{$v.goods_sku_spec}</td>
{else/}
<td>-</td>
{/if}
{if $v.goods_unit && $v.goods_unit !=''}
<td style="text-align: right;">{$v.goods_unit}</td>
{else/}
<td style="text-align: right;"></td>
{/if}
<td style="text-align: right;">{$v.stock}</td>
<td style="text-align: right;">{$v.inventory_num}</td>
<td style="text-align: right;" id="profitloss_num">{$v.profitloss_num}</td>
<td style="text-align: right;">{$v.inventory_cost_money}</td>
<!--<td style="text-align: right;">{$v.profitloss_sale_money}</td>-->
</tr>
{/foreach}
</tbody>
</table>
<label style="display: flex;justify-content: flex-end;padding-right: 13px;">合计:共{$inventory_detail.goods_count}种商品,实盘{$inventory_detail.kinds_num}种, 盘盈:<span style="color: #ff0000;">{$inventory_detail.kinds_profit_num}</span>, 盘亏:<span style="color: #15eb26;">{$inventory_detail.kinds_loss_num}</span>,持平:{$inventory_detail.kinds_even_num}种</label>
</div>
</div>
</div>
<script type="text/javascript">
layui.use(['form', 'laytpl', 'element'], function () {
var form = layui.form;
laytpl = layui.laytpl;
element = layui.element;
element.on('tab(list_tab)', function () {
var state = $(this).attr('id');
if (state == 'all') {
$(".table-tr").show();
} else {
$(".table-tr").hide();
$(".table-tr[data-state='" + state + "']").show();
}
});
});
</script>

View File

@@ -0,0 +1,286 @@
<link rel="stylesheet" type="text/css" href="STATIC_EXT/searchable_select/searchable_select.css" />
<link rel="stylesheet" type="text/css" href="__STATIC__/ext/layui/extend/cascader/cascader.css"/>
<link rel="stylesheet" href="__ADDON__/stock/site/css/goods_lists.css">
<div class="main-wrap">
<div class="content_full">
<div class="screen layui-collapse margin-bot" lay-filter="selection_panel">
<div class="layui-colla-item">
<div class="layui-colla-content layui-form layui-show" lay-filter="order_list">
<div class="layui-form-item">
<div class="classification">
<div class="layui-inline">
<label class="layui-form-label">商品名称/编码:</label>
<div class="layui-input-inline">
<input type="text" name="search_text" autocomplete="off" placeholder="请输入商品名称/编码" class="layui-input" />
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">商品分类</label>
<div class="layui-input-inline category-wrap">
<input type="text" autocomplete="off" show="false" class="layui-input select-category" placeholder="请选择" readonly="">
<input type="hidden" name="category_id">
</div>
</div>
</div>
<div class="classification">
<div class="layui-inline">
<label class="layui-form-label">库存:</label>
<div class="layui-input-inline">
<input type="number" name="min_stock" id="start_sale" lay-verify="int" min="0" placeholder="最低库存" class="layui-input" autocomplete="off">
</div>
<div class="layui-form-mid">-</div>
<div class="layui-input-inline">
<input type="number" name="max_stock" id="end_sale" lay-verify="int" min="0" placeholder="最高库存" class="layui-input" autocomplete="off">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">门店:</label>
<div class="layui-input-inline">
<select name="store_id" lay-filter="store_list" class="len-mid">
<option value="">全部</option>
{foreach $store_list as $store_k => $store_v}
<option value="{$store_v.store_id}">{$store_v.store_name}</option>
{/foreach}
</select>
<input type="hidden" name="store_name"/>
</div>
</div>
</div>
</div>
<input type="hidden" name="goods_state" value="{$goods_state}"/>
<div class="form-row">
<button class="layui-btn" lay-submit lay-filter="search">筛选</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
<button class="layui-btn layui-btn-primary" lay-submit lay-filter="batch_export_stock">导出商品</button>
<a class="layui-btn layui-btn-primary" href="{:href_url('stock://shop/stock/export')}" target="_blank">查看导出记录</a>
</div>
</div>
</div>
</div>
<!-- 批量操作时判断是否为当前选项,防止重复点击 -->
<input type="hidden" name="openSwitch" lay-type="grouping" value="">
</div>
<div class="layui-tab table-tab" lay-filter="goods_list_tab">
<ul class="layui-tab-title">
<li {if $goods_state=='' }class="layui-this" {/if} lay-id="">全部</li>
<li {if $goods_state=='1' }class="layui-this" {/if} lay-id="1">销售中</li>
<li {if $goods_state=='0' }class="layui-this" {/if} lay-id="0">仓库中</li>
</ul>
<div class="layui-tab-content" style="margin-top: 15px;">
<table id="goods_list" lay-filter="goods_list"></table>
</div>
</div>
</div>
<script type="text/html" id="goods_detail">
<div class='table-title'>
<div class='title-pic'>
<img layer-src src="{{ns.img(d.sku_image, 'small')}}">
</div>
<div class='title-content'>
<p class="layui-elip" style="color: #333;" title="{{d.goods_name}}">{{d.goods_name}}</p>
<p class="layui-elip">{{d.spec_name}}</p>
</div>
</div>
</script>
<script type="text/html" id="operation">
<div class="table-btn">
<a class="layui-btn" lay-event="records">查看记录</a>
</div>
</script>
<script src="STATIC_EXT/searchable_select/searchable_select.js"></script>
<script>
var table,form,layCascader;
layui.use(['form', 'element','layCascader'], function() {
form = layui.form;
layCascader = layui.layCascader;
element = layui.element;
form.render();
var store_name = $('select[name="store_id"] option:selected').text()
$('input[name="store_name"]').val(store_name);
table = new Table({
elem: '#goods_list',
url: ns.url("stock://shop/stock/manage"),
cols: [
[{
type: 'checkbox',
unresize: 'false',
width: '3%'
},{
field: 'sku_name',
title: '商品信息',
width: '30%',
templet: '#goods_detail'
}, {
field: 'sku_no',
title: '编码',
width: '10%',
}, {
field: 'stock',
title: '销售库存',
width: '9%',
templet: function (data){
if(!data.stock){
return 0;
}
return data.stock;
}
}, {
field: 'stock',
title: '实物库存',
width: '9%',
templet: function (data){
if(!data.real_stock){
return 0;
}
return data.real_stock;
}
}, {
field: 'cost_price',
title: '成本价',
width: '9%',
}, {
title: '状态',
unresize: 'false',
width: '8%',
templet: function (data) {
var str = '';
if (data.goods_state == 1) {
str = '销售中';
} else if (data.goods_state == 0) {
str = '仓库中';
}
return str;
}
}, {
field: 'create_time',
title: '添加时间',
width: '15%',
templet: function (data) {
return ns.time_to_date(data.create_time);
}
},
{
title: '操作',
width: '7%',
toolbar: '#operation',
align: 'right',
}
]
],
});
/**
* 监听工具栏操作
*/
table.tool(function (obj) {
var data = obj.data;
switch (obj.event) {
case 'records': //查看
window.open(ns.href("stock://shop/stock/records?sku_id=" + data.sku_id));
break;
}
});
element.on('tab(goods_list_tab)', function () {
var id = this.getAttribute('lay-id');
$('input[name="goods_state"]').val(id)
table.reload({
page: {
curr: 1
},
where: {
search_text: $('input[name="search_text"]').val(),
category_id: $('input[name="category_id"]').val(),
min_stock: $('input[name="min_stock"]').val(),
max_stock: $('input[name="max_stock"]').val(),
store_id: $('select[name="store_id"]').val(),
goods_state: $('input[name="goods_state"]').val()
}
});
});
form.on('select(store_list)', function (data) {
var store_name = $('select[name="store_id"] option:selected').text()
$('input[name="store_name"]').val(store_name);
})
//监听筛选事件
form.on('submit(search)', function (data) {
table.reload({
page: {
curr: 1
},
where: data.field
});
});
// 商品导出
form.on('submit(batch_export_stock)', function(data){
var id_array = [];
var checkedData = table.checkStatus('goods_list').data;
for (var i in checkedData) id_array.push(checkedData[i].goods_id);
data.field.goods_ids = id_array.toString(); // 选择要导出的商品
$.ajax({
type: 'post',
dataType: 'json',
url: ns.url("stock://shop/stock/exportGoods"),
data: data.field,
success: function (res) {
}
})
window.open(ns.href("stock://shop/stock/export",{}));
});
var goodsCategory = [];
fetchCategory('.select-category', function (value, node) {
$('[name="category_id"]').val(value)
});
/**
* 渲染分类选择
* @param elem
* @param callback
*/
function fetchCategory(elem, callback){
if (!goodsCategory.length) {
$.ajax({
url : ns.url("shop/goodscategory/lists"),
dataType: 'JSON',
type: 'POST',
async: false,
success: function(res) {
goodsCategory = res.data;
}
})
}
if($(elem).length) {
var _cascader = layCascader({
elem: elem,
options: goodsCategory,
props: {
value: 'category_id',
label: 'category_name',
children: 'child_list'
}
});
_cascader.changeEvent(function (value, node) {
typeof callback == 'function' && callback(value, node)
});
$("form").unbind().bind("reset", function (event) {
_cascader.clearCheckedNodes()
});
}
}
});
</script>

View File

@@ -0,0 +1,151 @@
<style>
.layui-table .layui-btn{
justify-content: flex-end;
padding-right: 0px;
text-align: right;
}
.name{
display: flex;
align-content: center;
}
.name img{
max-width: inherit;
width: 60px;
height: 60px;
margin-right: 10px;
}
</style>
<div class="layui-form" lay-filter="storeform">
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">基本信息</span>
</div>
<div class="layui-card-body">
<div class="layui-row">
<div class="layui-col-md3">
<div class="layui-form-item">
<label class="layui-form-label">制单人:</label>
<div class="layui-input-block">{$document_detail.operater_name}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">关联单据:</label>
<div class="layui-input-block">{$document_detail.type_name}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">制单时间:</label>
<div class="layui-input-block">{$document_detail.create_time}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">备注:</label>
<div class="layui-input-block">{$document_detail.remark}</div>
</div>
</div>
<div class="layui-col-md3">
<div class="layui-form-item">
<label class="layui-form-label">状态:</label>
<div class="layui-input-block">{$document_detail.status_data.name}</div>
</div>
{if !empty($document_detail.verifier_name) }
<div class="layui-form-item">
<label class="layui-form-label">审核人:</label>
<div class="layui-input-block">{$document_detail.verifier_name}</div>
</div>
{/if}
{if !empty($document_detail.audit_time) }
<div class="layui-form-item">
<label class="layui-form-label">审核时间:</label>
<div class="layui-input-block">{$document_detail.audit_time}</div>
</div>
{/if}
{if $document_detail.status == -1}
<div class="layui-form-item">
<label class="layui-form-label">拒绝理由:</label>
<div class="layui-input-block">{$document_detail.refuse_reason}</div>
</div>
{/if}
</div>
<div class="layui-col-md3">
<div class="layui-form-item">
<label class="layui-form-label">出库门店:</label>
<div class="layui-input-block">{$document_detail.store_name}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">出库单号:</label>
<div class="layui-input-block">{$document_detail.document_no}</div>
</div>
{if $document_detail.time > 0}
<div class="layui-form-item">
<label class="layui-form-label">出库时间:</label>
<div class="layui-input-block">{$document_detail.time}</div>
</div>
{/if}
</div>
</div>
</div>
</div>
<div class="layui-card card-common card-brief">
<div class="layui-card-header">
<span class="card-title">商品明细</span>
</div>
<div class="layui-card-body">
<table class="layui-table order_goods_list" lay-filter="order_goods" lay-skin="line">
<colgroup>
<col width="30%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
</colgroup>
<thead>
<tr>
<th>商品名称/条形码</th>
<th>规格</th>
<th>单位</th>
<th>数量</th>
<th>成本价(元)</th>
<th>金额(元)</th>
</tr>
</thead>
</table>
<table class="layui-table order_goods_list order_goods_list-bottom" lay-filter="order_goods_list" lay-skin="line">
<colgroup>
<col width="30%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
<col width="10%" />
</colgroup>
<tbody>
{foreach $document_detail.goods_sku_list_array as $k => $v}
<tr class="table-tr">
<td class="name">
<img src="{:img($v.goods_sku_img,'small')}" alt="">
<span>{$v.goods_sku_name}</span>
</td>
{if $v.goods_sku_spec && $v.goods_sku_spec !=''}
<td>{$v.goods_sku_spec}</td>
{else/}
<td>-</td>
{/if}
{if $v.goods_unit && $v.goods_unit !=''}
<td>{$v.goods_unit}</td>
{else/}
<td></td>
{/if}
<td>{$v.goods_num}</td>
<td>{$v.goods_price}</td>
<td>{$v.goods_sum}</td>
</tr>
{/foreach}
</tbody>
</table>
<label style="display: flex;justify-content: flex-end;padding-right: 13px;">合计:共{$document_detail.goods_count}种商品{$document_detail.goods_price}件,合计金额:
<span style="color: #ff0000;">{$document_detail.goods_total_price}</span></label>
</div>
</div>
</div>

View File

@@ -0,0 +1,198 @@
<style>
#records_list{
margin-top: 14px;
}
.layui-icon-next{
font-size:14px;
color: #999;
}
</style>
<div class="main-wrap">
<div class="screen layui-collapse margin-bot ">
<div class="layui-colla-item">
<form class="layui-colla-content layui-form layui-show" lay-filter="screen">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">业务类型:</label>
<div class="layui-input-inline">
<select name="type">
<option value="">全部</option>
{foreach $type_list as $k => $v}
<option value="{$v.key}">{$v.name}</option>
{/foreach}
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">门店:</label>
<div class="layui-input-inline">
<select name="store_id" class="len-mid">
<option value="">全部</option>
{foreach $store_list as $store_k => $store_v}
<option value="{$store_v.store_id}">{$store_v.store_name}</option>
{/foreach}
</select>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">时间:</label>
<div class="layui-inline layui-inline-margin" id="time_fission">
<div class="layui-input-inline">
<input type="text" id="start_time" name="start_time" class="layui-input" placeholder="请输入开始时间" autocomplete="off">
<i class="iconfont iconriqi"></i>
</div>
<div class="layui-form-mid">-</div>
<div class="layui-input-inline">
<input type="text" id="end_time" name="end_time" class="layui-input" placeholder="请输入结束时间" autocomplete="off">
<i class="iconfont iconriqi"></i>
</div>
</div>
</div>
<input type="hidden" name="state" value="all">
</div>
<div class="form-row">
<button class="layui-btn bg-color" lay-submit lay-filter="search">筛选</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</form>
</div>
<table id="records_list" lay-filter="records_list"></table>
</div>
</div>
<!-- 操作 -->
<script type="text/html" id="operation">
<div class="table-btn">
<a class="layui-btn" lay-event="detail">查看</a>
</div>
</script>
<script>
var laytpl,table,form,element, laydate;
layui.use(['form','element','laytpl', 'laydate'], function() {
form = layui.form;
laydate = layui.laydate;
element = layui.element;
laytpl = layui.laytpl;
form.render();
//日期时间选择器
laydate.render({
elem: '#start_time'
,type: 'datetime'
});
//日期时间选择器
laydate.render({
elem: '#end_time'
,type: 'datetime'
});
table = new Table({
elem: '#records_list',
url: ns.url("stock://shop/stock/records"),
where:{sku_id:'{$sku_id}'},
cols: [
[{
title: '时间',
width: '12%',
templet: function(data) {
return '<div class="text">'+ns.time_to_date(data.create_time)+'</div>'; //创建时间转换方法
}
}, {
field: 'operater_name',
title: '操作人',
width: '6%',
templet: function(data) {
return '<div class="text">'+data.operater_name+'</div>';
}
}, {
field: 'store_name',
title: '门店',
width: '10%',
templet: function(data) {
return '<div class="text">'+data.store_name+'</div>';
}
},{
title: '业务类型',
field: 'name',
width: '8%',
templet: function(data) {
return '<div class="text">'+data.name+'</div>';
}
},{
title: '原库存',
field: 'before_store_stock',
},{
title: '库存变化',
templet: function(data) {
var change = data.type == 'input' ? '+' : '-';
return change + data.goods_num; //创建时间转换方法
}
},{
title: '现库存',
field: 'after_store_stock',
},{
title: '成本价',
templet: function(data) {
return data.goods_price; //创建时间转换方法
}
},{
title: '成本价变化',
width: '12%',
templet: function(data) {
return '<div class="text">'+data.before_store_goods_price + ' <i class="layui-icon layui-icon-next"></i> ' + data.after_store_goods_price+'</div>';
}
},{
title: '备注',
field: 'remark',
width:'10%',
templet: function(data) {
return '<div class="text">'+data.remark+'</div>';
}
},{
title: '操作',
toolbar: '#operation',
align:'right'
}]
]
});
/**
* 监听工具栏操作
*/
table.tool(function(obj) {
var data = obj.data;
switch (obj.event) {
case 'detail': //查看详情
if(data.type == "input"){
location.hash = ns.hash("stock://shop/stock/inputdetail?document_id="+ data.document_id);
}else{
location.hash = ns.hash("stock://shop/stock/outputdetail?document_id="+ data.document_id);
}
break;
}
});
/**
* 搜索功能
*/
form.on('submit(search)', function(data) {
table.reload({
page: {
curr: 1
},
where: data.field
});
return false;
});
});
</script>

View File

@@ -0,0 +1,213 @@
<link rel="stylesheet" type="text/css" href="ADDON_STOCK_CSS/stock.css" />
<style>
.stock-title-body {
position: relative;
}
.stock-title-body span {
position: absolute;
top: 5px;
right: 5px;
background-color: #fff;
z-index: 10;
cursor: pointer;
}
.stock-title-body input {
padding-right: 25px;
}
input.stock-search {
border-width: 0;
}
input.stock-search:focus {
border-width: 1px;
}
.layui-table th,
.layui-table td {
padding: 7px 30px !important;
}
.layui-table .layui-input {
height: 28px !important;
}
.remark{
width: 611px;
}
button[lay-filter='save'] .layui-icon-loading {
animation: loding-rotate 1s linear infinite;
/* 设置动画效果 */
transform-origin: center;
display: inline-block;
}
@keyframes loding-rotate {
0% {
transform: rotate(0);
}
/* 起始位置 */
100% {
transform: rotate(360deg);
}
/* 结束位置,旋转一周 */
}
</style>
<div class="layui-form form" lay-filter="formTest">
<div class="stock-view">
{if $stock_config.is_audit == 1}
<div class="tips text-color">说明:待审核状态下只有经办人允许修改,只有变为已审核状态后才会使库存发生变化,已审核状态的单据不允许再修改。</div>
{/if}
<div class="store-view">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">入库单号:</label>
<div class="layui-input-block len-mid">
{if isset($document_info)}
<input type="text" value="{$document_info['document_no']}" name="document_no" class="layui-input len-mid">
{else /}
<input type="text" value="{$document_no}" name="document_no" class="layui-input len-mid">
{/if}
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label"><span class="required">*</span>入库门店:</label>
<div class="layui-input-block len-mid">
<select name="store_id" lay-verify="required" lay-filter="store_list" class="len-mid">
{foreach $store_list as $store_k => $store_v}
{if isset($document_info)}
<option value="{$store_v.store_id}" {if $document_info['store_id']==$store_v['store_id']}selected {php} $default_store_id=$store_v['store_id']; {/php}{/if}>{$store_v.store_name}</option>
{else /}
<option value="{$store_v.store_id}" {if $store_k==0}selected {php} $default_store_id=$store_v['store_id']; {/php}{/if}>{$store_v.store_name}</option>
{/if}
{/foreach}
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">入库时间:</label>
<div class="layui-input-block len-mid">
<input type="text" class="layui-input" name="date_time" value="{$document_info ? time_to_date($document_info['time']) : date('Y-m-d H:i:s')}" placeholder="入库时间" id="date_time" readonly>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">当前操作人:</label>
<div class="layui-input-block len-mid">
<span>{$user_info['username']}</span>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label"><span class="required"></span>备注:</label>
<div class="layui-input-block remark">
<textarea class="layui-textarea" maxlength="100" name="remark" placeholder="请输入备注">{$document_info['remark'] ?? ''}</textarea>
</div>
</div>
</div>
</div>
<table class="layui-table" lay-size="lg">
<colgroup>
<col width="350">
<col width="120">
<col width="90">
<col>
<col>
<col width="120">
<col width="90">
</colgroup>
<thead>
<tr>
<th>产品名称</th>
<th>当前库存</th>
<th>单位</th>
<th>数量</th>
<th>成本价</th>
<th>总金额</th>
<th>操作</th>
</tr>
</thead>
<tbody class="stock-body">
<tr class="stock-search-line">
<td class="stock-search-block">
<div class="stock-title-body">
<input type="text" class="layui-input stock-search" placeholder="请输入产品名称/规格/编码" />
<span class="iconfont icontuodong" onclick="editBtn('btn')"></span>
</div>
</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="7" class="total-data">合计: 共<span class="kinds-num">0</span>种,<span class="count-num">0</span>件产品,合计金额:<span class="goods-money">0</span></td>
</tr>
</tfoot>
</table>
{notempty name="$document_info"}
<input type="hidden" name="document_id" value="{$document_info['document_id']}">
<input type="hidden" name="document_goods_list" value='{:json_encode($document_info["goods_list"])}'>
{/notempty}
<div class="form-row">
<button class="layui-btn" lay-submit lay-filter="save"><span class="layui-icon"></span>入库</button>
<button class="layui-btn layui-btn-primary" onclick="backStockAction()">返回</button>
</div>
</div>
</div>
<script type="text/html" id="stock_goods_info">
<tr class="stock-tr" data-key='{{ d.index }}'>
<td>
{{d.sku_name}}
</td>
<!-- 库存 -->
<td>{{ d.real_stock || 0 }}</td>
<!-- 单位 -->
<td>{{ d.unit || '件' }}</td>
<!-- 数量 -->
<td>
<input type="number" class="layui-input stock-num" name="goods_num" value="{{ d.goods_num || 0 }}" placeholder="0" onchange="dataChange(this)"/>
</td>
<!-- 成本价 -->
<td>
<input type="number" class="layui-input stock-cost-price" name="goods_price" value="{{ d.goods_price || 0 }}" onchange="dataChange(this)"/>
</td>
<!-- 成本总价 -->
<td>
<span class="total-cost-money">{{ d.goods_money || 0 }}</span>
</td>
<td>
<a class="text-color action-btn" onclick="delTr(this)">删除</a>
</td>
</tr>
</script>
<script>
var stockDataObj = JSON.parse($("input[name='document_goods_list']").val() || '{}');// 库存数据
var stockData = Object.values(stockDataObj)
var defaultStoreId = {$default_store_id ?? 0};
var stockConfig = {:json_encode($stock_config) };
var stockAction = {
id: 'document_id',
listRoute: 'storage', // 库存操作标识storage入库wastage出库
saveRoute: 'stockin', // 保存地址
params:{
'document_no':$('input[name="document_no"]'),
'time':$('input[name="date_time"]'),
'remark':$('textarea[name="remark"]')
}
};
</script>
<script src="ADDON_STOCK_JS/stock_action.js?time=20250113"></script>

View File

@@ -0,0 +1,191 @@
<link rel="stylesheet" type="text/css" href="ADDON_STOCK_CSS/stock.css" />
<style>
.stock-title-body{
position: relative;
}
.stock-title-body span{
position: absolute;
top:5px;
right:5px;
background-color: #fff;
z-index: 10;
cursor: pointer;
}
.stock-title-body input{
padding-right: 25px;
}
input.stock-search{
border-width: 0;
}
input.stock-search:focus{
border-width: 1px;
}
.layui-table th,.layui-table td{
padding: 7px 30px !important;
}
.layui-table .layui-input{
height: 28px !important;
}
.remark{
width: 611px;
}
button[lay-filter='save'] .layui-icon-loading {
animation: loding-rotate 1s linear infinite; /* 设置动画效果 */
transform-origin: center;
display: inline-block;
}
@keyframes loding-rotate {
0% { transform: rotate(0); } /* 起始位置 */
100% { transform: rotate(360deg); } /* 结束位置,旋转一周 */
}
</style>
<div class="layui-form form" lay-filter="formTest">
<div class="stock-view">
{if $stock_config.is_audit == 1}
<div class="tips text-color">说明:待审核状态下只有经办人允许修改,只有变为已审核状态后才会使库存发生变化,已审核状态的单据不允许再修改。</div>
{/if}
<div class="store-view">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">出库单号:</label>
<div class="layui-input-block len-mid">
{if isset($document_info)}
<input type="text" value="{$document_info['document_no']}" name="document_no" class="layui-input len-mid">
{else /}
<input type="text" value="{$document_no}" name="document_no" class="layui-input len-mid">
{/if}
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label"><span class="required">*</span>门店:</label>
<div class="layui-input-block len-mid">
<select name="store_id" lay-verify="required" lay-filter="store_list" class="len-mid">
{foreach $store_list as $store_k => $store_v}
{if isset($document_info)}
<option value="{$store_v.store_id}" {if $document_info['store_id']==$store_v['store_id']}selected {php} $default_store_id=$store_v['store_id']; {/php}{/if}>{$store_v.store_name}</option>
{else /}
<option value="{$store_v.store_id}" {if $store_k==0}selected {php} $default_store_id=$store_v['store_id']; {/php}{/if}>{$store_v.store_name}</option>
{/if}
{/foreach}
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">出库时间:</label>
<div class="layui-input-block len-mid">
<input type="text" class="layui-input" name="date_time" value="{$document_info ? time_to_date($document_info['time']) : date('Y-m-d H:i:s')}" placeholder="出库时间" id="date_time" readonly>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">当前操作人:</label>
<div class="layui-input-block len-mid">
<span>{$user_info['username']}</span>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label"><span class="required"></span>备注:</label>
<div class="layui-input-block remark">
<textarea class="layui-textarea" maxlength="100" name="remark" placeholder="请输入备注">{$document_info['remark'] ?? ''}</textarea>
</div>
</div>
</div>
</div>
<table class="layui-table" lay-size="lg">
<colgroup>
<col width="25%">
<col width="10%">
<col width="10%">
<col width="25%">
<col width="20%">
<col width="10%">
</colgroup>
<thead>
<tr>
<th>产品名称/规格/编码</th>
<th>当前库存</th>
<th>单位</th>
<th>成本价</th>
<th>数量</th>
<th>操作</th>
</tr>
</thead>
<tbody class="stock-body">
<tr class="stock-search-line">
<td class="stock-search-block">
<div class="stock-title-body">
<input type="text" class="layui-input stock-search" placeholder="请输入产品名称/规格/编码" />
<span class="iconfont icontuodong" onclick="editBtn('btn')"></span>
</div>
</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="7" class="total-data">合计: 共<span class="kinds-num">0</span>种,<span class="count-num">0</span>件产品,合计金额:<span class="goods-money">0</span></td>
</tr>
</tfoot>
</table>
{notempty name="$document_info"}
<input type="hidden" name="document_id" value="{$document_info['document_id']}">
<input type="hidden" name="document_goods_list" value='{:json_encode($document_info["goods_list"])}'>
{/notempty}
<div class="form-row">
<button class="layui-btn" lay-submit lay-filter="save"><span class="layui-icon"></span>出库</button>
<button class="layui-btn layui-btn-primary" onclick="backStockAction()">返回</button>
</div>
</div>
</div>
<script type="text/html" id="stock_goods_info">
<tr class="stock-tr" data-key='{{ d.index }}'>
<td>
{{d.sku_name}}
</td>
<!-- 库存 -->
<td>{{ d.real_stock || 0 }}</td>
<!-- 单位 -->
<td>{{ d.unit || '件' }}</td>
<td>
{{ d.cost_price || 0.00 }}
<input type="hidden" name="goods_price" value="{{ d.cost_price || 0 }}" />
</td>
<!-- 数量 -->
<td>
<input type="number" class="layui-input stock-num" name="goods_num" value="{{ d.goods_num || 0 }}" placeholder="0" onchange="dataChange(this)"/>
</td>
<td>
<a class="text-color action-btn" onclick="delTr(this)">删除</a>
</td>
</tr>
</script>
<script>
var stockDataObj = JSON.parse($("input[name='document_goods_list']").val() || '{}');// 库存数据
var stockData = Object.values(stockDataObj)
var defaultStoreId = {$default_store_id ?? 0};
var stockConfig = {:json_encode($stock_config)};
var stockAction = {
id: 'document_id',
listRoute: 'wastage', // 库存操作标识storage入库wastage出库
saveRoute: 'stockout', // 保存地址
params:{
'document_no':$('input[name="document_no"]'),
'time':$('input[name="date_time"]'),
'remark':$('textarea[name="remark"]')
}
};
</script>
<script src="ADDON_STOCK_JS/stock_action.js?time=20250111"></script>

View File

@@ -0,0 +1,373 @@
<style>
.single-filter-box {justify-content: left;line-height: 34px}
.single-filter-box a{cursor:pointer;margin-left: 10px}
</style>
<div class="main-wrap">
<div class="single-filter-box">
<button type="button" class="layui-btn bg-color" onclick="add()">添加入库单</button>
</div>
<!-- 搜索框 -->
<div class="screen layui-collapse search-nav" lay-filter="selection_panel">
<div class="layui-colla-item">
<form class="layui-colla-content layui-form layui-show">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">入库单号:</label>
<div class="layui-input-inline">
<input type="text" name="search_text" placeholder="请输入入库单号" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">门店:</label>
<div class="layui-input-inline">
<select name="store_id" class="len-mid">
<option value="">全部</option>
{foreach $store_list as $store_k => $store_v}
<option value="{$store_v.store_id}">{$store_v.store_name}</option>
{/foreach}
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">审核状态:</label>
<div class="layui-input-inline">
<select name="status" lay-filter="status" class="len-mid">
<option value="">全部</option>
{foreach name="$status_list" item="vo"}
<option value="{$vo.status}">{$vo.name}</option>
{/foreach}
</select>
</div>
</div>
</div>
<div class="form-row">
<button class="layui-btn bg-color" lay-submit lay-filter="search">筛选</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</form>
</div>
</div>
<div class="layui-tab table-tab">
<div class="layui-tab-content">
<table id="doc_list" lay-filter="doc_list"></table>
</div>
</div>
</div>
<script type='text/html' id="import_document">
<div class="layui-form import-document">
<div class="layui-form-item">
<label class="layui-form-label ">文件上传</label>
<div class="layui-input-block ">
<div class="upload-file sub-text disabled-click">
<div class="upload-img-block" id="addFile">
<div class="upload-img-box">
<div class="upload-default">
<div class="upload">
<i class="iconfont iconshangchuan"></i>
<p>导入模版</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="word-aux">需按照指定模板导入支持格式xlsxlsx下载<a href="ADDON_STOCK_FILE/stockin_template.xlsx" class="text-color"> 导入模板</a></div>
</div>
<div class="form-row">
<button class="layui-btn confirm-auto">确定</button>
<button class="layui-btn layui-btn-primary cancel">取消</button>
</div>
</div>
</script>
<!-- 操作 -->
<script type="text/html" id="operation">
<div class="table-btn">
<a class="layui-btn" lay-event="detail">查看</a>
<!-- 待审核状态下进行审核操作 -->
{{# if(d.status == 1 && {$is_audit} == 0){ }}
<!-- 只有管理员和拥有单据审核权限的才能审核 -->
<a class="layui-btn" lay-event="audit_agree">审核通过</a>
<a class="layui-btn" lay-event="audit_refuse">审核拒绝</a>
{{# } }}
{{# if(d.status == -1){ }}
<a class="layui-btn" lay-event="detail_refuse">拒绝理由</a>
{{# } }}
<!-- 只有经办人才能操作入库单 -->
{{# if((d.status == 1 || d.status == -1) && d.operater == {$user_info['uid']} ){ }}
<a class="layui-btn" lay-event="edit">编辑</a>
<a class="layui-btn" lay-event="delete">删除</a>
{{# } }}
</div>
</script>
<script>
var table, form, laytpl, element, layer_pass, repeat_flag = false, upload; //防重复标识
layui.use(['form', 'laytpl', 'element', 'upload'], function() {
form = layui.form;
laytpl = layui.laytpl;
element = layui.element;
upload = layui.upload;
form.render();
table = new Table({
elem: '#doc_list',
url: ns.url("stock://shop/stock/storage"),
cols: [
[{
field: 'document_no',
title: '入库单号',
width: '15%',
}, {
field: 'store_name',
title: '门店',
width: '15%',
}, {
field: 'type_name',
title: '单据类型',
width: '10%',
}, {
field: 'document_money',
title: '单据金额',
width: '10%',
}, {
field: 'status_name',
title: '审核状态',
width: '10%',
}, {
title: '操作人',
width: '15%',
templet: function(data) {
var html = '';
html += '经办人:' + data.operater_name + '<br/>';
if(data.verifier_name) html += '审核人:' + data.verifier_name;
return html;
}
}, {
title: '操作时间',
width: '15%',
templet: function(data) {
var html = '';
html += '制单时间:' + ns.time_to_date(data.create_time) + '<br/>';
if (data.time) html += '入库时间:' + ns.time_to_date(data.time) + '<br/>';
if (data.audit_time) html += '审核时间:' + ns.time_to_date(data.audit_time);
return html;
}
}, {
title: '操作',
width: '10%',
align: 'right',
toolbar: '#operation',
}]
]
});
// 监听工具栏操作
table.tool(function(obj) {
var data = obj.data;
switch (obj.event) {
case 'audit_agree':
// 审核通过
agree(data.document_id);
break;
case 'audit_refuse':
// 审核拒绝
refuse(data.document_id);
break;
case 'edit':
// 编辑
edit(data.document_id);
break;
case 'delete':
// 删除
deleteDocument(data.document_id);
break;
case 'detail':
// 查看
window.open(ns.href("stock://shop/stock/inputdetail?document_id=" + data.document_id));
break;
case 'detail_refuse':
layer.open({
title: '拒绝理由',
content: data.refuse_reason,
})
break;
}
});
// 搜索功能
form.on('submit(search)', function(data){
table.reload({
page: {
curr: 1
},
where: data.field
});
return false;
});
});
function importExcel() {
laytpl($("#import_document").html()).render({}, function (html) {
cardPup = layer.open({
type: 1,
title:"导入入库单",
area:['700px','350px'],
content: html,
success: function(layero, index){
form.render();
// 上传文件
var uploadInst = upload.render({
elem: '#addFile' //绑定元素
,url: ns.url("stock://shop/stock/file") //上传接口
,accept:'file'
,acceptMime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
,acceptMime: 'xlsx'
,exts: 'xlsx'
,data:{
type: 'import',
},
done: function(res){
if (res.code >= 0) {
importing(res.data.path);
} else {
layer.msg(res.message);
}
}
});
$(".import-document .form-row .cancel,.import-document .form-row .confirm-auto").click(function(){
layer.closeAll();
});
function importing(path){
$.ajax({
url: ns.url("stock://shop/stock/import"),
data: {
path: path,
type : 'PURCHASE'
},
dataType: 'JSON',
type: 'POST',
success: function (res) {
if(res.code == 0){
// table.reload();
}else{
layer.msg(res.message)
}
}
});
}
}
});
});
}
function add() {
location.hash = ns.hash("stock://shop/stock/stockin");
}
function edit(document_id) {
location.hash = ns.hash("stock://shop/stock/stockin",{document_id});
}
// 同意
var agree_repeat_flag = false;
function agree(document_id) {
layer.confirm('确定要通过该单据吗?', function(index) {
if(agree_repeat_flag) return;
agree_repeat_flag = true;
layer.close(index);
$.ajax({
url: ns.url("stock://shop/stock/agree"),
data: {document_id},
dataType: 'JSON',
type: 'POST',
success: function(res) {
agree_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
} else {
layer.msg(res.message);
}
layer.closeAll();
}
});
});
}
// 拒绝
var refuse_repeat_flag = false;
function refuse(document_id) {
layer.prompt({
title: '拒绝理由',
formType: 2,
yes: function (index, layero) {
var refuse_reason = layero.find(".layui-layer-input").val();
if (!refuse_reason) {
layer.msg('请输入拒绝理由!', {icon: 5, anim: 6});
return;
}
if (refuse_repeat_flag) return;
refuse_repeat_flag = true;
$.ajax({
url: ns.url("stock://shop/stock/refuse"),
data: {document_id, refuse_reason},
dataType: 'JSON',
type: 'POST',
success: function (res) {
layer.msg(res.message);
refuse_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
}
}
});
layer.close(index);
}
});
}
// 删除单据
var delete_repeat_flag = false;
function deleteDocument(document_id) {
layer.confirm('确定要删除该单据吗?', function(index) {
if(delete_repeat_flag) return;
delete_repeat_flag = true;
layer.close(index);
$.ajax({
url: ns.url("stock://shop/stock/delete"),
data: {document_id},
dataType: 'JSON',
type: 'POST',
success: function(res) {
delete_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
} else {
layer.msg(res.message);
}
layer.closeAll();
}
});
});
}
</script>

View File

@@ -0,0 +1,279 @@
<div class="main-wrap">
<div class="single-filter-box">
<button type="button" class="layui-btn bg-color" onclick="add()">添加出库单</button>
</div>
<!-- 搜索框 -->
<div class="screen layui-collapse search-nav" lay-filter="selection_panel">
<div class="layui-colla-item">
<form class="layui-colla-content layui-form layui-show">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">出库单号:</label>
<div class="layui-input-inline">
<input type="text" name="search_text" placeholder="请输入出库单号" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">门店:</label>
<div class="layui-input-inline">
<select name="store_id" class="len-mid">
<option value="">全部</option>
{foreach $store_list as $store_k => $store_v}
<option value="{$store_v.store_id}">{$store_v.store_name}</option>
{/foreach}
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">审核状态:</label>
<div class="layui-input-inline">
<select name="status" lay-filter="status" class="len-mid">
<option value="">全部</option>
{foreach name="$status_list" item="vo"}
<option value="{$vo.status}">{$vo.name}</option>
{/foreach}
</select>
</div>
</div>
</div>
<div class="form-row">
<button class="layui-btn bg-color" lay-submit lay-filter="search">筛选</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</form>
</div>
</div>
<div class="layui-tab table-tab">
<div class="layui-tab-content">
<table id="wastage_list" lay-filter="wastage_list"></table>
</div>
</div>
</div>
<!-- 操作 -->
<script type="text/html" id="operation">
<div class="table-btn">
<a class="layui-btn" lay-event="detail">查看</a>
<!-- 待审核状态下进行审核操作 -->
{{# if(d.status == 1 && {$is_audit} == 0){ }}
<!-- 只有管理员和拥有单据审核权限的才能审核 -->
<a class="layui-btn" lay-event="audit_agree">审核通过</a>
<a class="layui-btn" lay-event="audit_refuse">审核拒绝</a>
{{# } }}
{{# if(d.status == -1){ }}
<a class="layui-btn" lay-event="detail_refuse">拒绝理由</a>
{{# } }}
<!-- 只有经办人才能操作入库单 -->
{{# if((d.status == 1 || d.status == -1) && d.operater == {$user_info['uid']} ){ }}
<a class="layui-btn" lay-event="edit">编辑</a>
<a class="layui-btn" lay-event="delete">删除</a>
{{# } }}
</div>
</script>
<script>
var table, form, laytpl, element, layer_pass;
layui.use(['form', 'laytpl', 'element'], function() {
form = layui.form;
laytpl = layui.laytpl;
element = layui.element;
form.render();
table = new Table({
elem: '#wastage_list',
url: ns.url("stock://shop/stock/wastage"),
cols: [
[{
field: 'document_no',
title: '出库单号',
width: '15%',
}, {
field: 'store_name',
title: '门店',
width: '15%',
}, {
field: 'type_name',
title: '单据类型',
width: '10%',
}, {
field: 'document_money',
title: '单据金额',
width: '10%',
}, {
field: 'status_name',
title: '审核状态',
width: '10%',
}, {
title: '操作人',
width: '15%',
templet: function(data) {
var html = '';
html += '经办人:' + data.operater_name + '<br/>';
if(data.verifier_name) html += '审核人:' + data.verifier_name;
return html;
}
}, {
title: '操作时间',
width: '15%',
templet: function(data) {
var html = '';
html += '制单时间:' + ns.time_to_date(data.create_time) + '<br/>';
if (data.time) html += '出库时间:' + ns.time_to_date(data.time) + '<br/>';
if (data.audit_time) html += '审核时间:' + ns.time_to_date(data.audit_time);
return html;
}
}, {
title: '操作',
width: '10%',
align: 'right',
toolbar: '#operation',
}]
]
});
// 监听工具栏操作
table.tool(function(obj) {
var data = obj.data;
switch (obj.event) {
case 'audit_agree':
// 审核通过
agree(data.document_id);
break;
case 'audit_refuse':
// 审核拒绝
refuse(data.document_id);
break;
case 'edit':
// 编辑
edit(data.document_id);
break;
case 'delete':
// 删除
deleteDocument(data.document_id);
break;
case 'detail': //查看
window.open(ns.href("stock://shop/stock/outputdetail?document_id="+ data.document_id));
break;
case 'detail_refuse':
layer.open({
title: '拒绝理由',
content: data.refuse_reason,
})
break;
}
});
// 搜索功能
form.on('submit(search)', function(data){
table.reload({
page: {
curr: 1
},
where: data.field
});
return false;
});
});
function add() {
location.hash = ns.hash("stock://shop/stock/stockout");
}
function edit(document_id) {
location.hash = ns.hash("stock://shop/stock/stockout",{document_id});
}
// 同意
var agree_repeat_flag = false;
function agree(document_id) {
layer.confirm('确定要通过该单据吗?', function(index) {
if(agree_repeat_flag) return;
agree_repeat_flag = true;
layer.close(index);
$.ajax({
url: ns.url("stock://shop/stock/agree"),
data: {document_id},
dataType: 'JSON',
type: 'POST',
success: function(res) {
agree_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
} else {
layer.msg(res.message);
}
layer.closeAll();
}
});
});
}
// 拒绝
var refuse_repeat_flag = false;
function refuse(document_id) {
layer.prompt({
title: '拒绝理由',
formType: 2,
yes: function (index, layero) {
var refuse_reason = layero.find(".layui-layer-input").val();
if (!refuse_reason) {
layer.msg('请输入拒绝理由!', {icon: 5, anim: 6});
return;
}
if (refuse_repeat_flag) return;
refuse_repeat_flag = true;
$.ajax({
url: ns.url("stock://shop/stock/refuse"),
data: {document_id, refuse_reason},
dataType: 'JSON',
type: 'POST',
success: function (res) {
layer.msg(res.message);
refuse_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
}
}
});
layer.close(index);
}
});
}
// 删除单据
var delete_repeat_flag = false;
function deleteDocument(document_id) {
layer.confirm('确定要删除该单据吗?', function(index) {
if(delete_repeat_flag) return;
delete_repeat_flag = true;
layer.close(index);
$.ajax({
url: ns.url("stock://shop/stock/delete"),
data: {document_id},
dataType: 'JSON',
type: 'POST',
success: function(res) {
delete_repeat_flag = false;
if (res.code >= 0) {
listenerHash(); // 刷新页面
} else {
layer.msg(res.message);
}
layer.closeAll();
}
});
});
}
</script>

View File

@@ -0,0 +1,233 @@
<style>
#goods thead th{ background-color: #f7f7f7;}
/* 优惠商品 */
.goods-title{display: flex;align-items: center;}
.goods-title .goods-img{display: flex;align-items: center;justify-content: center;width: 55px;height: 55px;margin-right: 5px;}
.goods-title .goods-img img{max-height: 100%;max-width: 100%;}
.goods-title .goods-name{flex: 1;line-height: 1.6;}
.goods_num {padding-left: 20px;}
</style>
<div class="layui-form form-wrap">
<div class="layui-form-item">
<label class="layui-form-label"><span class="required">*</span>转换名称:</label>
<div class="layui-input-block">
<input type="text" name="name" lay-verify="required" autocomplete="off" class="layui-input len-long" maxlength="255" value="{$transform_info.name ?? ''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><span class="required">*</span>转换商品:</label>
<div class="layui-input-block">
<table class="layui-table" id="goods" lay-skin="line" lay-size="lg">
<colgroup>
<col width="60%">
<col width="30%">
<col width="10%">
</colgroup>
<thead>
<tr>
<th>商品名称</th>
<th>基本单位数量</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody">
</tbody>
</table>
<script type="text/html" id="tbody_tpl" >
{{# d.forEach(function(item, index){ }}
<tr data-index="{{ index }}">
<td>
<div class="goods-title">
<div class="goods-img">
<img layer-src="{{ns.img(item.sku_image, 'big')}}" src="{{ns.img(item.sku_image, 'small')}}" alt="">
</div>
<p class="multi-line-hiding goods-name">{{item.sku_name}}</p>
</div>
</td>
<td>
<input name="num" type="number" lay-verify="num" placeholder="请输入基本单位数量" autocomplete="off" class="layui-input len-mid" value="{{item.num}}">
</td>
<td class='operation'>
<div class='table-btn'>
<a href='javascript:;' class='layui-btn' data-action="delete">删除</a>
</div>
</td>
</tr>
{{# }) }}
{{# if(d.length == 0){ }}
<tr class="goods-empty">
<td colspan="3">
<div>未选择商品</div>
</td>
</tr>
{{# } }}
</script>
<button class="layui-btn" id="select_goods">选择商品</button>
</div>
</div>
<div class="form-row">
<button class="layui-btn" lay-submit lay-filter="save">保存</button>
<button class="layui-btn layui-btn-primary" onclick="back()">返回</button>
</div>
<input type="hidden" name="transform_id" value="{$transform_info.transform_id ?? 0}">
</div>
<script>
var form, selectGoodsSkuId = [];
var data_table;
var transform_id = Number($("input[name='transform_id']").val());
var goods_list = [];
if(transform_id > 0){
goods_list = {:json_encode($transform_info.goods_list ?? [])};
}
layui.use("form", function() {
form = layui.form;
var repeat_flag = false; //防重复标识
/**
* 监听提交
*/
form.on('submit(save)', function(data) {
let goods_list = data_table.getData();
if(goods_list.length < 2){
layer.msg('请至少选择两种商品');
return;
}
data.field.goods_list = JSON.stringify(goods_list);
let action = 'add';
let action_name = '添加';
if(transform_id > 0){
action = 'edit';
action_name = '编辑';
}
if (repeat_flag) return;
repeat_flag = true;
$.ajax({
type: 'POST',
dataType: 'JSON',
url: ns.url("stock://shop/transform/"+action),
data: data.field,
async: false,
success: function(res) {
repeat_flag = false;
if (res.code == 0) {
layer.confirm(action_name+'成功', {
title: '操作提示',
btn: ['返回列表', '继续'+action_name],
closeBtn: 0,
yes: function(index, layero) {
location.hash = ns.hash("stock://shop/transform/lists");
layer.close(index);
},
btn2: function(index, layero) {
listenerHash(); // 刷新页面
layer.close(index);
}
});
} else {
layer.msg(res.message);
}
}
})
});
form.verify({
num: function(value) {
if(value === ''){
return '请输入基本单位数量';
}
if(!ns.getRegexp('>0num').test(value)){
return '基本单位数量必须为正整数';
}
}
});
})
function back() {
location.hash = ns.hash("stock://shop/transform/lists");
}
function DataTable(param){
param = param || {};
let that = this;
that.data = param.data || [];
that.layui = null;
that.init();
}
DataTable.prototype = {
select : function (){
let that = this;
let num_data = {};
that.data.forEach((item)=>{
num_data[item.sku_id] = item.num;
})
goodsSelect(function (data) {
that.data = [];
Object.values(data).forEach((goods_item)=>{
Object.values(goods_item.selected_sku_list).forEach((sku_item,index)=>{
sku_item.num = num_data[sku_item.sku_id] || 1;
that.data.push(sku_item);
})
})
that.render();
}, Object.keys(num_data).toString(), {mode: "sku",goods_class:'1,6'});
},
delete : function (index){
let that = this;
that.data.splice(index, 1);
that.render();
},
render : function (){
let that = this;
that.layui.laytpl($('#tbody_tpl').html()).render(that.data,function(html){
$('#tbody').html(html);
})
},
bindEvent : function (){
let that = this;
$('#tbody').on('click', 'a[data-action=delete]', function (){
let index = $(this).parents('tr').data('index');
that.delete(index);
})
$('#tbody').on('blur', 'input[type=text],input[type=number]', function (){
let index = $(this).parents('tr').data('index');
let field = $(this).attr('name');
let value = $(this).val();
that.data[index][field] = value;
})
$("#select_goods").click(function (){
that.select();
})
},
getData:function (){
let that = this;
let data = [];
that.data.forEach((item, index)=>{
data.push({
sku_id:item.sku_id,
num:item.num,
})
})
return data;
},
init: function (){
let that = this;
layui.use("laytpl", function() {
that.layui = layui;
that.bindEvent();
that.render();
})
},
}
data_table = new DataTable({
data:goods_list,
})
</script>

View File

@@ -0,0 +1,156 @@
<style>
.goods-title-box{display: flex;flex-wrap: wrap;}
.goods-title{display: flex;align-items: center;border: 1px solid #ccc;border-radius: 4px;margin: 4px;padding:4px 4px;}
.goods-title .goods-img{display: flex;align-items: center;justify-content: center;width: 55px;height: 55px;margin-right: 5px;}
.goods-title .goods-img img{max-height: 100%;max-width: 100%;}
.goods-title .goods-name{width: 150px;}
.goods-title .goods-name .name{line-height: 19px !important;}
.goods-title .goods-name .other{color:#999;}
</style>
<div class="layui-collapse tips-wrap" style="margin-bottom: 15px;">
<div class="layui-colla-item">
<h2 class="layui-colla-title">操作提示</h2>
<ul class="layui-colla-content layui-show">
<li>1、一个转换关系中可以添加多个商品规格可以是同一个商品的不同规格也可以是不同商品的规格</li>
<li>2、商品类型可以是实物商品和称重商品两种请根据商品的实际销售包装设置合适的基本单位数量</li>
<li>3、前台购买商品时可以下单的数量为转换后的库存</li>
</ul>
</div>
</div>
<!-- 搜索框 -->
<div class="single-filter-box">
<button class="layui-btn" onclick="add()">添加转换关系</button>
<div class="layui-form">
<div class="layui-input-inline">
<input type="text" name="search_text" placeholder="请输入关键词" autocomplete="off" class="layui-input">
<button type="button" class="layui-btn layui-btn-primary" lay-filter="search" lay-submit>
<i class="layui-icon">&#xe615;</i>
</button>
</div>
</div>
</div>
<table id="supplier_list" lay-filter="supplier_list"></table>
<script type="text/html" id="goods_list">
<div class="goods-title-box">
{{# d.goods_list.forEach((item)=>{ }}
<div class="goods-title">
<div class="goods-img">
<img layer-src="{{ns.img(item.sku_image, 'big')}}" src="{{ns.img(item.sku_image, 'small')}}" alt="">
</div>
<div class="goods-name">
<p class="multi-line-hiding name">{{item.sku_name}}</p>
<p class="multi-line-hiding other">基本单位{{item.num}}</p>
<p class="multi-line-hiding other">原始库存{{item.stock}}</p>
<p class="multi-line-hiding other">转换库存{{item.transform_stock}}</p>
</div>
</div>
{{# }) }}
</div>
</script>
<!-- 操作 -->
<script type="text/html" id="operation">
<div class="table-btn">
<a class="layui-btn" lay-event="edit">编辑</a>
<a class="layui-btn" lay-event="delete">删除</a>
</div>
</script>
<script>
var form, table;
layui.use(['table', 'form'], function() {
form = layui.form;
form.render();
table = new Table({
elem: '#supplier_list',
url: ns.url("stock://shop/transform/lists"),
cols: [
[{
title: '转换名称',
field: 'name',
width: '12%',
unresize: 'false',
templet: function (data){
return '<div class="text">'+ data.name +'</div>';
},
},{
title: '基本单位总数',
field: 'transform_stock',
width: '10%',
unresize: 'false',
templet: function (data){
return data.transform_stock;
},
},{
title: '转换商品',
field: 'goods_list',
width: '68%',
unresize: 'false',
templet: '#goods_list',
}, {
title: '操作',
width: '10%',
toolbar: '#operation',
unresize: 'false',
align : 'right'
}]
],
});
/**
* 监听工具栏操作
*/
table.tool(function(obj) {
var data = obj.data;
switch (obj.event) {
case 'edit':
location.hash = ns.hash("stock://shop/transform/edit", {transform_id: data.transform_id});
break;
case 'delete':
deleteTransform(data);
break;
}
});
/**
* 删除
*/
function deleteTransform(data) {
layer.confirm('确定要删除该库存转换吗?', function(index) {
layer.close(index);
$.ajax({
url: ns.url("stock://shop/transform/delete"),
data: {transform_ids: data.transform_id},
dataType: 'JSON',
type: 'POST',
success: function (res) {
layer.msg(res.message);
if (res.code == 0) {
table.reload();
}
}
});
});
}
/**
* 搜索功能
*/
form.on('submit(search)', function(data){
table.reload({
page: {
curr: 1
},
where: data.field
});
});
});
function add() {
location.hash = ns.hash("stock://shop/transform/add");
}
</script>