系统操作日志表单形式构建

1.概述

     所谓操作日志,就是某人对指定模块的指定对象进行操作的记录,在某种情况下,可能会有显示本次操作对哪些数据字段进行啦了动,或者是操作前后该模型的数据比对情况。针对于这类需求,想要查看某条操作记录具体改动项信息的时候,对于前端来讲,他不需要知道这个对象的具体类型及各个字段的意义的汉字描述,他们只需要循环遍历,将所有的数据拼到一个div容器里即可。后台该如何去设计才能做到最简化的操作那?第一种情况可以用枚举的形式,来标记每种模型的类型,在每次记录日志的时候,可以将当前枚举也记录进去(数据库/nosql),这样的话,在查看每种记录变动的详情时,就可以根据每种类型封装不同的拼接数据的策略,最终以统一的格式返回给前端。但是,这种操作起来并不是很理想,没实现一种模块的操作都要实现对应的表单项拼接策略,显然以后维护起来并不是十分的完美。那么,能不能通过反射的形式来根绝具体的模型名称动态的获取模型类型,并根据具体的类型和json数据来形成对象,从而完成表单项的构建那??答案是:可以的(c#中可以根据Type type = Type.GetType(FullTypeName);类实现)。下面我们就先实现一下获取当前操作模型具体操作操作记录。

2.需求分析及实现

    1.前端需要展示成这样:

       2.后台代码设置

     

 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 
 8 namespace ConsoleApp1.OpearorLog.Entity
 9 {
10     public class ColumnRenark : Attribute
11     {
12         /// <summary>
13         /// 字段名称
14         /// </summary>
15         public string ColumnName { get; set; }
16         /// <summary>
17         /// 字段类型
18         /// </summary>
19         public ColumnType ColumnType { get; set; }
20 
21 
22         public ColumnRenark() { }
23     }
24     public enum ColumnType
25     {
26         [Description("基础类型(int/string...)")]
27         Basic = 0,
28         [Description("类类型")]
29         Class = 1,
30         [Description("字典类型")]
31         Dic = 2,
32         [Description("列表类型")]
33         Lst = 3,
34 
35 
36     }
37 }
View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1.OpearorLog.Entity
{
    /// <summary>
    ///行记录
    /// </summary>
    public class RowRecord
    {
        /// <summary>
        /// 字段语义
        /// </summary>
        public string Key { get; set; }
        /// <summary>
        /// 字段对应值
        /// </summary>
        public string Value { get; set; }
        /// <summary>
        /// 所属层级
        /// </summary>
        public int Lev { get; set; }
        /// <summary>
        /// 包含的子项
        /// </summary>
        public List<List<RowRecord>> Child { get; set; }

        public RowRecord()
        {
            Child = new List<List<RowRecord>>();
        }

    }
}
View Code
  1 using Newtonsoft.Json;
  2 using System;
  3 using System.Collections.Generic;
  4 using System.Linq;
  5 using System.Runtime.InteropServices;
  6 using System.Text;
  7 using System.Threading.Tasks;
  8 
  9 namespace ConsoleApp1
 10 {
 11   public  class OperatorLogContext
 12     {
 13         #region attr
 14         private List<RowRecord> RowRecords { get; set; }
 15         private object Obj { get; set; }
 16         public string FullTypeName { get; set; }
 17         public string JsonStr { get; set; }
 18         #endregion
 19 
 20         public OperatorLogContext(string fullTypeName,string jsonStr)
 21         {
 22             FullTypeName = fullTypeName;
 23             JsonStr = jsonStr;
 24             RowRecords = new List<RowRecord>();
 25             Type type = Type.GetType(FullTypeName);
 26             Obj = JsonConvert.DeserializeObject(JsonStr,type);
 27         }
 28         public OperatorLogContext()
 29         {
 30             Type type = Type.GetType(FullTypeName);
 31             Obj = JsonConvert.DeserializeObject(JsonStr, type);
 32         }
 33         /// <summary>
 34         /// 构建表单项
 35         /// </summary>
 36         /// <returns></returns>
 37         public List<RowRecord> BuildForm()
 38         {
 39             return Build(Obj);
 40         }
 41         #region private
 42         private List<RowRecord> Build(object obj, RowRecord parentRow = null, List<RowRecord> childRow = null, int lev = 0)
 43         {
 44             //1.当前类型
 45             Type currentType = obj.GetType();
 46             //2.获取当下模型的所有属性字段
 47             var props = currentType.GetProperties();
 48             foreach (var prop in props)
 49             {
 50                 RowRecord rowRecord = new RowRecord();
 51                 rowRecord.Lev = lev;   //设置当前树形级别
 52                 //3.获取当下属性字段下的所有自定义属性
 53                 var attr = prop.CustomAttributes.FirstOrDefault(o => o.AttributeType == typeof(ColumnRenark));
 54                 if (attr == null)
 55                 {
 56                     continue;
 57                 }
 58                 else
 59                 {
 60                     foreach (var named in attr.NamedArguments)
 61                     {
 62                         if (named.MemberName == "ColumnName")
 63                         {
 64                             rowRecord.Key = named.TypedValue.Value.ToString();
 65                         }
 66                         else if (named.MemberName == "ColumnType")
 67                         {
 68                             ColumnType columnType = (ColumnType)Enum.Parse(typeof(ColumnType), named.TypedValue.Value.ToString());
 69                             switch (columnType)
 70                             {
 71                                 case ColumnType.Basic:
 72                                     rowRecord.Value = prop.GetValue(obj).ToString();
 73                                     break;
 74                                 case ColumnType.Class:
 75                                     Build(prop.GetValue(obj), rowRecord, new List<RowRecord>());
 76                                     break;
 77                                 case ColumnType.Lst:
 78                                     var currentLst = (IEnumerable<object>)prop.GetValue(obj);
 79 
 80                                     foreach (var opt in currentLst)
 81                                     {
 82 
 83                                         Build(opt, rowRecord, new List<RowRecord>());
 84                                     }
 85                                     break;
 86                             }
 87                         }
 88                     }
 89                 }
 90 
 91                 if (parentRow != null)
 92                 {
 93                     rowRecord.Lev = parentRow.Lev + 1;
 94                     childRow.Add(rowRecord);
 95                 }
 96                 else
 97                 {
 98                     RowRecords.Add(rowRecord);
 99                 }
100             }
101             if (childRow != null)
102             {
103                 parentRow.Child.Add(childRow);
104             }
105             return RowRecords;
106         }
107         #endregion
108 
109     }
110 }
View Code
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            User user = new User();
            user.Age = 20;
            user.Name = "lsh";
            user.Book = new Book()
            {
                Name = "c#从入门指南",
                Desc = "书籍描述"
            };
            user.Hobby = new List<Hobby>() {
                new Hobby() { Name = "读书", Rate = "89%" },
                new Hobby() { Name = "旅游", Rate = "33%" }
            };
            string json = JsonConvert.SerializeObject(user);
            var lst = new OperatorLogContext("ConsoleApp1.User", json).BuildForm();
            Console.ReadKey();
        }
    }
    public class User
    {
        [ColumnRenark(ColumnName = "姓名", ColumnType = ColumnType.Basic)]
        public string Name { get; set; }
        [ColumnRenark(ColumnName = "年龄", ColumnType = ColumnType.Basic)]
        public int Age { get; set; }
        [ColumnRenark(ColumnName = "书籍", ColumnType = ColumnType.Class)]
        public Book Book { get; set; }
        [ColumnRenark(ColumnName = "爱好", ColumnType = ColumnType.Lst)]
        public List<Hobby> Hobby { get; set; }

    }
    public class Hobby
    {
        [ColumnRenark(ColumnName = "爱好名", ColumnType = ColumnType.Basic)]
        public string Name { get; set; }
        [ColumnRenark(ColumnName = "比率", ColumnType = ColumnType.Basic)]
        public string Rate { get; set; }
    }
    /// <summary>
    /// 行元素
    /// </summary>
    public class RowRecord
    {
        public string Key { get; set; }
        public string Value { get; set; }
        public int Lev { get; set; }
        public List<List<RowRecord>> Child { get; set; }

        public RowRecord()
        {
            Child = new List<List<RowRecord>>();
        }
    }
    public class Book
    {
        [ColumnRenark(ColumnName = "书名", ColumnType = ColumnType.Basic)]
        public string Name { get; set; }
        [ColumnRenark(ColumnName = "书描述", ColumnType = ColumnType.Basic)]
        public string Desc { get; set; }
    }
    /// <summary>
    /// 字段标记属性
    /// </summary>
    public class ColumnRenark : Attribute
    {
        /// <summary>
        /// 字段名称
        /// </summary>
        public string ColumnName { get; set; }
        /// <summary>
        /// 字段类型
        /// </summary>
        public ColumnType ColumnType { get; set; }


        public ColumnRenark() { }
    }

    public enum ColumnType
    {
        [Description("基础类型(int/string...)")]
        Basic = 0,
        [Description("类类型")]
        Class = 1,
        [Description("字典类型")]
        Dic = 2,
        [Description("列表类型")]
        Lst = 3,


    }
}
View Code

3.测试结果

   

posted @ 2018-12-02 19:42  深海里的一条鱼  阅读(529)  评论(0编辑  收藏  举报