極簡實用的Asp.NetCore框架再新增商城模塊


概述

關於這個框架的背景,在前面我已經交代過了。不清楚的可以查看這個鏈接 

1、極簡實用的Asp.NetCore模塊化框架決定免費開源了

2、極簡實用的Asp.NetCore模塊化框架新增CMS模塊

算下來確實好長時間沒更新博客了,在這段時間內一直在出差,閑暇時間一直在想dotnetcore框架本身就是模塊化的,為什么還要在這個上層應用上面繼續進行模塊化封裝,意義何在?是為了更好地划分業務還是輪子重復利用?

細細想來,這個框架不應該再繼續模塊化下去,主要有以下幾點理由支持:

1、本身於我現有地業務而言,沒必要模塊化,我只是做個大而全地系統(權限管理,內容管理,商城,微信管理等)。

2、如果要做模塊化,本身就要犧牲掉一些性能,這是我反反復復斟酌以后不能接受的,主要是犧牲性能有點多!

3、dotnetcore本身就更友好模塊化,沒必要在這個上層應用上面再包裹一層,沒有任何意義,我下載了dotnetcore源碼后,覺得它的設計理念特別棒,於是“dotnetcore”本身就是最好的模塊化(組件化)框架,可以把很多時間和精力投身於源碼上面研究,沒有必要在糾結於模塊化這個概念,在上層應用折騰來折騰去,對於技術的成長微乎其微。

4、以前划分為模塊化,是想朝微服務的方向發展,到時盡量改動小一點。現在想想我就一個后台管理,沒必要想那么多。

  基於以上幾點,我於是把框架進行了更改,對於原來的模塊化框架也進行了分支保留(一定意義上來說也不全是模塊化)。

新增業務功能

新增加一個商城模塊,主要包含商品管理(支持多個sku),商品分類,小程序用戶,用戶收獲地址、訂單各種狀態的列表。

 

 關於添加和修改商品的部分后端代碼:

 public async Task<ApiResult> AddAsync(GoodsInput input)
        {
            try
            {
                Db.BeginTran();
                // 保存商品
                var goods = _mapper.Map<Goods>(input);
                var goodsId = await Db.Insertable<Goods>(goods).ExecuteReturnIdentityAsync();
                // 保存規格
                await DealwithGoodsSpec(goodsId, input);
                Db.CommitTran();
            }
            catch (Exception e)
            {
                Db.RollbackTran();
                return new ApiResult(e.Message);
            }
            return new ApiResult();
        }
        /// <summary>
        /// 公共的商品規格信息處理
        /// </summary>
        /// <param name="goodsId"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        private async Task DealwithGoodsSpec(int goodsId, GoodsInput input)
        {
            // 保存規格
            if (input.SpecType == SpecTypeEnum.Single.GetValue<int>())
            {
                var specSingle = JsonConvert.DeserializeObject<GoodsSpecInput>(input.SpecSingle);
                input.GoodsSpecInput = specSingle;
                var goodsSpec = input.BuildGoodsSpec(goodsId);
                if (null == goodsSpec)
                {
                    throw new FriendlyException("商品規格實體數據不能為空!");
                }
                await Db.Insertable(goodsSpec).ExecuteReturnIdentityAsync();
            }
            else
            {
                var goodsSpecs = input.BuildGoodsSpecs(goodsId);
                if (null == goodsSpecs || goodsSpecs.Count == 0)
                {
                    throw new FriendlyException("商品規格實體數據集合不能為空!");
                }
                await Db.Insertable(goodsSpecs).ExecuteReturnIdentityAsync();
                var goodsSpecRels = input.BuildGoodsSpecRels(goodsId);
                if (goodsSpecRels.Count == 0 || goodsSpecRels == null)
                {
                    throw new FriendlyException("商品規格實體關系集合數據不能為空!");
                }
                //根據規格值反推規格組id
                var specValues = await Db.Queryable<SpecValue>().Where(d => d.Status).ToListAsync();
                foreach (var item in goodsSpecRels)
                {
                    var specId = specValues.Where(d => d.Status && d.Id == item.SpecValueId).Select(d => d.SpecId);
                    item.SpecId = specId.FirstOrDefault();
                }
                await Db.Insertable(goodsSpecRels).ExecuteReturnIdentityAsync();
            }
        }
        public async Task<ApiResult> ModifyAsync(GoodsModifyInput input)
        {
            var goods = await GetModelAsync(d => d.Id == input.Id);
            if (goods == null) throw new FriendlyException($"此商品{input.Id}沒有查找對應的商品信息");
            try
            {
                Db.BeginTran();
                // 更新商品
                var model = _mapper.Map<Goods>(input);
                var goodsId = await Db.Updateable(model).IgnoreColumns(d => new { d.CreateTime }).ExecuteCommandAsync();
                // 更新規格 
                await Db.Deleteable<GoodsSpec>().Where(d => d.GoodsId == input.Id).ExecuteCommandAsync();
                await Db.Deleteable<GoodsSpecRel>().Where(d => d.GoodsId == input.Id).ExecuteCommandAsync();
                // 保存規格
                await DealwithGoodsSpec(input.Id, input);
                Db.CommitTran();
            }
            catch (Exception e)
            {
                Db.RollbackTran();
                return new ApiResult(e.Message);
            }
            return new ApiResult();
        }

前端添加商品部分代碼:

@{
    ViewData["Title"] = "Modify";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@section css{
    <link href="~/css/site.min.css" rel="stylesheet" asp-append-version="true" />
    <link href="~/css/goods.css" rel="stylesheet" asp-append-version="true" />
}
<div id="container">
    <form class="layui-form form-cus form-back" action="" id="app" lay-filter="column-edit">
        <div class="panel-body">
            <div class="panel-addpic">
                <div class="text">基本屬性</div>
                <div class="form-cur-wall">
                    <label>所屬分類</label>
                    <div class="layui-input-block">
                        <select name="categoryId" id="categoryId" lay-search="">
                            <option value="0">父級</option>
                        </select>
                    </div>
                </div>
                <div class="form-cur-wall">
                    <label>初始銷量</label>
                    <div class="layui-input-block">
                        <input type="text" name="salesInitial" maxlength="100" autocomplete="off" class="layui-input">
                    </div>
                </div>
                <div class="form-cur-wall">
                    <label>商品狀態</label>
                    <div class="layui-input-block">
                        <input type="radio" name="goodsStatus" lay-skin="primary" value="10" title="上架" />
                        <input type="radio" name="goodsStatus" lay-skin="primary" value="20" title="下架" />
                    </div>
                </div>
                <div class="form-cur-wall">
                    <label>運費模板</label>
                    @*目前現調用字典表的模板*@
                    <div class="layui-input-block">
                        <select name="deliveryId" id="deliveryId" lay-verify="required" lay-search="" maxlength="100">
                            @if (ViewBag.Freights != null)
                            {
                                foreach (var item in (List<Config>)ViewBag.Freights)
                                {
                                    <option value="@item.Id">@item.Name</option>
                                }
                            }
                        </select>
                    </div>
                </div>
            </div>
            <div class="layui-row">
                <div class="layui-form-item">
                    <label class="layui-form-label" required>商品名稱</label>
                    <div class="layui-input-block">
                        <input type="text" name="name" maxlength="100" lay-verify="required" lay-verType="tips" autocomplete="off" class="layui-input">
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label required">商品圖片</label>                    
                    <div class="layui-upload">
                        <button type="button" class="layui-btn" id="btnUploadShowImg">上傳圖片</button>
                        <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;margin-left:110px;">
                            預覽圖:
                            <div class="layui-upload-list" id="demo2"></div>
                        </blockquote>
                    </div>
                </div>

                <hr />

                <div class="layui-form-item">
                    <label class="layui-form-label" required>商品規格</label>
                    <div class="layui-input-block">
                        <input type="radio" name="specType" lay-skin="primary" value="10" lay-filter="specType" title="單規格" class="layui-input" checked/>
                        <input type="radio" name="specType" lay-skin="primary" value="20" lay-filter="specType" title="多規格" class="layui-input" />
                    </div>
                </div>
                <div class="goods-spec-many am-form-group">
                    <div class="goods-spec-box am-u-sm-9 am-u-sm-push-2 am-u-end">
                        <!-- 規格屬性 -->
                        <div class="spec-attr"></div>

                        <!-- 添加規格:按鈕 -->
                        <div class="spec-group-button">
                            <button type="button" class="btn-addSpecGroup am-btn">添加規格</button>
                        </div>

                        <!-- 添加規格:表單 -->
                        <div class="spec-group-add">
                            <div class="spec-group-add-item am-form-group">
                                <label class="am-form-label form-require">規格名 </label>
                                <input type="text" class="input-specName tpl-form-input" placeholder="請輸入規格名稱">
                            </div>
                            <div class="spec-group-add-item am-form-group">
                                <label class="am-form-label form-require">規格值 </label>
                                <input type="text" class="input-specValue tpl-form-input" placeholder="請輸入規格值">
                            </div>
                            <div class="spec-group-add-item am-margin-top">
                                <button type="button" class="btn-addSpecName am-btn am-btn-xs
                                            am-btn-secondary">
                                    確定
                                </button>
                                <button type="button" class="btn-cancleAddSpecName am-btn am-btn-xs
                                              am-btn-default">
                                    取消
                                </button>
                            </div>
                        </div>
                        <!-- 商品多規格sku信息 -->
                        <div class="goods-sku am-scrollable-horizontal">
                            <!-- 分割線 -->
                            <div class="goods-spec-line am-margin-top-lg am-margin-bottom-lg"></div>
                            <!-- sku 批量設置 -->
                            <div class="spec-batch am-form-inline">
                                <div class="am-form-group">
                                    <label class="am-form-label">批量設置</label>
                                </div>
                                <div class="am-form-group">
                                    <input type="text" data-type="goods_no" placeholder="商家編碼">
                                </div>
                                <div class="am-form-group">
                                    <input type="number" data-type="goods_price" placeholder="銷售價">
                                </div>
                                <div class="am-form-group">
                                    <input type="number" data-type="line_price" placeholder="划線價">
                                </div>
                                <div class="am-form-group">
                                    <input type="number" data-type="stock_num" placeholder="庫存數量">
                                </div>
                                <div class="am-form-group">
                                    <input type="number" data-type="goods_weight" placeholder="重量">
                                </div>
                                <div class="am-form-group">
                                    <button type="button" class="btn-specBatchBtn am-btn am-btn-sm am-btn-secondary
                                                 am-radius">
                                        確定
                                    </button>
                                </div>
                            </div>
                            <!-- sku table -->
                            <table class="spec-sku-tabel am-table am-table-bordered am-table-centered am-margin-bottom-xs am-text-nowrap"></table>
                        </div>
                    </div>
                </div>

                <div id="sigleSpec">
                    <div class="layui-form-item">
                        <label class="layui-form-label" required>商品價格</label>
                        <div class="layui-input-block">
                            <input type="text" name="goodsPrice" maxlength="30" autocomplete="off" class="layui-input">
                        </div>
                    </div>
                    <div class="layui-form-item">
                        <label class="layui-form-label" required>商品划線價</label>
                        <div class="layui-input-block">
                            <input type="text" name="linePrice" maxlength="40" autocomplete="off" class="layui-input">
                        </div>
                    </div>
                    <div class="layui-form-item">
                        <label class="layui-form-label">商品編碼</label>
                        <div class="layui-input-block">
                            <input type="text" name="goodsNo" maxlength="40" autocomplete="off" class="layui-input">
                        </div>
                    </div>
                    <div class="layui-form-item">
                        <label class="layui-form-label" required>庫存數量</label>
                        <div class="layui-input-block">
                            <input type="number" name="stockNum" maxlength="40" class="layui-input">
                        </div>
                    </div>
                    <div class="layui-form-item">
                        <label class="layui-form-label" required>商品重量(Kg)</label>
                        <div class="layui-input-block">
                            <input type="number" name="goodsWeight" maxlength="40"  class="layui-input">
                        </div>
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label" required>庫存計算</label>
                    <div class="layui-input-block">
                        <input type="radio" name="deductStockType" value="10" lay-skin="primary" title="下單減庫存" />
                        <input type="radio" name="deductStockType" value="20" lay-skin="primary" title="付款減庫存" />
                    </div>
                </div>
            </div>
            <div class="layui-row">
                <div class="layui-form-item layui-form-text">
                    <label class="layui-form-label">商品詳情</label>
                    <div class="layui-input-block">
                        <textarea id="content" name="content" placeholder="請輸入內容" class="layui-textarea"></textarea>
                    </div>
                </div>
            </div>

            <div class="layui-form-item">
                <div class="layui-input-block">
                    <button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">確認保存</button>
                </div>
            </div>
        </div>

    </form>
</div>

@section js{
    <script src="/lib/tinymce/tinymce.min.js"></script>
    <script src="/lib/tinymce/langs/zh_CN.js"></script>
    <script src="~/lib/jquery-3.4.1/jquery-3.4.1.min.js"></script>
    <script src="~/js/goodsSpec.js" asp-append-version="true"></script>
    <script src="~/js/art-template.js" asp-append-version="true"></script>
    <script src="~/js/imgUpload.js" asp-append-version="true"></script>
    <!-- 商品多規格模板 -->
    @await Html.PartialAsync("~/Views/Shared/Templates/tpl_spec_many.cshtml")
    <script>
        tinymce.init({
            selector: '#content',
            auto_focus: true,
            height: 500,
            content_style: "img {max-width:100%;}",
            image_advtab: true,//開啟圖片上傳的高級選項功能
            images_upload_url: '/api/goods/UploadImg',//圖片上傳
            plugins: 'print preview code searchreplace autolink directionality visualblocks visualchars fullscreen image link media codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists textcolor wordcount imagetools contextmenu colorpicker textpattern help ',
            toolbar: 'formatselect styleselect | bold italic forecolor backcolor | link  | alignleft aligncenter alignright alignjustify  | numlist bullist outdent indent  | removeformat'
        });
        layui.use(['form', 'common'], function () {
            var form = layui.form,
                $ = layui.$,
                apiUtil = layui.common;
            // 當前彈出層,防止ID被覆蓋
            var parentIndex = parent.layer.getFrameIndex(window.name);

            apiUtil.BindParentCategory();
            form.render();

            // 注冊商品多規格組件
            var specMany = new GoodsSpec({
                container: '.goods-spec-many'
            });

            //處理單/多規格的顯示問題
            form.on('radio(specType)', function (data) {
                //但規格
                if (data.value == 10) {
                    $("#sigleSpec").show() && $(".goods-spec-many").hide();
                }
                //多規格
                if (data.value == 20) {
                    $("#sigleSpec").hide() && $(".goods-spec-many").show();
                }
                //console.log(data.elem); //得到radio原始DOM對象
            });
          
            //監聽提交
            form.on('submit(saveBtn)', function (data) {
                data.field.content = tinyMCE.editors[0].getContent();
                var specType = $('input[name=specType]:checked').val();
                if (specType == 20) {
                    var specMany2 = JSON.stringify(specMany.getData());
                    console.log("specMany:" + specMany2);
                    var isEmpty = specMany.isEmptySkuList();
                    if (isEmpty == true) {
                        layer.msg('商品規格不能為空');
                        return false;
                    }
                    data.field.specMany = specMany2;
                } else {
                    var specSingle =  {
                        goods_no: data.field.goodsNo,
                        line_price: data.field.linePrice,
                        goods_price: data.field.goodsPrice,
                        goods_weight: data.field.goodsWeight,
                        stock_num: data.field.stockNum,
                    };
                    data.field.specSingle=JSON.stringify(specSingle);
                }                
                data.field.specType = specType;
                data.field.goodsStatus = $('input[name=goodsStatus]:checked').val();
                data.field.deductStockType = $('input[name=deductStockType]:checked').val();
                data.field.imgUrl = $(".div_img input").map(function () { return $(this).attr("value"); }).get().join(',');
                if (data.field.imgUrl == "" || data.field.imgUrl == null) {
                   apiUtil.error("商品圖片至少需要上傳一張!");
                    return false;
                }
                apiUtil.ajax('goods/add', data.field, "application/json", "post", function (res) {
                    apiUtil.success(res.msg);
                    parent.layer.close(parentIndex);
                });
                return false;
            });           
        });

    </script>
}

這里只貼部分代碼吧,更多的細節可以直接去看源碼。另外關於商城的設計其實寫個系列也不過分,下次抽時間具體寫篇文章介紹下商品的多規格怎么設計好一點。

源碼地址:https://gitee.com/shenniu_code_group/shen-nius.-modularity

喜歡交流的人進微信群

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM