• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

ASP.NET MVC中商品模块小样

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

在前面的几篇文章中,已经在控制台和界面实现了属性值的笛卡尔乘积,这是商品模块中的一个难点。本篇就来实现在ASP.NET MVC4下商品模块的一个小样。与本篇相关的文章包括:


1、ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积01, 在控制台实现 
2、
ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积02, 在界面实现  
3、
再议ASP.NET MVC中CheckBoxList的验证  
4、
ASP.NET MVC在服务端把异步上传的图片裁剪成不同尺寸分别保存,并设置上传目录的尺寸限制  
5、
ASP.NET MVC异步验证是如何工作的01,jQuery的验证方式、错误信息提示、validate方法的背后  
6、
ASP.NET MVC异步验证是如何工作的02,异步验证表单元素的创建  
7、
ASP.NET MVC异步验证是如何工作的03,jquery.validate.unobtrusive.js是如何工作的 
8、
MVC批量更新,可验证并解决集合元素不连续控制器接收不完全的问题 
9、
MVC扩展生成CheckBoxList并水平排列  

 

本篇主要包括:

商品模块小样简介
领域模型和视图模型
控制器和视图实现

 

商品模块小样简介

 

※ 界面

○ 类别区域,用来显示产品类别,点击选择某个类别,在"产品属性"区域出现该类别下的所有属性,以及属性值,对于单选的属性值用Select显示,对于多选的属性值用CheckBoxList显示。
○ 产品描述,表示数据库中产品表中的字段,当然实际情况中,这里的字段更多,比如上传时间,是否通过,产品卖点,等等。
○ 产品属性,只有点击选择产品类别,这里才会显示
○ 定价按钮,点击这个按钮,如果"产品属性"区域中有CheckBoxList项,"产品SKU与定价"区域会出现关于属性值、产品价格的SKU组合项;如果"产品属性"区域中没有CheckBoxList项,"产品SKU与定价"区域只出现一个有关价格的input元素。另外,每次点击定价按钮,出现提交按钮,定价按钮隐藏。
○ 产品SKU与定价:这里要么呈现属性值、价格的SKU项,要么只出现一个有关价格的input元素

 

※ 点击类别项,在"产品属性"区域包括CheckBoxList

○ 点击类名中的"家电"选项,在"产品属性"区域中出现属性及其值,有些属性值以Select呈现,有些属性值以CheckBoxList呈现
○ 点击属性行后面的"删除行"直接删除属性行

 

※ 点击类别项,在"产品属性"区域包括CheckBoxList,点击"定价"按钮

点击"定价"按钮,如果每组的CheckBoxList中没有一项被选中,会在属性行后面出现错误提示。在"产品SKU与定价"区域不会出现内容。

 

※ 点击类别项,在"产品属性"区域包括CheckBoxList,点击"定价"按钮,再点击CheckBoxList选项,某些错误提示消失

点击CheckBoxList中的某项,该属性行后面的错误提示消失。在"产品SKU与定价"区域还是不会出现内容。

 

※ 点击类别项,在"产品属性"区域包括CheckBoxList,如果所有的CheckBoxList至少有一项被选中,点击"定价"按钮

 

○ 会把所有的选中属性值进行笛卡尔乘积显示到"产品SKU与定价"区域
○ 出现"提交"按钮
○ 如果有关价格的input验证不通过会出现异步验证错误信息
○ 与有关价格的input一起渲染的还有一个隐藏域,用来存放该SKU项的属性值Id,以便和价格一起被保存到数据库

 

 

※ 点击类别项,在"产品属性"区域不包括CheckBoxList

当选择类别中的"家具"项,在"产品属性"区域中的属性值只是以Select来呈现。

 

※ 点击类别项,在"产品属性"区域不包括CheckBoxList,点击"定价"按钮

如果"产品属性"区域中只有Select元素,点击"定价"按钮,在"产品SKU与定价"区域只出现有关价格的input,并且带异步验证,同时还出现提交按钮。

 

※ 在控制器提交产品的方法中打断点,点击"提交"按钮

在界面提交的包括:

 

在控制器方法中收到了所有的提交:

 

 

领域模型和视图模型

 

有关产品类别的领域模型:

    public class Category
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

 

有关属性的领域模型:

    public class Prop
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int CategoryId { get; set; }
        public short InputType { get; set; }
        public Category Category { get; set; }
    }

 

以上,InputType属性对应InputTypeEnum的枚举项,会依据此属性加载不同的视图(Select或CheckBoxList)。

 

    public enum InputTypeEnum
    {
        //下拉选框
        PropDropDownList = 0,
        //复选框
        PropCheckBoxList = 1
    }  

 

有关属性值的领域模型:

    public class PropOption
    {
        public int Id { get; set; }
        public string RealValue { get; set; }
        public int PropId { get; set; }
        public Prop Prop { get; set; }
    }    

 

在产品提交页,和产品有关包括:产品类别、产品本身的描述、属性及属性值(属性值有些以Select显示,有些以CheckBoxList显示)、属性值和价格的SKU组合项。提炼出有关产品的一个视图模型:

    public class ProductVm
    {
        public ProductVm()
        {
            this.PropOptionDs = new List<PropOptionVmD>();
            this.ProductSKUs = new List<ProductSKUVm>();
            this.PropOptionCs = new List<PropOptionVmC>();
        }
        public int Id { get; set; }
        [Required(ErrorMessage = "必填")]
        public int CategoryId { get; set; }
        [Required(ErrorMessage = "必填")]
        [Display(Name = "产品编号")]
        [MaxLength(10, ErrorMessage = "最大长度10")]
        public string Code { get; set; }
        [Required(ErrorMessage = "必填")]
        [Display(Name = "产品名称")]
        [MaxLength(10, ErrorMessage = "最大长度10")]
        public string Name { get; set; }
        public List<PropOptionVmD> PropOptionDs { get; set; }
        public List<PropOptionVmC> PropOptionCs { get; set; }
        public List<ProductSKUVm> ProductSKUs { get; set; }
    }

以上,
PropOptionDs表示以Select显示属性值的、有关属性和属性值的集合
PropOptionCs表示以CheckBoxList显示属性值的、有关属性和属性值的集合
ProductSKUs 表示SKU项的集合

 

PropOptionVmD视图模型用来显示每一个属性名,该属性下的属性值是以Select呈现:

    public class PropOptionVmD
    {
        public int Id { get; set; }
        public int PropId { get; set; }
        public string PropName { get; set; }
        [Required(ErrorMessage = "必填")]
        public int PropOptionId { get; set; } 
    }

以上,
PropId用来表示属性Id,在界面中是以隐藏域存在的,会被传给服务端
PropName 表示属性名,在界面中显示属性的名称
PropOptionId 表示界面中被选中的属性值Id

 

PropOptionVmC视图模型也用来显示每一个属性名,该属性下的属性值以CheckBoxList呈现:

    public class PropOptionVmC
    {
        public int Id { get; set; }
        public int PropId { get; set; }
        public string PropName { get; set; }
        public string PropOptionIds { get; set; }  
    }

 

ProductSKUVm视图模型用来显示SKU项中的价格部分:

    public class ProductSKUVm
    {
        [Display(Name = "价格")]
        [Required(ErrorMessage = "必填")]
        [Range(typeof(Decimal), "0", "9999", ErrorMessage = "{0} 必须是数字介于 {1} 和 {2}之间.")]
        public decimal Price { get; set; } 
        public string  OptionIds { get; set; } 
    }

以上,
Price用来显示SKU项中的价格
OptionIds用来存放SKU项中的所有属性值编号,以逗号隔开,在界面中以隐藏域存在

 

控制器和视图实现

 

□ HomeController

 

当呈现Home/Index.cshtml视图的时候,HomeController应该提供一个方法,把所有的类别放在SelectListItem集合中传给前台,并返回一个有关产品视图模型强类型视图。

 

当在界面上点击类别选项,HomeController应该有一个方法接收类别的Id,把该类别下所有的属性Id以Json格式返回给前台。

 

当在界面上接收到一个属性Id集合,需要遍历属性Id集合,把每个属性Id传给控制器,HomeController应该有一个方法接收属性Id,在方法内部根据InputType来决定显示带Select的视图,还是带CheckBoxList的视图。

 

当点击界面上的"定价"按钮,可能需要对属性值进行笛卡尔乘积,可能不需要,因此,HomeController应该提供2个方法,一个方法用来渲染出需要笛卡尔乘积的视图,另一个方法用来渲染不需要笛卡尔乘积的视图。

 

当点击界面上的"提交"按钮,HomeController应该提供一个提交产品的方法,该方法接收的参数是有关产品的视图模型。

 

   public class HomeController : Controller
    {
        public ActionResult Index()
        {
            //把类别封装成SelectListItem集合传递到前台
            var categories = Database.GetCategories();
            var result = from c in categories
                select new SelectListItem() {Text = c.Name, Value = c.Id.ToString()};
            ViewData["categories"] = result;
            return View(new ProductVm());
        }
        //添加产品
        [HttpPost]
        public ActionResult AddProduct(ProductVm productVm)
        {
            
            if (ModelState.IsValid)
            {
                //TODO:各种保存
                return Json(new { msg = true });
            }
            else
            {
                //把类别封装成SelectListItem集合传递到前台
                var categories = Database.GetCategories();
                var result = from c in categories
                             select new SelectListItem() { Text = c.Name, Value = c.Id.ToString() };
                ViewData["categories"] = result;
                return RedirectToAction("Index", productVm);
            }
        }
        //根据分类返回分类下的所有属性Id
        [HttpPost]
        public ActionResult GetPropIdsByCategoryId(int categoryId)
        {
            var props = Database.GetPropsByCategoryId(categoryId);
            List<int> propIds = props.Select(p => p.Id).ToList();
            return Json(propIds);
        }
        //显示属性和属性项的部分视图
        public ActionResult AddPropOption(int propId)
        {
            var prop = Database.GetProps().Where(p => p.Id == propId).FirstOrDefault();
            var propOptions = Database.GetPropOptionsByPropId(propId);
            if (prop.InputType == (short) InputTypeEnum.PropDropDownList)
            {
                PropOptionVmD propOptionVmD = new PropOptionVmD();
                propOptionVmD.PropId = propId;
                propOptionVmD.PropName = prop.Name;
                ViewData["propOptionsD"] = from p in propOptions
                                           select new SelectListItem() { Text = p.RealValue, Value = p.Id.ToString() };
                return PartialView("_AddPropOptionD", propOptionVmD);
            } 
            else
            {
                PropOptionVmC  propOptionVmC = new PropOptionVmC();
                propOptionVmC.PropId = propId;
                propOptionVmC.PropName = prop.Name;
                ViewData["propOptionsC"] = from p in propOptions
                    select new SelectListItem() {Text = p.RealValue, Value = p.Id.ToString()};
                return PartialView("_AddPropOptionC", propOptionVmC);
            }          
        }
        //当在前台界面上勾选CheckBoxList选项,点击"定价"按钮,就把PropAndOption集合传到这里
        [HttpPost]
        public ActionResult DisplaySKUs(List<PropAndOption> propAndOptions)
        {
            try
            {
                //属性值分组
                var groupValues = (from v in propAndOptions
                                   group v by v.PropId
                                       into grp
                                       select grp.Select(t => Database.GetOptionValueById(t.PropOptionId))).ToList();
                //属性值Id分组
                var groupIds = (from i in propAndOptions
                                group i by i.PropId
                                    into grep
                                    select grep.Select(t => t.PropOptionId.ToString())).ToList();
                //属性值分组后进行笛卡尔乘积
                IEnumerable<string> values;
                values = groupValues.First();
                groupValues.RemoveAt(0);

 
                    
                    
                     
                    
                    
                    
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
【ASP.NET Core 3.1_参考中间件源码实现自定义AOP】发布时间:2022-07-10
下一篇:
ASP.NET MVC5请求管道和生命周期发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap