刚开始接触项目,上手有点慢,中间遇到好多自己不会的问题,解决后都记录下来,便于自己以后看看,也不知道怎么写,先慢慢积累吧!
价格促销价维护:
一、表、类搭建。
数据库分为两张表,主表sms_promotion_price 副表sms_promotion_price_detail
主表对应的字段:private String id;
private User createBy;
private Date createDate;
private User updateBy;
private Timestamp updateDate;
private String remarks;
private String delFlag;
private String salesOrganization //(sales_organization)
private String name //促销价名称
private String description //活动描述
private Date startTime; //活动开始时间
private Date endTime; //活动结束时间
private List<PromotionPriceDetail> promotionPriceList; //副表对应的list
private CommonsMultipartFile uploadFile; //导入的文件名
private Date beginStartTime; //按时间查询活动的开始时间
private Date endStartTime; //按时间查询活动的结束时间
副表对应字段: private String id;
private User createBy;
private Date createDate;
private User updateBy;
private Timestamp updateDate;
private String remarks;
private String delFlag;
private String promotion_id; //主表id
private String product_identifier; //商品条码
private Bigdecimal discountRate;
private Bigdecimal discountPrice;
private Bigdecimal productPrice;
// 商品条码
@ExcelField(title = "商品条码", type = 0, sort = 1)
private String productIdentifier;
// 产品名称
@ExcelField(title = "商品名称", type = 0, sort = 2)
private String productName;
// 产品货号
@ExcelField(title = "货号", type = 0, sort = 3)
private String productArticleNo;
// 款号
@ExcelField(title = "款号", type = 0, sort = 4)
private String productStyle;
// 产品颜色描述
@ExcelField(title = "颜色", type = 0, sort = 5)
private String productColordesc;
// 产品零售价格
@ExcelField(title = "零售价", type = 0, sort = 6)
private BigDecimal productPrice;
// 产品折扣率
@ExcelField(title = "折扣率", type = 0, sort = 7)
private BigDecimal discountRate; //促销活动折扣率
@ExcelField(title = "货号", type = 0, sort = 1)
下载模板字段: private String productArticleNo; //商品货号
@ExcelField(title = "折扣率", type = 0, sort = 2)
private Bigdecimal discountRate; //商品折扣率
备注:@ExcelField(title = "货号", type = 0, sort = 3)这种注解表示导入或导出的excel表里面必备的
字段,没有注解就没有这个字段,type表示导入或者导出,sort表示列的顺序。
二、功能流程及涉及技术
1、根据销售组织name、活动开始时间区间来查询促销活动信息
1)list页面功能,选择销售组织,获得name,将name通过form表单或是选择将时间条件传递到后台,也可以将两个条件
一起传递到后台查询。@RequestMapping(value = {"list", ""})
接受路径是action="${ctx}/sms/promotionprice/promotionPrice/"或是
action="${ctx}/sms/promotionprice/promotionPrice/list"的请求,
dao.xml文件查询语句
<sql id="promotionPriceDetailColumns">
a.id AS "id",
a.create_by AS "createBy.id",
a.create_date AS "createDate",
a.update_by AS "updateBy.id",
a.update_date AS "updateDate",
a.remarks AS "remarks",
a.del_flag AS "delFlag",
a.sales_organization AS "salesOrganization",
a.name AS "name",
a.description AS "description",
a.start_time AS "startTime",
a.end_time AS "endTime",
o.id AS "smsSalesOrganizationId",
o.name AS "smsSalesOrganizationName",
n.price AS "productPrice",
p.identifier AS "productIdentifier",
p.name AS "productName",
p.article_no AS "productArticleno",
p.style AS "productStyle",
p.color_desc AS "productColordesc"
</sql>
//前面的字段color_desc对应数据库字段,后面的字段productColordesc对应实体类字段,命名规则
_连接处用后一个单词的大写字母代替!
<sql id="promotionPriceJoins">
LEFT JOIN sms_sales_organization o ON o.id = a.sales_organization
</sql>
//以上两句都是被引用语句
<select id="findList" resultType="PromotionPrice"> //findList,dao里面的方法名字,PromotionPrice返回类型
SELECT
<include refid="promotionPriceListColumns"/> //引用需要查询的数据
FROM sms_promotion_price a
<include refid="promotionPriceJoins"/> //引用连接查询语句
<where>
1=1
<if test="beginStartTime != null and endStartTime != null and beginStartTime != '' and endStartTime != ''">
AND a.start_time BETWEEN #{beginStartTime} AND #{endStartTime}
</if>
<if test="product != null and product.articleno != null and product.articleno != ''">
AND d.article_no= #{product.articleno}
</if>
<if test="salesOrganization != null and salesOrganization != ''">
AND o.name = #{salesOrganization}
</if>
</where>
<choose>
<when test="page !=null and page.orderBy != null and page.orderBy != ''">
ORDER BY ${page.orderBy}
</when>
<otherwise>
ORDER BY a.update_date DESC
</otherwise>
</choose>
</select>
Page<PromotionPrice> page = promotionPriceService.findPage(new Page<PromotionPrice>(request, response), promotionPrice);
model.addAttribute("page", page);
return "modules/sms/promotionprice/promotionPriceList";
在页面上通过${page.list}将值用foreach循环出来。
2、form页面功能,通过form表单提交的方式将值绑定传到后台
<form:input path="name" id="promotionName" htmlEscape="false" maxlength="120" class="input-xlarge "/>
通过path属性来传值,这里path的name对应着实体类里面的属性,应与实体类属性名称一致
<input name="endTime" id="endTime" type="text" readonly="readonly" maxlength="20" class="input-medium Wdate "
value="<fmt:formatDate value="${promotionPrice.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/>"
οnclick="WdatePicker({dateFmt:'yyyy-MM-dd HH:mm:ss',isShowClear:false});"/>
input通过name属性来传值
<td style="width: 100px">
<input id="discountRate${status.index}" style="width: 50px"
name="promotionPriceList[${status.index}].discountRate" class="setNumber"
type="number" value="${promotionPrice.discountRate }" οninput="getTotal('${status.index }');"/>
</td>
这种是table里面的自动封装方式!
表单提交后值自动封装在对应的实体类中,由于导入框是一个独立的form表单,现在将了两个form表单并成一个form表单,
只留下保存的作为submit提交,其余的都将type改为button,然后再添加事件!
导入,根据货号查询商品,以及将相关属性显示在页面上等功能:
1)导入前台校验
$(document).ready(function() {
// 添加导入按钮事件
$("#btnImport").click(function(){
var salesOrganizationId = $("#smsSalesOrganizationId").val(); //前台才能看到这个是隐藏框的id
var promotionName = $("#promotionName").val();
var startTimeStr = $("#startTime").val();
var endTimeStr = $("#endTime").val();
var startDate = new Date(startTimeStr); // 将文本格式转为日期格式,方便比较大小!
var endDate = new Date(endTimeStr);
if (null == salesOrganizationId || "" == salesOrganizationId){
$.jBox.messager('请选择销售组织!',"提示", 5000, {icon: 'error'});
return false;
}
if (null == promotionName || "" == promotionName){
$.jBox.messager('请输入促销价名称!',"提示", 5000, {icon: 'error'});
return false;
}
if (null == startTimeStr || "" == startTimeStr){
$.jBox.messager('请输入活动开始时间!',"提示", 5000, {icon: 'error'});
return false;
}
if (null == endTimeStr || "" == endTimeStr){
$.jBox.messager('请输入活动结束时间!',"提示", 5000, {icon: 'error'});
return false;
}
if(startDate.getTime() >= endDate.getTime())
{
$.jBox.messager('结束时间不能大于开始时间!',"提示", 5000, {icon: 'error'});
return false;
}
var importAction = "${ctx}/sms/promotionprice/promotionPrice/import"; //将导入的动作赋给导入框,触发导入动作,跳出导入选择框!
$("#formAction").val(importAction);
通过import方法选择加载!
$.jBox($("#importBox").html(), {title:"导入数据", buttons:{"关闭":true},
bottomText:"导入文件不能超过5M,仅允许导入“xls”或“xlsx”格式文件!"}); //导入框底部提示信息!
});
//formAction是导入选择框的隐藏文本框的id
function selectFileClick(){
$("#uploadFile").click(); //选择文件
}
function importClick(){
$("#btnSubmitImport").click(); //导入
}
<!-- 导入的选择框 -->
<form:form id="inputForm" modelAttribute="promotionPrice" action="${ctx}/sms/promotionprice/promotionPrice/import" method="post" enctype="multipart/form-data" class="form-horizontal">
<input id="uploadFile" name="uploadFile" type="file" style="display: none"/>
<input id="formAction" name="formAction" type="hidden"/>
<input id="er" name="er" type="hidden" value="${promotionPrice.productName }"/>
<div id="importBox" class="hide">
<input id="uploadFileBtn" name="uploadFileBtn" type="button" οnclick="selectFileClick();" value="选择文件"/><br/><br/> 【并没有具体事件】
<input id="btnImportSubmit" class="btn btn-primary" type="button" οnclick="importClick();" value=" 导 入 "/>
<a href="${ctx}/sms/promotionprice/promotionPrice/exportTemplate">下载模板</a>
</div>
选择文件
//创建Excel对象
ImportExcel ei = new ImportExcel(promotionPrice.getUploadFile(), 1, 0);
//获取传入Excel文件的数据,根据传入参数类型,自动转换为对象
list = ei.getDataList(PromotionPriceImport.class);
//用foreach循环遍历数据,保存数据
for (PromotionPriceImport promotionPriceImport : list) {
try {
// 验证数据导入成功或者失败!
BeanValidators.validateWithException(validator, promotionPriceImport);
//根据货号来查询商品!
Product product = productService.getProductByArticleNo(promotionPriceImport.getProductArticleNo());
//初始化实体,然后将需要的商品的字段封装到类中
PromotionPrice sms = new PromotionPrice();
if(product !=null){
String identifier = promotionPrice.getProduct().getIdentifier();
String salesOrganization = promotionPrice.getSmsSalesOrganization().getName();
// 根据销售组织名称和商品条码来查询商品的零售价!
String productPrice = promotionPriceService.getProductPriceByValue(salesOrganization,identifier);
sms.setProductArticleNo(promotionPriceImport.getProductArticleNo());
sms.setSalesOrganization(promotionPrice.getSalesOrganization());
sms.setStartTime(promotionPrice.getStartTime());
sms.setEndTime(promotionPrice.getEndTime());
sms.setProductColordesc(promotionPrice.getProduct().getColorDesc());
sms.setProductIdentifier(promotionPrice.getProduct().getIdentifier());
sms.setProductName(promotionPrice.getProduct().getName());
sms.setProductStyle(promotionPrice.getProduct().getStyle());
sms.setProductPrice(new BigDecimal(productPrice));
从导入的文件获得discountRate的值!
sms.setDiscountRate(new BigDecimal(promotionPriceImport.getDiscountRate()));
关于Bigdecimal值的计算!
BigDecimal a = new BigDecimal(100); //
BigDecimal decimal = (new BigDecimal(productPrice)).multiply(a.divide((new BigDecimal(promotionPriceImport.getDiscountRate())),2,BigDecimal.ROUND_HALF_UP)); //
sms.setDiscountPrice(decimal); //
}
将多有的属性全部封装到副表priceList里面
priceList.add(sms);
if(!StringUtils.isNotEmpty(product.getArticleNo())){
throw new Exception("货号不存在:"+promotionPriceImport.getProductArticleNo());
}
successNum++;
} catch (ConstraintViolationException ex) {
errRowList.add(list.indexOf(promotionPriceImport)+1);
failureMsg.append("<br/>第"+(list.indexOf(promotionPriceImport)+1)+"行数据:");
failureMsg.append("导入失败:");
failureNum++;
List<String> messageList = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
for (String message : messageList) {
failureMsg.append(message + "; ");
}
} catch (Exception ex) {
errRowList.add(list.indexOf(promotionPriceImport)+1);
failureMsg.append("<br/>第"+(list.indexOf(promotionPriceImport)+1)+"行数据:");
failureMsg.append("导入失败:");
failureMsg.append(ex.getMessage());
failureNum++;
}
}
if (failureNum > 0) {
failureMsg.insert(0, ",失败 " + failureNum + " 条促销价格数据,导入信息如下:");
}
addMessage(redirectAttributes, "已成功导入 " + successNum + " 条促销价格数据" + failureMsg);
} catch (Exception e) {
addMessage(redirectAttributes, "导入促销价格数据失败!失败信息:" + e.getMessage());
}
然后再将list封装到主表实体类中,这时的实体类中应该有N个List<PromotionPriceDetail> promotionPriceList!
promotionPrice.setPromotionPriceList(priceList);
可以直接在页面上用${promotionPrice.promotionPriceList}
//model.addAttribute("priceList", priceList);
model.addAttribute("errRow",errRowList);
model.addAttribute("message", "可以成功导入 " + successNum + " 条促销价格数据" + failureMsg.toString());
return "modules/sms/promotionprice/promotionPriceForm";
}
2)模板下载功能
@RequiresPermissions("sms:promotionprice:promotionPrice:view")
@RequestMapping(value = "exportTemplate")
public void exportTemplate(HttpServletResponse response) throws Exception {
String fileName = "商品促销信息导入模版.xlsx";
//引入ExportExcel接口!
ExportExcel exportExcel = new ExportExcel("商品促销信息导入", PromotionPriceImport.class);
try {
exportExcel.write(response, fileName);
} catch (Exception e) {
throw new Exception("下载模版失败!失败信息:" + e.getMessage());
}
}
3)统一折扣设置
<div class="controls">
<input id="he" style="width: 173px" οninput="setRate('${status.index }');"/>
<input id="btnSet" class="btn btn-primary" type="button" οnclick="setValue()" value="设置"/>
function setValue(){
var t =$('.setNumber').length; //类选择器获取所有元素(获得同列的所有重复元素,多个list)
var id = $('#he').val(); //获得he里面的值
console.log(id);
for(var i = 0 ;i<=t;i++){
$('.setNumber').eq(i).val(id); //将设置的值赋给setNumber里面的第i行
var price = $(".setPrice").eq(i).val(); //获得setPrice第i行的值
var result = (price*id/100).toFixed(2);//将两者相乘
$('.result').eq(i).val(result); //将得到的结果赋给result里面的第i行
}
4)改变单个折扣率的值,单个折扣价也会跟着改变
在当前列的input中添加oninput事件
<td style="width: 100px">
<input id="discountRate${status.index}" style="width: 50px"
name="promotionPriceList[${status.index}].discountRate" class="setNumber"
type="number" value="${promotionPrice.discountRate }" οninput="getTotal('${status.index }');"/>
</td>
//计算
function getTotal(index){
var disId = "discountRate" + index; //获取折扣率的动态id
var proId = "productPrice" + index;
var sumId = "sum" + index;
console.log($("#"+disId).val());
console.log($("#"+proId).val());
var price = (($("#"+disId).val() * $("#"+proId).val())/100).toFixed(2); //得到结果保留两位小数
$('#'+sumId).val(price);
/* console.log(disId);
var b = $("#"+disId).val(); //$("#"+disId).val()动态id取值的写法,$("#disId").val()静态id取值的写法
console.log(b);// 控制台打印
var a = $("#"+disId).val()*1;
console.log(a); */
}
5)保存信息,保存信息分为两部分,第一部分将促销活动的信息插入主表,第二部分是将多个产品的信息循环插入副表
<td style="width: 100px">
<input id="discountRate${status.index}" style="width: 50px"
name="promotionPriceList[${status.index}].discountRate" class="setNumber"
type="number" value="${promotionPrice.discountRate }" οninput="getTotal('${status.index }');"/>
</td>
这种格式的写法可以根据name自动封装!【用正常的格式用form表单提交一样可以封装到类里面,这样封装的好处是什么】
promotionPriceService.save(promotionPrice);
<insert id="insert">
INSERT INTO sms_promotion_price(
id,
create_by,
create_date,
update_by,
update_date,
remarks,
del_flag,
sales_organization,
name,
description,
start_time,
end_time
) VALUES (
#{id},
#{createBy.id},
#{createDate},
#{updateBy.id},
#{updateDate},
#{remarks},
#{delFlag},
#{smsSalesOrganization.name},
#{name},
#{description},
#{startTime},
#{endTime}
)
</insert>
//循环插入
promotionPriceService.saveDetail(promotionPrice);
<insert id="insertPD" useGeneratedKeys="true" parameterType="java.util.List">
insert into sms_promotion_price_detail (
id,
create_by,
create_date,
update_by,
update_date,
remarks,
del_flag,
promotion_id,
product_identifier,
discount_rate,
product_price,
discount_price
)
values
<foreach collection="list" item="item" index="index" separator="," >
(#{item.id},
#{item.createBy.id},
#{item.createDate},
#{item.updateBy.id},
#{item.updateDate},
#{item.remarks},
#{item.delFlag},
#{item.promotionId},
#{item.productIdentifier},
#{item.discountRate},
#{item.productPrice},
#{item.discountPrice}
)
</foreach>
</insert>
<!-- 批量修改商品零售价信息 -->
<update id="updatePriceList" parameterType="SmsProductPrice">
<foreach collection="list" item="item" index="index" separator=";">
UPDATE sms_product_price a
SET a.price=#{item.price}
WHERE
a.sales_organization=#{item.salesOrganization} AND a.product_identifier=#{item.productIdentifier}
</foreach>
</update>
3、update页面
和添加页面类似,统一设置,修改折扣率是改变价格,修改单个折扣率时价格也跟着改变!
1)查询出页面所需信息!
//根据ID查询主表数据
PromotionPrice promotionPriceObject = promotionPriceService.get(promotionPrice.getId());
//根据主表ID查询详细信息
List<PromotionPrice> promotionPriceList = new ArrayList<PromotionPrice>();
List<PromotionPrice> promotionDetailList = promotionPriceService.findPromotionList(promotionPriceObject);
for (int i = 0; i < promotionDetailList.size(); i++) {
PromotionPrice sms = new PromotionPrice();
sms.setProductArticleNo(promotionDetailList.get(i).getProductArticleNo());
sms.setSmsSalesOrganizationName(promotionDetailList.get(i).getSmsSalesOrganizationName());
sms.setStartTime(promotionDetailList.get(i).getStartTime());
sms.setEndTime(promotionDetailList.get(i).getEndTime());
sms.setProductColordesc(promotionDetailList.get(i).getProductColordesc());
sms.setProductIdentifier(promotionDetailList.get(i).getProductIdentifier());
sms.setProductName(promotionDetailList.get(i).getProductName());
sms.setProductStyle(promotionDetailList.get(i).getProductStyle());
sms.setProductPrice(promotionDetailList.get(i).getProductPrice());
sms.setDiscountRate(promotionDetailList.get(i).getPromotionDiscountRate());
BigDecimal productPrice = promotionDetailList.get(i).getProductPrice();
sms.setProductPrice(productPrice);
BigDecimal discountRate = promotionDetailList.get(i).getPromotionDiscountRate();
BigDecimal discountPrice = productPrice.multiply(discountRate);
BigDecimal c = new BigDecimal(100);
//BigDecimal promotionDiscountRate = discountRate.multiply(c);
//sms.setDiscountRate(promotionDiscountRate);
//BigDecimal a = (promotionDiscountRate).multiply(productPrice);
//BigDecimal discountPrice = a.divide(c,2,BigDecimal.ROUND_HALF_UP);//a除以c保留2位小数
//sms.setDiscountPrice(discountPrice);
promotionPriceList.add(sms);
}
model.addAttribute("promotionPriceObject", promotionPriceObject);
promotionPrice.setPromotionPriceList(promotionPriceList);
把promotionDetailList里面的属性拿出来重新封装到主表类的表层,这样方便在页面上取值。
最后是批量更新,先根据主表id删除副表信息,然后再循环插入副表信息!
// 先根据主表id删除字表信息
promotionPriceDao.deleteDetail(promotionPrice);
<!-- 删除促销商品信息 -->
<update id="deleteDetail">
DELETE FROM sms_promotion_price_detail
WHERE promotion_id = #{id}
</update>
// 重新插入子表信息,循环插入
String id = promotionPrice.getId();
List<PromotionPrice> promotionPriceList = promotionPrice.getPromotionPriceList();
for (PromotionPrice promotions : promotionPriceList) {
promotions.preInsert();
promotions.setPromotionId(id); // 再字表list里面添加主表id,给字表promotion_id字段赋值
}
promotionPriceDao.insertPD(promotionPriceList);
4、ajax的post提交方法
$.post(
"${dpsCtx}/shoppingcart/qtyChange", //提交路径
{ "id" : id , "qty" : qty}, //提交参数
function(response){
if(response.code>0){ //响应条件
}else{
alert(response.msg); //响应结果
}
},
"json" //解析方式
);
@RequestMapping("qtyChange")
public Object qtyChange(String id, int qty) {
Map<String, Object> resultMap = new HashMap<String, Object>();
int changeNumber = dpsProductShoppingCartService.qtyChange(id, qty);
if (changeNumber > 0) {
resultMap.put("code", 1);
resultMap.put("msg", "更改数量成功!");
} else {
resultMap.put("code", 0);
resultMap.put("msg", "更改数量成功!");
}
return resultMap;
}
//ajax提交方法
if(price>0){
$.ajax({
cache: true, //是否在浏览器缓存中提取数据
type: "POST", //提交方式
url:"updatePrice", //提交路径
data:{
productIdentifier:productIdentifier,
salesOrganization:supplier,
priceto:price
},
async: false, //是否为异步请求
success: function(data) {
}
});
$.jBox.error('零售价设置成功', '系统提示');
$(".jbox-icon-error").css("margin-top","12px");
$("#"+pcid).attr("readonly",true);
$("#"+btn).text("修改");
}else{
$.jBox.error('零售价设置必须大于零', '系统提示');
$(".jbox-icon-error").css("margin-top","12px");
}
商品价格阶梯维护:
一、list页面
数据字典的引用
var tpl = $("#treeTableTpl").html().replace(/(\/\/\<!\-\-)|(\/\/\-\->)/g,"");
var data =${fns:toJson(list)}, ids = [], rootIds = [];
for (var i=0; i<data.length; i++){
ids.push(data[i].id);
}
ids = ',' + ids.join(',') + ',';
for (var i=0; i<data.length; i++){
if (ids.indexOf(','+data[i].parentId+',') == -1){
if ((','+rootIds.join(',')+',').indexOf(','+data[i].parentId+',') == -1){
rootIds.push(data[i].parentId);
}
}
}
for (var i=0; i<rootIds.length; i++){
addRow("#treeTableList", tpl, data, rootIds[i], true);
}
$("#treeTable").treeTable({expandLevel : 5});
});
这段代码直接放到$(document).ready(function(){}里面加载
<li><label style="width: 100px">常规/非常规:</label>
<form:select path="routine" class="input-medium" cssStyle="width:177px;">
<form:option value="" label="请选择"/>
<form:options items="${fns:getDictList('routine_type')}" itemLabel="label" itemValue="value" htmlEscape="false"/>
</form:select>
</li>
<td> ${fns:getDictLabel(smsPriceLadder.routine, 'routine_type', '')}</td>
routine_type指的是数据字典里面配的类型
删除功能。
先根据主表id删除阶梯价格详细信息,然后再根据主表id删除主表信息!
二、form页面
增加价格阶梯
function addPayment(){
var tr = $('#contentTable tr:last');
var seq = parseInt($(tr).find("td :first").text());
var trClone = $(tr).clone();
$(trClone).find("td :first").text(seq+1);
$("#contentTable").append(trClone);
updateInputName();
}
删除行
function delRow(self){
var trList = $('#contentTable tbody tr');
if (trList.size() <= 1){
$.jBox.messager('删除失败,必须保留一行数据!',"提示", 5000, {icon: 'error'});
return;
}
$(self).parents("tr").remove();
//更新序号
$('#contentTable tbody tr').each(function(index){
$(this).find("td :first").text(index+1);
});
updateInputName();
}
function updateInputName(){
$('#contentTable tbody tr').each(function(trIndex){
$(this).find("input[name^='smsPriceLadderDetailList']").each(function(index){
var field = $(this).attr("field");
var name = "smsPriceLadderDetailList["+trIndex+"]."+field;
$(this).attr("name",name);
});
});
}
用样式来限制<class="input-small required number">输入的数只能是正整数
<td>
<form:input path="smsPriceLadderDetailList[0].grade" field="grade" class="input-small required digits"/>
</td>
<td>
<form:input path="smsPriceLadderDetailList[0].lowerLimit" field="lowerLimit" class="input-small required number"/>
</td>
<td>
<form:input path="smsPriceLadderDetailList[0].upperLimit" field="upperLimit" class="input-small required number"/>
</td>
<td>
<form:input path="smsPriceLadderDetailList[0].discountRate" field="discountRate" class="input-small required number"/>
</td>
添加之后的行用上面这种方式来封装
//保存的后台验证!
public String save(SmsPriceLadder smsPriceLadder, Model model, RedirectAttributes redirectAttributes) {
if (!beanValidator(model, smsPriceLadder)) { 【验证的含义】
return form(smsPriceLadder, model);
}
List<SmsPriceLadderDetail> validateSmsPriceLadderDetailList = smsPriceLadder.getSmsPriceLadderDetailList();
for (SmsPriceLadderDetail spld : validateSmsPriceLadderDetailList) {
spld.getLowerLimit(); //下限
spld.getUpperLimit();//上限
if(spld.getLowerLimit().doubleValue()>spld.getUpperLimit().doubleValue()){
addMessage(redirectAttributes, "下限不能大于上限");
return "redirect:" + Global.getAdminPath() + "/sms/priceladder/smsPriceLadder/?repage"; 【整个验证的逻辑】
}
}
for (SmsPriceLadderDetail spld : validateSmsPriceLadderDetailList) {
for (SmsPriceLadderDetail spld2 : validateSmsPriceLadderDetailList) {
if (!spld.getGrade().equals(spld2.getGrade())) {
if (spld.getLowerLimit().doubleValue() > spld2.getLowerLimit().doubleValue()
&& spld.getLowerLimit().doubleValue() < spld2.getUpperLimit().doubleValue()){
addMessage(redirectAttributes, "不在这个区间");
return "redirect:" + Global.getAdminPath() + "/sms/priceladder/smsPriceLadder/?repage";
}
if (spld.getUpperLimit().doubleValue() > spld2.getLowerLimit().doubleValue()
&& spld.getUpperLimit().doubleValue() < spld2.getUpperLimit().doubleValue()){
addMessage(redirectAttributes, "不在这个区间");
return "redirect:" + Global.getAdminPath() + "/sms/priceladder/smsPriceLadder/?repage";
}
}
}
}
SmsPriceLadder s = smsPriceLadderService.getSmsPriceLadder(smsPriceLadder.getSmsSalesOrganization().getName());
if (s != null) {
addMessage(redirectAttributes, "销售组织" + smsPriceLadder.getSmsSalesOrganization().getName() + "已存在");
return "redirect:" + Global.getAdminPath() + "/sms/priceladder/smsPriceLadder/?repage";
}
三、update页面
页面和form页面一样,update的思路,先根据主表id删除价格阶梯详情,然后再添加新的信息。
public void updateSmsPriceLadder(SmsPriceLadder smsPriceLadder) {
//先更新主表信息
SmsPriceLadder tempSmsPriceLadder = get(smsPriceLadder.getId()); 【数据已经封装在了smsPriceLadder,为什么还要取出来再重新封装一次?】
tempSmsPriceLadder.setRoutine(smsPriceLadder.getRoutine());
super.save(tempSmsPriceLadder);
List<SmsPriceLadderDetail> smsPriceLadderDetailList = smsPriceLadder.getSmsPriceLadderDetailList();
for (SmsPriceLadderDetail smsPriceLadderDetail : smsPriceLadderDetailList){
smsPriceLadderDetail.preInsert();
smsPriceLadderDetail.setLadderId(smsPriceLadder.getId());
}
tempSmsPriceLadder.setSmsPriceLadderDetailList(smsPriceLadderDetailList);
//删除子表信息
smsPriceLadderDao.deletePriceLadderDetail(tempSmsPriceLadder);
//重新插入子表信息
smsPriceLadderDao.ladderDetailInsert(tempSmsPriceLadder);
}
四、watch页面
直接调用update方法就可以了!
商品数据
一、list页面
//分页查询
function page(n,s){
$("#searchForm").attr("action", "${ctx}/sms/product/product/list"); 【如果路径是"${ctx}/sms/product/product/",那对应的value={list,""}】
$("#pageNo").val(n);
$("#pageSize").val(s);
$("#searchForm").submit();
return false;
}
//清空查询表单
function clearForm(){
$("#identifier").val("");
$("#name").val("");
$("#style").val("");
$("#articleNo").val("");
$("#colorDesc").val("");
$("#brandId").val("");
document.getElementById("brand.name").value="";
$("#typeId").val("");
document.getElementById("type.name").value="";
$("#yearnum").val("");
}
商品数据功能
1、创建数据库,实体类
Product类
@ExcelField(title = "商品条码*", type = 0, sort = 1)
private String identifier; // 商品条码
@ExcelField(title = "名称*", type = 0, sort = 2)
private String name; // 名称
@ExcelField(title = "品牌*", type = 1, sort = 3, value = "brand.name")
private SmsProductBrand brand; // 品牌
@ExcelField(title = "品牌*", type = 2, sort = 3)
private String brandName;
private String brandId; // 品牌ID
@ExcelField(title = "年份(2017~2024)*", type = 0, sort = 4, dictType = "productYearnum")
private String yearnum; // 年份
@ExcelField(title = "款号*", type = 0, sort = 5)
private String style; // 款号
@ExcelField(title = "款号代码*", type = 0, sort = 6)
private String styleCode; // 款号代码
@ExcelField(title = "季度(春夏、秋冬、全年)*", type = 0, sort = 7, dictType = "productQuarter")
private String quarter; // 季度
@ExcelField(title = "性别(通用、男、女、男童、女童)*", type = 0, sort = 8, dictType = "productSexCode")
private String sexCode; // 性别代码
@ExcelField(title = "颜色名称*", type = 0, sort = 9)
private String colorDesc; // 颜色名称
@ExcelField(title = "颜色代码*", type = 0, sort = 10)
private String color; // 颜色代码
@ExcelField(title = "货号*", type = 0, sort = 11)
private String articleNo; // 货号
private String typeId; // 类型ID
@ExcelField(title = "类型*", type = 1, sort = 12, value = "type.name")
private SmsProductType type;// 类型
@ExcelField(title = "类型*", type = 2, sort = 12)
private String typeName;// 类型
@ExcelField(title = "主题系列", type = 0, sort = 13)
private String themeSeries; // 主题系列
@ExcelField(title = "类别(主推款、常规款、明星款)*", type = 0, sort = 14, dictType = "productCategory")
private String category; // 类别
@ExcelField(title = "爆品新品(爆品、主销品)*", type = 0, sort = 15, dictType = "productNewExplosive")
private String newExplosive; // 爆品新品
@ExcelField(title = "起批量*", type = 0, sort = 16)
private String batchProduction; // 起批量
@ExcelField(title = "常规/非常规(常规、非常规)*", type = 0, sort = 17, dictType = "productRoutine")
private String routine; // 常规/非常规
@ExcelField(title = "规格(无规格、S、M、L)*", type = 0, sort = 18, dictType = "productSpecifications")
private String specifications; // 规格代码
@ExcelField(title = "尺寸描述*", type = 0, sort = 19)
private String sizeDescription; // 尺寸描述
@ExcelField(title = "尺码类别(其他、男下装、女下装、男鞋、女鞋)", type = 0, sort = 20, dictType = "productSizeCategory")
private String sizeCategory; // 尺码类别
@ExcelField(title = "尺码", type = 0, sort = 21)
private String sizeValue; // 尺码
@ExcelField(title = "材质*", type = 0, sort = 23)
private String texture; // 材质
@ExcelField(title = "单位(个、套)*", type = 0, sort = 24, dictType = "productUnit")
private String unit; // 单位
@ExcelField(title = "商品特点描述*", type = 0, sort = 25)
private String description; // 商品特点描述
private String picturePath; // 列表图片路径
private String upDownFlag; // 上下架标记
private Date upDate; // 上架时间
private Date downDate; // 下架时间
private String frozenFlag; // 冻结标记
private User createUser; // 建档人
private User updateUser; // 修改人
// 扩展字段,用于传参,不用保存
private String picturesUrl; // 商品所有图片路径拼接字符串
private String picturesName;// 商品所有图片名称拼接字符串
private String picturesSize;// 商品所有大小拼接字符串
private String picturesSort;// 商品所有图片展示顺序拼接字符串
private String price; // 零售价
private String discountPrice;// 促销价;
private String discountRate;// 折扣;
private String salesOrganization;// 销售区域;
private List<Product> sizeValueList;
private List<Product> sexCodeList;
private List<Product> colorList;
private List<ProductPicture> productPictureList;
private String hasSizeValue;
private String hasSex;
private String upMonth;// 新品上架月份
private String startPrice;// 开始价格
private String endPrice;// 结束价格
private String[] categorys;// 爆品主销品查询 连接字符串,用于in查询
private String typeIds;
private int countStyle;// 同款统计
private CommonsMultipartFile uploadFile;
private String wclmIdentifier;//箱唛编号
private int wclmQty;//装箱数量
ProductPicture类
private String productIdentifier; // 商品条码
private String pictureName;// 图片名称
private String size;// 大小
private String picturePath;// 商品图片路径
private String sort;// 图片展示顺序
1、list页面,打开品牌窗口
//打开品牌选择窗口
function openBrandListWin(){
$.jBox("iframe:${ctx}/sms/product/product/brandList", {
title: "商品品牌选择",
width: 800,
height: 350,
buttons: { '关闭': true }
});
}
$(function(){
//设置td背景透明
$("tbody td").css("background-color","Transparent")
//更改鼠标为手指
$("tbody tr").css("cursor","pointer");
// 鼠标进入事件,更改背景色和字体颜色
$("tbody tr").mouseenter(function(){
$(this).css("background-color","#2FA4E7");
$(this).find("td").css("color","white");
$(this).find("a").css("color","white");
});
// 鼠标移出事件,更改背景色和字体颜色
$("tbody tr").mouseleave(function(){
$(this).css("background-color","white");
$(this).find("td").css("color","#555555");
$(this).find("a").css("color","#2FA4E7");
});
});
//将选择的值付给父窗口元素
function setParentWinType(brandId,brandName,brandIdentifier,areaName){ //function接收起的参数名字,不用和类里面的属性对应
var parentWin = window.parent;
parentWin.setBrandByWin(brandId,brandName,brandIdentifier,areaName);
}
//将品牌选择窗口中选择的品牌付给表单元素
function setBrandByWin(brandId,brandName,brandIdentifier,areaName){
$("#brandId").val(brandId);
document.getElementById("brand.name").value=brandName;
//document.getElementById("brand.identifier").value=brandIdentifier;
//document.getElementById("brand.area.name").value=areaName;
$.jBox.close(true);
}
//清空查询表单
function clearForm(){
$("#identifier").val("");
$("#name").val("");
$("#style").val("");
$("#articleNo").val("");
$("#colorDesc").val("");
$("#brandId").val("");
document.getElementById("brand.name").value="";
$("#typeId").val("");
document.getElementById("type.name").value="";
$("#yearnum").val("");
}
//点击查询按钮查询
function query(){
$("#searchForm").attr("action", "${ctx}/sms/product/product/list");//路径
$("#searchForm").submit(); //提交
return false; //不跳转页面
// 单独写时间时的格式
<fmt:formatDate value="${product.updateDate}" pattern="yyyy-MM-dd HH:mm:ss"/>
String postfix = StringUtils.substringAfter(uploadFile.getOriginalFilename(), ".").toUpperCase();
substringAfter(string,string)返回第一个参数字符串中在第一次出现第二个参数字符串之后的子字符串,如果第一个参数字符串中不包含第二个参数字符串,则返回空字符串。
toUpperCase();将所有的英文字母转化为大写字母,toLowerCase();将所有英文字母转化为小写字母。
bigdecimal比较大小,compareTo,返回int类型,-1表示小于,0是等于,1是大于。
/**
* 商品数据导入
*
* @param file
* @param redirectAttributes
* @param model
* @return
*/
@RequiresPermissions("sms:product:product:edit")
@RequestMapping(value = "import", method = RequestMethod.POST)
public String importFile(MultipartFile uploadFile, RedirectAttributes redirectAttributes, Model model) {
try {
if (!uploadFile.isEmpty()) {
String postfix = StringUtils.substringAfter(uploadFile.getOriginalFilename(), ".").toUpperCase();
if (!StringUtils.contains("XLS,XLSX", postfix)) {
addMessage(redirectAttributes, "导入商品数据失败,仅限于导入.xls,.xlsx 文件");
return "redirect:" + Global.getAdminPath() + "/sms/product/product/list?repage";
}
BigDecimal bd = new BigDecimal(uploadFile.getSize());
bd = bd.divide(new BigDecimal("1024"));
bd = bd.divide(new BigDecimal("1024"));
BigDecimal bd_half_even = bd.setScale(4, RoundingMode.HALF_EVEN);
BigDecimal ok = new BigDecimal("5");
if (bd_half_even.compareTo(ok) == 1) {
addMessage(redirectAttributes, "导入商品数据失败,文件大小超过5M");
return "redirect:" + Global.getAdminPath() + "/sms/product/product/list?repage";
}
ImportExcel ei = new ImportExcel(uploadFile, 1, 0);
List<Product> list = ei.getDataList(Product.class);
if (list.size() > 0) {
int totalFaildNum = 0;
int rowFailNum = 0;
StringBuffer sb = new StringBuffer();
StringBuffer checkResultMessage = new StringBuffer();
Date dt = new Date();
Product product = null;
SmsProductBrand brand = null;
SmsProductType type = null;
int rowNum = 3;//行号
int iCount = 0; //计数器
for(int i =0; i < list.size(); i++){
rowFailNum = 0;
sb = new StringBuffer();
iCount = i + 1;
//验证导入文件中是否有相同的商品条码和货号
if( i < (list.size() -1) ){
for(int j = iCount; j < list.size(); j++){ //从i+1开始循环,第i行开始往下开始比较
if(list.get(i).getIdentifier().equals(list.get(j).getIdentifier())){
sb.append("商品条码["+list.get(i).getIdentifier()+"]与第["+j+"]行的商品条码相同; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if(list.get(i).getArticleNo().equals(list.get(j).getArticleNo())){
sb.append("货号["+list.get(i).getArticleNo()+"]与第["+j+"]行的货号相同; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
}
}
//验证商品条码是否为空
if (StringUtils.isBlank(list.get(i).getIdentifier())) {
sb.append("商品条码为空; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
} else {
product = productService.getProductByIdentifier(list.get(i).getIdentifier());
if (product == null) {
list.get(i).setCreateBy(UserUtils.getUser());
list.get(i).setCreateDate(dt);
list.get(i).setUpdateBy(UserUtils.getUser());
list.get(i).setUpDate(dt);
list.get(i).setDelFlag("0");
list.get(i).setFrozenFlag("2");
list.get(i).setUpDownFlag("2");
list.get(i).preInsert();
list.get(i).setIsNewRecord(true);
} else {
product = null;
product = productService.getProductByArticleNo(list.get(i).getArticleNo());
if(product != null){
if(! product.getIdentifier().equals(list.get(i).getIdentifier()) ){
product = null;
sb.append("货号["+list.get(i).getArticleNo()+"]已存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}else{
list.get(i).setId(product.getId());
list.get(i).setUpdateBy(UserUtils.getUser());
list.get(i).setUpDate(dt);
list.get(i).setPicturePath(product.getPicturePath());
list.get(i).setIsNewRecord(false);
product = null;
}
}
}
}
if (StringUtils.isBlank(list.get(i).getName())) {
sb.append("名称为空; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getBrandName())) {
sb.append("品牌为空; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
} else {
brand = brandService.getProductBrandByName(list.get(i).getBrandName());
if (brand == null) {
sb.append("品牌[" + list.get(i).getBrandName() + "]不存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
} else {
list.get(i).setBrandId(brand.getId());
}
}
if (StringUtils.isBlank(list.get(i).getYearnum())) {
sb.append("年份在数据字典中不存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getStyle())) {
sb.append("款号为空; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
} else {
list.get(i).setStyleCode(StringUtils.substring(list.get(i).getStyle(), 2, 5));
}
if (StringUtils.isBlank(list.get(i).getStyleCode())) {
sb.append("款号代码为空; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getQuarter())) {
sb.append("季度在数据字典中不存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getSexCode())) {
sb.append("性别在数据字典中不存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getColorDesc())) {
sb.append("颜色为空; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getColor())) {
sb.append("颜色代码为空; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getArticleNo())) {
sb.append("货号为空; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getTypeName())) {
sb.append("类型为空; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
} else {
type = typeService.getProductType(list.get(i).getTypeName());
if (type == null) {
sb.append("类型[" + list.get(i).getTypeName() + "]不存在;");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
} else {
list.get(i).setTypeId(type.getId());
}
}
if (StringUtils.isBlank(list.get(i).getCategory())) {
sb.append("类别在数据字典中不存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getNewExplosive())) {
sb.append("爆品主销品在数据字典中不存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getBatchProduction()) || list.get(i).getBatchProduction() == null) {
sb.append("起批量为空; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getRoutine())) {
sb.append("常规/非常规在数据字典中不存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (StringUtils.isBlank(list.get(i).getSpecifications())) {
sb.append("规格在数据字典中不存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if("0".equals(list.get(i).getSpecifications())){
list.get(i).setSizeCategory("O");
list.get(i).setSizeValue("U");
}
if (StringUtils.isNotBlank(list.get(i).getSizeCategory())
&& StringUtils.isNotBlank(list.get(i).getSizeValue())) {
List<Dict> dl = DictUtils.getDictList(list.get(i).getSizeCategory());
boolean isExists = false;
for (Dict dict : dl) {
if (dict.getValue().equals(list.get(i).getSizeValue())) {
isExists = true;
}
}
if (!isExists) {
sb.append("尺码[" + list.get(i).getSizeValue() + "]在尺码类别[" + list.get(i).getSizeCategory()
+ "]数据字典中不存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
}
if (StringUtils.isNotBlank(list.get(i).getSizeCategory())){
if (StringUtils.isBlank(list.get(i).getSizeValue())){
list.get(i).setSizeCategory("O");
list.get(i).setSizeValue("U");
}
}
if (StringUtils.isBlank(list.get(i).getUnit())) {
sb.append("单位在数据字典中不存在; ");
totalFaildNum = totalFaildNum + 1;
rowFailNum = rowFailNum + 1;
}
if (rowFailNum > 0) {
checkResultMessage.append("第[" + rowNum + "]行:");
sb.append("<br>");
checkResultMessage.append(sb);
sb = null;
}
rowFailNum = 0;
rowNum = rowNum + 1;
}
if (totalFaildNum > 0) {
// 数据问题,将问题返回给客户
addMessage(redirectAttributes, "导入商品数据失败,请修改后重新导入:<br>" + checkResultMessage.toString());
return "redirect:" + Global.getAdminPath() + "/sms/product/product/list?repage";
} else {
// 保存数据
productService.importData(list);
addMessage(redirectAttributes, "导入商品数据成功,应导入" + list.size() + "笔,成功导入" + list.size() + "笔");
return "redirect:" + Global.getAdminPath() + "/sms/product/product/list?repage";
}
}
addMessage(redirectAttributes, "导入商品数据成功,应导入" + list.size() + "笔,成功导入" + list.size() + "笔");
return "redirect:" + Global.getAdminPath() + "/sms/product/product/list?repage";
} else {
addMessage(redirectAttributes, "导入商品数据失败,文件为空");
return "redirect:" + Global.getAdminPath() + "/sms/product/product/list?repage";
}
} catch (Exception ex) {
addMessage(redirectAttributes, "导入商品数据失败," + ex.getMessage());
return "redirect:" + Global.getAdminPath() + "/sms/product/product/list?repage";
}
}
//只能输入正整数及两位小数。
οnkeyup="clearNoNum(this)"
function clearNoNum(obj){
//修复第一个字符是小数点 的情况.
if(obj.value !=''&& obj.value.substr(0,1) == '.'){
obj.value="";
}
obj.value = obj.value.replace(/^0*(0\.|[1-9])/, '$1');//解决 粘贴不生效
obj.value = obj.value.replace(/[^\d.]/g,""); //清除“数字”和“.”以外的字符
obj.value = obj.value.replace(/\.{2,}/g,"."); //只保留第一个. 清除多余的
obj.value = obj.value.replace(".","$#$").replace(/\./g,"").replace("$#$",".");
obj.value = obj.value.replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3');//只能输入两个小数
if(obj.value.indexOf(".")< 0 && obj.value !=""){//以上已经过滤,此处控制的是如果没有小数点,首位不能为类似于 01、02的金额
if(obj.value.substr(0,1) == '0' && obj.value.length == 2){
obj.value= obj.value.substr(1,obj.value.length);
}
}
}
//输入值之后,校验设置的折扣率为两位以内的正数,设置值计算
function setValue(){
var t =$('.setNumber').length;
var id = $('#he').val();
var ed = /(^[0-9]{1,2}$)|(^[0-9]{1,2}[\.]{1}[0-9]{1,2}$)/;
var va = $('#contentTable').find('tr').length;
if(va == 1){
$.jBox.messager('请先导入商品信息!',"提示", 5000, {icon: 'error'});
}
if(!ed.test(id)){
$.jBox.messager('请输入两位小数以内的正数!',"提示", 5000, {icon: 'error'});
}else{
for(var i = 0 ;i<=t;i++){
$('.setNumber').eq(i).val(id);
var price = $(".setPrice").eq(i).val();
var result = (price*id/100).toFixed(2);
$('.result').eq(i).val(result);
}
}
}
//foreach的用法
List<PromotionPrice> priceList = promotionPrice.getPromotionPriceList();
for (PromotionPrice promotionPricelist : priceList) { //promotionPricelist 是Promotionprice中的类,priceList是需要循环的对象
if(promotionPricelist.getDiscountRate() == null){
model.addAttribute("message", "导入数据有误,请重新导入! ");
return "modules/sms/promotionprice/promotionPriceForm";
}
}