ASP.NET MVC4+BootStrap 实战(十)

年过完了,也该收心了。想想过年这几天都是每天睡到12:00,实在是腐化。大家都沉浸在抢红包的喜悦之中。

技术分享

不说了,今天我们主要看一下新闻链接管理界面。先上图,无图无真相。

技术分享

上半部分主要是对已经添加的外链接进行修改删除,设置优先级,下半部分是新增外链接网站。

首先我们先看一下上半部分。

<div id="div_newsManage" class="panel panel-primary" ng-app="newsLinkManageModule" ng-controller="newsLinkManageController">
    <div class="panel-heading">
        <h3 class="panel-title">
            <img class="img-panel-title" src="~/Images/Base/newslink.png" />
            <b>新闻链接管理</b>
        </h3>
    </div>
    <div class="panel-body">
        <fieldset>
            <legend>
                <h5><b>外链接管理</b></h5>
            </legend>
            <div class="row">
                <div class="col-md-1">
                    <input type="checkbox" ng-model="IsSelectAll" />
                </div>
                <label class="col-md-5" style="color:#333333">网站名称</label>
                <label class="col-md-2" style="color:#333333">TOP(X)</label>
                <label class="col-md-2" style="color:#333333">操作</label>
                <label class="col-md-2" style="color:#333333">优先级</label>
            </div>
            <div class="line-seperate-style-main"></div>
            <div ng-repeat="website in WebSites" class="a-list">
                <div class="row" style="line-height:40px">
                    <div class="col-md-1">
                        <input class="chklist-vertical-align" type="checkbox" ng-model="website.IsChecked" />
                    </div>
                    <div class="col-md-5">
                        <a href="{{website.WebSiteURL}}">{{website.WebSiteName}}</a>
                    </div>
                    <div class="col-md-2">
                        <select class="form-control" ng-model="website.TopNewsCount" ng-options="number for number in numbers">
                            @*<option ng-repeat="num in numbers" label="{{num}}" value="{{num}}"></option>*@
                        </select>
                    </div>
                    <div class="col-md-2">
                        <span style="cursor: pointer;" class="glyphicon glyphicon-pencil span-grid"></span>
                        <span ng-click="newslinkdeleteSingle(website.TransactionNumber)" style="cursor:pointer;margin-left:5px;" class="glyphicon glyphicon-trash span-grid"></span>
                    </div>
                    <div class="col-md-2">
                        <span style="cursor:pointer;" class="glyphicon glyphicon-arrow-up span-grid"></span>
                        <span style="cursor: pointer; margin-left: 5px;" class="glyphicon glyphicon-arrow-down span-grid"></span>
                    </div>
                </div>
                <div class="line-seperate-style"></div>
            </div>
            <input type="button" value="移除" ng-click="newslinkdelete()" style="margin-top:10px" class="btn btn-danger" />
        </fieldset>

还是bootStrap布局,将div分成1,5,2,2,2比例的五等份。我们通过ng-repeat生成多行div。在这里需要注意的是这里的select标签的ng-options,在这里如果不使用ng-options的话,ng-model是无法选中的。OK,我们看到头部有一个复选框,那个复选框是用来全选和反选的。OK,我们看一下js代码

var appModule = angular.module(‘newsLinkManageModule‘, []);
appModule.controller("newsLinkManageController", function ($scope, $http, $filter) {
    initData();

    $scope.AddedWebSites = [];

    $scope.numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    $scope.IsSelectAll = false;

在页面加载以后,我们首先会调用initData方法。

function initData() {
    $http.get("/NewsManage/NewsLinkList").success(function (data) {
         $scope.WebSites = data;
    });
};

其实就是调用一个后台action,得到WebSites。

[HttpGet]
[OutputCache(Duration = 60)]
public JsonResult NewsLinkList()
{
     var newsEntityList = NewsMngBiz.GetInstance().GetNewsLinkList();
     if (newsEntityList == null) return null;

     return Json(newsEntityList, JsonRequestBehavior.AllowGet);
}

在这里,实体的定义如下

public class NewsLinkEntity
    {
        public int TransactionNumber { get; set; }
        public string WebSiteName { get; set; }
        public string WebSiteURL { get; set; }
        public int TopNewsCount { get; set; }
        public int Priority { get; set; }
    }

就是将这样一个实体list以json格式返回到客户端。全选和全不选的js代码如下

$scope.$watch("IsSelectAll", setCheckState);
function setCheckState(newValue, oldValue) {
     angular.forEach($scope.WebSites, function (obj, key) {
           obj.IsChecked = newValue;
     });
}

我们通过监控IsSelectAll的值来实时设置列表中的选中状态。

接着我们看一下这里移除按钮的实现。

var linkIDs = [];
$scope.newslinkdelete = function () {
     linkIDs = [];
     angular.forEach(
          $filter(‘filter‘)($scope.WebSites, { IsChecked: true }),
                function (v) {
                    linkIDs.push(v.TransactionNumber);
                }
     );

     if (linkIDs.length == 0) {
          alert("请选择要删除的数据!");
          return;
     }

     if (confirm("您确定要删除吗?")) {
          var param = { requestJson: JSON.stringify({ linkIDs: linkIDs }) };
          newsLinkDelete(param);
     }
};

在这里先拿到选中的TransactionNumber,然后发送到服务端进行处理。

function newsLinkDelete(param) {
      $http({
                method: "Delete",
                url: "/NewsManage/DeleteNewsLink",
                headers: { ‘Content-Type‘: ‘application/x-www-form-urlencoded‘ },
                data: $.param(param)
            }).success(function (data, status, headers, config) {
                alert(data.msg);
                if (data.suc == 1) {
                    initData();
                }
            }).error(function (data, status, headers, config) {
                alert(status);
      });
}

我们看一下服务端的处理

[HttpDelete]
public JsonResult DeleteNewsLink()
{
     string requestJson = Request["requestJson"];
     string[] linkIDArray = JsonBuilder.BuildStringArray(requestJson, "linkIDs");
     int suc = NewsMngBiz.GetInstance().DeleteNewsLinks(linkIDArray);

     if (suc >= 0)
     {
         return GetJsonMessage("CM_002", JsonMsgType.SUCCESS);
     }

     return GetJsonMessage("CM_005");
}

DAL层调用如下的脚本进行处理

DECLARE @NewsLinkIDTable TABLE
(
    ID INT IDENTITY(1,1),
    TransactionNumber INT NOT NULL
)

INSERT INTO @NewsLinkIDTable
(
    TransactionNumber
)
SELECT short_str
FROM dbo.F_SQLSERVER_SPLIT(@NewsLinkIDs,‘,‘)

DELETE A FROM dbo.InformationNewsLink A
WHERE EXISTS(
    SELECT TOP 1 1
    FROM @NewsLinkIDTable B
    WHERE B.TransactionNumber = A.TransactionNumber
)

OK,接下来我们看一下下半部分。下半部分,当用户点击新增按钮的时候,会动态增加一个用于添加链接网站的div。

技术分享

看一下代码

<fieldset style="margin-top:20px">
            <legend>
                <h5><b>外链接新增</b></h5>
            </legend>
            <div class="row">
                <label class="col-md-1">序号</label>
                <label class="col-md-1">勾选</label>
                <label class="col-md-4">网站名称</label>
                <label class="col-md-6">网站URL</label>
            </div>
            <div class="line-seperate-style-main"></div>
            <div class="row" style="line-height:40px">
                <div class="col-md-1">
                    <div class="div-circal-list">1</div>
                </div>
                <div class="col-md-1">
                    <input disabled type="checkbox" ng-model="IsChecked" class="chklist-vertical-align" />
                </div>
                <div class="col-md-4">
                    <input type="text" ng-model="WebSiteName" maxlength="30" style="width:100%" class="form-control" />
                </div>
                <div class="col-md-6">
                    <input type="text" placeholder="请以http或者https开头" maxlength="200" ng-model="WebSiteURL" style="width:100%" class="form-control" />
                </div>
            </div>
            <div ng-repeat="website in AddedWebSites">
                <div class="row" style="line-height:40px">
                    <div class="col-md-1">
                        <div class="div-circal-list">{{$index + 2}}</div>
                        @*<img src="~/Images/orderedList{{$index + 1}}.png" />*@
                    </div>
                    <div class="col-md-1">
                        <input type="hidden" value="{{$index + 1}}" ng-model="website.Index" />
                        <input type="checkbox" ng-model="website.IsChecked" class="chklist-vertical-align" />
                    </div>
                    <div class="col-md-4">
                        <input type="text" ng-model="website.LinkName" maxlength="30" style="width:100%" class="form-control" />
                    </div>
                    <div class="col-md-6">
                        <input type="text" placeholder="请以http或者https开头" maxlength="200" ng-model="website.URL" style="width:100%" class="form-control" />
                    </div>
                </div>
            </div>
            <div style="margin-top:20px">
                <input type="button" class="btn btn-primary" value="新增" ng-click="addnewlink()" />
                <input type="button" class="btn btn-info" value="保存" />
                <input type="button" class="btn btn-danger" value="移除" ng-click="removelink()" />
            </div>
        </fieldset>

这个界面上第一个复选框是disabled,因为我们始终要保持一个表单在。在这里我们表单的新增其实就是通过更新model实现的。当我们给数组中新增一个对象时,界面就会自动新增一行。我们看一下实现

$scope.addnewlink = function () {
      if ($scope.AddedWebSites.length >= 9) {
           alert("您一次最多只能添加10个网站链接!");
           return;
      }

      $scope.AddedWebSites.push({ URL: "", LinkName: "" });
};

很简单,前面的圆圈序列号是由如下div实现的。

<div class="div-circal-list">{{$index + 2}}</div>

css代码很简单。

.div-circal-list {
    width:30px;
    height:30px;
    border-radius:50%;
    background-color:#428bca;
    text-align:center;
    line-height:30px;
    color:white;
}

我们再看一下移除。

$scope.removelink = function () {
      var selectedIDs = [];
      angular.forEach($scope.AddedWebSites, function (obj, key) {
           if (obj.IsChecked) {
                 selectedIDs.push(key);
           }
      });

      var num = 0;
      angular.forEach(selectedIDs, function (value, key) {
          $scope.AddedWebSites.splice(value - num, 1);
                ++num;
      });
};

在这里我们根据数组的下标进行删除。因为每删除一行,会重新生成一个$index,所以我们必须先把选中的index放到一个数组中,然后循环从列表中删除。因为每删除一个index就会减1,所以我们就每次value-num。OK,本篇到此结束。

最后我们看一下上节遗留的Excel导出功能,其实就是将form提交到如下action

[OutputCache(Duration = 60, NoStore = true)]
        [HttpPost]
        public FileResult Export(FormCollection fc)
        {
            string userID = fc["searchUserID"];
            string userName = fc["searchUserName"];
            string userSex = fc["searchUserSex"];
            string birthDayStart = fc["searchStartDate"];
            string birthDayEnd = fc["searchEndDate"];

            string pageIndex = fc["hfdPageIndex"];
            string pageSize = fc["hfdPageSize"];

            UserSearchRequest userSearchRequest = new UserSearchRequest()
            {
                UserID = userID,
                UserName = userName,
                UserSex = userSex,
                StartDate = string.IsNullOrEmpty(birthDayStart) ? null : (DateTime?)DateTime.Parse(birthDayStart),
                EndDate = string.IsNullOrEmpty(birthDayEnd) ? null : (DateTime?)DateTime.Parse(birthDayEnd),
                PageIndex = int.Parse(pageIndex),
                PageSize = int.Parse(pageSize)
            };

            byte[] fileBytes = UserInfoBiz.GetInstance().GetExportFileBytes(userSearchRequest);
            if (fileBytes == null) return File("~/NoData.xls", "application/ms-excel");

            return File(fileBytes, "application/ms-excel", string.Concat("UserInfo", Guid.NewGuid().ToString(), ".xls"));
        }

在这里我们通过NPOI组件返回个byte数组,通过Biz层调用得到数组,在action中输出到客户端。

public static byte[] ExportExcel(DataTable dt, string title)
        {
            HSSFWorkbook workbooks = new HSSFWorkbook();
            HSSFSheet worksheet = (HSSFSheet)workbooks.CreateSheet(title);

            if (dt.Rows.Count == 0)
            {
                return null;
            }
            //标题
            int titleCell = dt.Columns.Count;

            worksheet.AddMergedRegion(new Region(0, 0, 0, titleCell - 1));//合并单元格,第0行0列开始到第0行titleCell-1列
            HSSFCell cell = (HSSFCell)worksheet.CreateRow(0).CreateCell(0);//创建单元格
            cell.SetCellValue(title);
            //设置样式
            HSSFCellStyle style = (HSSFCellStyle)workbooks.CreateCellStyle();
            HSSFFont font = (HSSFFont)workbooks.CreateFont();
            font.Boldweight = (short)FontBoldWeight.BOLD;//粗体
            font.Color = HSSFColor.RED.index;//字体颜色 red
            font.FontHeightInPoints = 18;//字体大小
            style.SetFont(font);
            style.Alignment = HorizontalAlignment.CENTER;
            cell.CellStyle = style;

            //设置样式
            HSSFCellStyle style1 = (HSSFCellStyle)workbooks.CreateCellStyle();
            HSSFFont font1 = (HSSFFont)workbooks.CreateFont();
            font1.Boldweight = (short)FontBoldWeight.BOLD;//粗体

            font1.FontHeightInPoints = 12;//字体大小
            style1.SetFont(font1);
            style1.WrapText = false;
            style1.Alignment = HorizontalAlignment.LEFT;
            HSSFRow row1 = (HSSFRow)worksheet.CreateRow(1);
            //写入字段
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                HSSFCell cell1 = (HSSFCell)row1.CreateCell(i);//创建单元格
                cell1.SetCellValue(dt.Columns[i].ColumnName);
                cell1.CellStyle = style1;
            }

            for (int r = 0; r < dt.Rows.Count; r++)
            {
                HSSFRow rowr = (HSSFRow)worksheet.CreateRow(r + 2);
                for (int c = 0; c < dt.Columns.Count; c++)
                {
                    HSSFCell cell2 = (HSSFCell)rowr.CreateCell(c);//创建单元格
                    var aa = dt.Columns[c].DataType.ToString();
                    var cellvalue = dt.Rows[r][dt.Columns[c].ColumnName].ToString();
                    #region
                    switch (dt.Columns[c].DataType.ToString())
                    {
                        case "System.String"://字符串类型
                            cell2.SetCellValue(cellvalue);
                            break;
                        case "System.Nullable`1[System.DateTime]"://日期类型
                        case "System.DateTime":
                            DateTime dateV;
                            DateTime.TryParse(cellvalue, out dateV);
                            cell2.SetCellValue(cellvalue);
                            break;
                        case "System.Boolean"://布尔型
                            bool boolV = false;
                            bool.TryParse(cellvalue, out boolV);
                            cell2.SetCellValue(cellvalue);
                            break;
                        case "System.Int16"://整型
                        case "System.Int32":
                        case "System.Int64":
                        case "System.Byte":
                            int intV = 0;
                            int.TryParse(cellvalue, out intV);
                            cell2.SetCellValue(cellvalue);
                            break;
                        case "System.Decimal"://浮点型
                        case "System.Double":
                            double doubV = 0;
                            double.TryParse(cellvalue, out doubV);
                            cell2.SetCellValue(cellvalue);
                            break;
                        case "System.DBNull"://空值处理
                            cell2.SetCellValue("");
                            break;
                        default:
                            cell2.SetCellValue("");
                            break;
                    }

                    #endregion
                }
            }

            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    workbooks.Write(ms);
                    ms.Flush();
                    ms.Position = 0;
                    worksheet.Dispose();
                    workbooks.Dispose();

                    byte[] data = ms.ToArray();
                    GC.Collect();
                    return data;
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteExceptionLog(MethodBase.GetCurrentMethod(),ex);
                return null;
            }
        }

Ok,我们看一下效果

技术分享

打开Excel,结果如下,样式没有细调。

技术分享

最后祝大家在新的一年里一顺百顺事事顺,欢天喜地迎新年。

本文出自 “技术创造价值” 博客,请务必保留此出处http://leelei.blog.51cto.com/856755/1615085

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。