From c32275f697e1541694836c47e1682e3291673dbc Mon Sep 17 00:00:00 2001
From: liaoxujun@qq.com <liaoxujun@qq.com>
Date: 星期一, 19 二月 2024 12:33:54 +0800
Subject: [PATCH] 完成系统设置页面,创建设置字典

---
 utils/utils.csproj                                               |    9 
 cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionarySearcher.cs |   31 +
 .gitignore                                                       |   13 
 cy_scdz/Areas/Setting/Views/Setting/index.cshtml                 |  169 +++++++
 cy_scdz/Areas/dictionary/Controllers/DictionaryController.cs     |  219 +++++++++
 cy_scdz.ViewModel/Setting/SettingListVM.cs                       |   12 
 cy_scdz/Areas/dictionary/Views/Dictionary/Delete.cshtml          |   18 
 cy_scdz/Areas/dictionary/Views/Dictionary/Import.cshtml          |   14 
 cy_scdz/Areas/dictionary/Views/Dictionary/BatchEdit.cshtml       |   14 
 cy_scdz/Areas/dictionary/Views/Dictionary/Details.cshtml         |   15 
 utils/utilsFun.cs                                                |   27 +
 cy_scdz.Model/Set/Dictionary.cs                                  |   52 ++
 cy_scdz.ViewModel/cy_scdz.ViewModel.csproj                       |    3 
 cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryImportVM.cs |   39 +
 cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryVM.cs       |   86 +++
 cy_scdz/appsettings.json                                         |    4 
 cy_scdz/Areas/dictionary/Views/Dictionary/Create.cshtml          |   16 
 cy_scdz/cy_scdz.csproj                                           |    3 
 cy_scdz.Test/Properties/launchSettings.json                      |   12 
 cy_scdz/Views/Login/Login.cshtml                                 |    2 
 cy_scdz.ViewModel/Setting/SettingVm.cs                           |  108 ++++
 cy_scdz/Areas/dictionary/Views/Dictionary/Edit.cshtml            |   17 
 cy_scdz.Test/DictionaryControllerTest.cs                         |  273 +++++++++++
 cy_scdz/Areas/dictionary/Views/Dictionary/BatchDelete.cshtml     |   12 
 cy_scdz/Areas/Setting/Controllers/SettingController.cs           |   65 ++
 cy_scdz.DataAccess/DataContext.cs                                |    3 
 cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryBatchVM.cs  |   35 +
 cy_scdz.sln                                                      |   57 +-
 cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryListVM.cs   |   71 ++
 cy_scdz.Model/cy_scdz.Model.csproj                               |    2 
 cy_scdz/Areas/dictionary/Views/Dictionary/Index.cshtml           |   12 
 cy_scdz/cy_scdz.csproj.user                                      |    9 
 32 files changed, 1,391 insertions(+), 31 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ca6f8ad
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+.vs/
+cy_scdz.DataAccess/bin/
+cy_scdz.DataAccess/obj/
+cy_scdz.Model/bin/
+cy_scdz.Model/obj/
+cy_scdz.Test/obj/
+cy_scdz.ViewModel/bin/
+cy_scdz.ViewModel/obj/
+cy_scdz/bin/
+cy_scdz/obj/Debug/
+utils/obj/
+cy_scdz/obj/
+utils/bin/
diff --git a/cy_scdz.DataAccess/DataContext.cs b/cy_scdz.DataAccess/DataContext.cs
index 293449e..6c9c28a 100644
--- a/cy_scdz.DataAccess/DataContext.cs
+++ b/cy_scdz.DataAccess/DataContext.cs
@@ -10,6 +10,7 @@
 using WalkingTec.Mvvm.Core.Extensions;
 using WalkingTec.Mvvm.Core.Models;
 using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using cy_scdz.Model.Set;
 
 namespace cy_scdz.DataAccess
 {
@@ -18,7 +19,7 @@
         public DbSet<FrameworkUser> FrameworkUsers { get; set; }
         public DbSet<FrameworkUserRole> FrameworkUserRoles { get; set; }
         public DbSet<FrameworkUserGroup> FrameworkUserGroups { get; set; }
-
+        public DbSet<Dictionary> Dictionary { get; set; }
         public DataContext(CS cs)
              : base(cs)
         {
diff --git a/cy_scdz.Model/Set/Dictionary.cs b/cy_scdz.Model/Set/Dictionary.cs
new file mode 100644
index 0000000..14a7cf6
--- /dev/null
+++ b/cy_scdz.Model/Set/Dictionary.cs
@@ -0,0 +1,52 @@
+锘縰sing Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using WalkingTec.Mvvm.Core;
+
+namespace cy_scdz.Model.Set
+{
+    [Display(Name = "璁剧疆瀛楀吀")]
+    public class Dictionary: TreePoco<Dictionary>
+    {
+        /// <summary>
+        /// 鍚嶇О
+        /// </summary>
+        [Display(Name = "鍚嶇О")]
+        [StringLength(50, ErrorMessage = "Validate.{0}stringmax{1}")]
+        [Comment("鍚嶇О")]
+        [Required]
+        public string Name { get; set; }
+        /// <summary>
+        /// 鍚嶇О
+        /// </summary>
+        [Display(Name = "Key")]       
+        [Comment("Key")]
+        [Required]
+        public string Key { get; set; }
+
+
+        /// <summary>
+        /// 鍊�
+        /// </summary>
+        [Display(Name = "鍊�")]
+        [StringLength(200, ErrorMessage = "Validate.{0}stringmax{1}")]
+        [Comment("鍊�")]   
+        public string Value { get; set; }
+
+
+        /// <summary>
+        /// 鏄惁鏈夋晥
+        /// </summary>
+        [Display(Name = "鏄惁鏈夋晥")]
+        [Comment("鏄惁鏈夋晥")]
+        public bool IsEn { get; set; }= true;
+        /// <summary>
+        /// 瀛愯妭鐐�
+        /// </summary>
+        public virtual ICollection<Dictionary> Children { get; set; } = new List<Dictionary>();
+    }
+}
diff --git a/cy_scdz.Model/cy_scdz.Model.csproj b/cy_scdz.Model/cy_scdz.Model.csproj
index d68f411..bf17676 100644
--- a/cy_scdz.Model/cy_scdz.Model.csproj
+++ b/cy_scdz.Model/cy_scdz.Model.csproj
@@ -9,6 +9,6 @@
 
   <ItemGroup>
     <PackageReference Include="WalkingTec.Mvvm.Core" Version="6.5.6" />
-  </ItemGroup >
+  </ItemGroup>
 </Project>
 
diff --git a/cy_scdz.Test/DictionaryControllerTest.cs b/cy_scdz.Test/DictionaryControllerTest.cs
new file mode 100644
index 0000000..ab2fce5
--- /dev/null
+++ b/cy_scdz.Test/DictionaryControllerTest.cs
@@ -0,0 +1,273 @@
+锘縰sing Microsoft.AspNetCore.Mvc;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using WalkingTec.Mvvm.Core;
+using cy_scdz.Controllers;
+using cy_scdz.ViewModel.dictionary.DictionaryVMs;
+using cy_scdz.Model.Set;
+using cy_scdz.DataAccess;
+
+
+namespace cy_scdz.Test
+{
+    [TestClass]
+    public class DictionaryControllerTest
+    {
+        private SetingController _controller;
+        private string _seed;
+
+        public DictionaryControllerTest()
+        {
+            _seed = Guid.NewGuid().ToString();
+            _controller = MockController.CreateController<SetingController>(new DataContext(_seed, DBTypeEnum.Memory), "user");
+        }
+
+        [TestMethod]
+        public void SearchTest()
+        {
+            PartialViewResult rv = (PartialViewResult)_controller.Index();
+            Assert.IsInstanceOfType(rv.Model, typeof(IBasePagedListVM<TopBasePoco, BaseSearcher>));
+            string rv2 = _controller.Search((rv.Model as DictionaryListVM).Searcher);
+            Assert.IsTrue(rv2.Contains("\"Code\":200"));
+        }
+
+        [TestMethod]
+        public void CreateTest()
+        {
+            PartialViewResult rv = (PartialViewResult)_controller.Create();
+            Assert.IsInstanceOfType(rv.Model, typeof(DictionaryVM));
+
+            DictionaryVM vm = rv.Model as DictionaryVM;
+            Dictionary v = new Dictionary();
+			
+            v.Name = "b";
+            v.Key = "xMrl9";
+            v.Value = "EywYKwZjnxDmyQVwVYph9bYpAudrE9fseXiODivU84zBNHxqZv7ztyImrm4bTwJHFxtTfnJfwnwkWtP9LQeWCjwoO0sKPFEz3KD5Ni6QzJViWgOZjbDtvCCAOM3Md";
+            v.IsEn = true;
+            v.ParentId = AddDictionary();
+            vm.Entity = v;
+            _controller.Create(vm);
+
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+                var data = context.Set<Dictionary>().Find(v.ID);
+				
+                Assert.AreEqual(data.Name, "b");
+                Assert.AreEqual(data.Key, "xMrl9");
+                Assert.AreEqual(data.Value, "EywYKwZjnxDmyQVwVYph9bYpAudrE9fseXiODivU84zBNHxqZv7ztyImrm4bTwJHFxtTfnJfwnwkWtP9LQeWCjwoO0sKPFEz3KD5Ni6QzJViWgOZjbDtvCCAOM3Md");
+                Assert.AreEqual(data.IsEn, true);
+            }
+
+        }
+
+        [TestMethod]
+        public void EditTest()
+        {
+            Dictionary v = new Dictionary();
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+       			
+                v.Name = "b";
+                v.Key = "xMrl9";
+                v.Value = "EywYKwZjnxDmyQVwVYph9bYpAudrE9fseXiODivU84zBNHxqZv7ztyImrm4bTwJHFxtTfnJfwnwkWtP9LQeWCjwoO0sKPFEz3KD5Ni6QzJViWgOZjbDtvCCAOM3Md";
+                v.IsEn = true;
+                v.ParentId = AddDictionary();
+                context.Set<Dictionary>().Add(v);
+                context.SaveChanges();
+            }
+
+            PartialViewResult rv = (PartialViewResult)_controller.Edit(v.ID.ToString());
+            Assert.IsInstanceOfType(rv.Model, typeof(DictionaryVM));
+
+            DictionaryVM vm = rv.Model as DictionaryVM;
+            vm.Wtm.DC = new DataContext(_seed, DBTypeEnum.Memory);
+            v = new Dictionary();
+            v.ID = vm.Entity.ID;
+       		
+            v.Name = "QsFRU0Hrpj0paqSATzzz7bBy7XUEiXX3n2ochswiODO";
+            v.Key = "xpZrS27u53";
+            v.Value = "guWhKhfl1PVouMDiYmcgkvledon5IsxDS1OmRCXsI7DN5NMIKex21a9FdhlIzkPnMebXpH5Lvb2kOk0ADso6eGecpBYjRnFQcZopebKAQp1q7XghV67Mbqe7Uy";
+            v.IsEn = false;
+            vm.Entity = v;
+            vm.FC = new Dictionary<string, object>();
+			
+            vm.FC.Add("Entity.Name", "");
+            vm.FC.Add("Entity.Key", "");
+            vm.FC.Add("Entity.Value", "");
+            vm.FC.Add("Entity.IsEn", "");
+            vm.FC.Add("Entity.ParentId", "");
+            _controller.Edit(vm);
+
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+                var data = context.Set<Dictionary>().Find(v.ID);
+ 				
+                Assert.AreEqual(data.Name, "QsFRU0Hrpj0paqSATzzz7bBy7XUEiXX3n2ochswiODO");
+                Assert.AreEqual(data.Key, "xpZrS27u53");
+                Assert.AreEqual(data.Value, "guWhKhfl1PVouMDiYmcgkvledon5IsxDS1OmRCXsI7DN5NMIKex21a9FdhlIzkPnMebXpH5Lvb2kOk0ADso6eGecpBYjRnFQcZopebKAQp1q7XghV67Mbqe7Uy");
+                Assert.AreEqual(data.IsEn, false);
+            }
+
+        }
+
+
+        [TestMethod]
+        public void DeleteTest()
+        {
+            Dictionary v = new Dictionary();
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+        		
+                v.Name = "b";
+                v.Key = "xMrl9";
+                v.Value = "EywYKwZjnxDmyQVwVYph9bYpAudrE9fseXiODivU84zBNHxqZv7ztyImrm4bTwJHFxtTfnJfwnwkWtP9LQeWCjwoO0sKPFEz3KD5Ni6QzJViWgOZjbDtvCCAOM3Md";
+                v.IsEn = true;
+                v.ParentId = AddDictionary();
+                context.Set<Dictionary>().Add(v);
+                context.SaveChanges();
+            }
+
+            PartialViewResult rv = (PartialViewResult)_controller.Delete(v.ID.ToString());
+            Assert.IsInstanceOfType(rv.Model, typeof(DictionaryVM));
+
+            DictionaryVM vm = rv.Model as DictionaryVM;
+            v = new Dictionary();
+            v.ID = vm.Entity.ID;
+            vm.Entity = v;
+            _controller.Delete(v.ID.ToString(),null);
+
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+                var data = context.Set<Dictionary>().Find(v.ID);
+                Assert.AreEqual(data, null);
+            }
+
+        }
+
+
+        [TestMethod]
+        public void DetailsTest()
+        {
+            Dictionary v = new Dictionary();
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+				
+                v.Name = "b";
+                v.Key = "xMrl9";
+                v.Value = "EywYKwZjnxDmyQVwVYph9bYpAudrE9fseXiODivU84zBNHxqZv7ztyImrm4bTwJHFxtTfnJfwnwkWtP9LQeWCjwoO0sKPFEz3KD5Ni6QzJViWgOZjbDtvCCAOM3Md";
+                v.IsEn = true;
+                v.ParentId = AddDictionary();
+                context.Set<Dictionary>().Add(v);
+                context.SaveChanges();
+            }
+            PartialViewResult rv = (PartialViewResult)_controller.Details(v.ID.ToString());
+            Assert.IsInstanceOfType(rv.Model, typeof(IBaseCRUDVM<TopBasePoco>));
+            Assert.AreEqual(v.ID, (rv.Model as IBaseCRUDVM<TopBasePoco>).Entity.GetID());
+        }
+
+        [TestMethod]
+        public void BatchEditTest()
+        {
+            Dictionary v1 = new Dictionary();
+            Dictionary v2 = new Dictionary();
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+				
+                v1.Name = "b";
+                v1.Key = "xMrl9";
+                v1.Value = "EywYKwZjnxDmyQVwVYph9bYpAudrE9fseXiODivU84zBNHxqZv7ztyImrm4bTwJHFxtTfnJfwnwkWtP9LQeWCjwoO0sKPFEz3KD5Ni6QzJViWgOZjbDtvCCAOM3Md";
+                v1.IsEn = true;
+                v1.ParentId = AddDictionary();
+                v2.Name = "QsFRU0Hrpj0paqSATzzz7bBy7XUEiXX3n2ochswiODO";
+                v2.Key = "xpZrS27u53";
+                v2.Value = "guWhKhfl1PVouMDiYmcgkvledon5IsxDS1OmRCXsI7DN5NMIKex21a9FdhlIzkPnMebXpH5Lvb2kOk0ADso6eGecpBYjRnFQcZopebKAQp1q7XghV67Mbqe7Uy";
+                v2.IsEn = false;
+                v2.ParentId = v1.ParentId; 
+                context.Set<Dictionary>().Add(v1);
+                context.Set<Dictionary>().Add(v2);
+                context.SaveChanges();
+            }
+
+            PartialViewResult rv = (PartialViewResult)_controller.BatchDelete(new string[] { v1.ID.ToString(), v2.ID.ToString() });
+            Assert.IsInstanceOfType(rv.Model, typeof(DictionaryBatchVM));
+
+            DictionaryBatchVM vm = rv.Model as DictionaryBatchVM;
+            vm.Ids = new string[] { v1.ID.ToString(), v2.ID.ToString() };
+            
+            vm.FC = new Dictionary<string, object>();
+			
+            _controller.DoBatchEdit(vm, null);
+
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+                var data1 = context.Set<Dictionary>().Find(v1.ID);
+                var data2 = context.Set<Dictionary>().Find(v2.ID);
+ 				
+            }
+        }
+
+
+        [TestMethod]
+        public void BatchDeleteTest()
+        {
+            Dictionary v1 = new Dictionary();
+            Dictionary v2 = new Dictionary();
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+				
+                v1.Name = "b";
+                v1.Key = "xMrl9";
+                v1.Value = "EywYKwZjnxDmyQVwVYph9bYpAudrE9fseXiODivU84zBNHxqZv7ztyImrm4bTwJHFxtTfnJfwnwkWtP9LQeWCjwoO0sKPFEz3KD5Ni6QzJViWgOZjbDtvCCAOM3Md";
+                v1.IsEn = true;
+                v1.ParentId = AddDictionary();
+                v2.Name = "QsFRU0Hrpj0paqSATzzz7bBy7XUEiXX3n2ochswiODO";
+                v2.Key = "xpZrS27u53";
+                v2.Value = "guWhKhfl1PVouMDiYmcgkvledon5IsxDS1OmRCXsI7DN5NMIKex21a9FdhlIzkPnMebXpH5Lvb2kOk0ADso6eGecpBYjRnFQcZopebKAQp1q7XghV67Mbqe7Uy";
+                v2.IsEn = false;
+                v2.ParentId = v1.ParentId; 
+                context.Set<Dictionary>().Add(v1);
+                context.Set<Dictionary>().Add(v2);
+                context.SaveChanges();
+            }
+
+            PartialViewResult rv = (PartialViewResult)_controller.BatchDelete(new string[] { v1.ID.ToString(), v2.ID.ToString() });
+            Assert.IsInstanceOfType(rv.Model, typeof(DictionaryBatchVM));
+
+            DictionaryBatchVM vm = rv.Model as DictionaryBatchVM;
+            vm.Ids = new string[] { v1.ID.ToString(), v2.ID.ToString() };
+            _controller.DoBatchDelete(vm, null);
+
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+                var data1 = context.Set<Dictionary>().Find(v1.ID);
+                var data2 = context.Set<Dictionary>().Find(v2.ID);
+                Assert.AreEqual(data1, null);
+            Assert.AreEqual(data2, null);
+            }
+        }
+
+        private Guid AddDictionary()
+        {
+            Dictionary v = new Dictionary();
+            using (var context = new DataContext(_seed, DBTypeEnum.Memory))
+            {
+                try{
+
+                v.Name = "SP8IclP";
+                v.Key = "dpuu";
+                v.Value = "umUUGsNG3WGFIQnAVwzjcLncu32tsbKnwmsdNxeZP20qaqTdQ2Soi1J2k5Y2x68gHiUOv";
+                v.IsEn = false;
+                context.Set<Dictionary>().Add(v);
+                context.SaveChanges();
+                }
+                catch{}
+            }
+            return v.ID;
+        }
+
+
+    }
+}
diff --git a/cy_scdz.Test/Properties/launchSettings.json b/cy_scdz.Test/Properties/launchSettings.json
new file mode 100644
index 0000000..1f6015b
--- /dev/null
+++ b/cy_scdz.Test/Properties/launchSettings.json
@@ -0,0 +1,12 @@
+{
+  "profiles": {
+    "cy_scdz.Test": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      },
+      "applicationUrl": "https://localhost:50665;http://localhost:50666"
+    }
+  }
+}
\ No newline at end of file
diff --git a/cy_scdz.ViewModel/Setting/SettingListVM.cs b/cy_scdz.ViewModel/Setting/SettingListVM.cs
new file mode 100644
index 0000000..ad39db8
--- /dev/null
+++ b/cy_scdz.ViewModel/Setting/SettingListVM.cs
@@ -0,0 +1,12 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace cy_scdz.ViewModel.Setting
+{
+    public class SettingListVM
+    {
+    }
+}
diff --git a/cy_scdz.ViewModel/Setting/SettingVm.cs b/cy_scdz.ViewModel/Setting/SettingVm.cs
new file mode 100644
index 0000000..5e8389c
--- /dev/null
+++ b/cy_scdz.ViewModel/Setting/SettingVm.cs
@@ -0,0 +1,108 @@
+锘縰sing cy_scdz.Model.Set;
+using Elsa.Models;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using utils;
+using WalkingTec.Mvvm.Core;
+using WalkingTec.Mvvm.Core.Extensions;
+
+namespace cy_scdz.ViewModel.Setting
+{
+    public partial class SettingVm:BaseCRUDVM<Dictionary>
+    {
+
+      public  List<Dictionary> allNodesWithChildren= new List<Dictionary>();
+        public SettingVm()
+        {
+            SetInclude(x => x.Parent);
+            
+        }
+
+        protected override void InitVM()
+        {
+            allNodesWithChildren = DC.Set<Dictionary>().Where(x=>x.Parent==null)
+                .Include(x=>x.Children)    
+      .ThenInclude(c => c.Children)
+
+      .ToList();
+        }
+
+        public override void DoAdd()
+        {
+            base.DoAdd();
+        }
+        /// <summary>
+        /// 澧炲姞涓�涓柊鐨勫瓧鍏�
+        /// </summary>
+        /// <param name="name">鍚嶇О</param>
+        /// <param name="PKey">鐖跺缓key</param>
+        /// <param name="Key">鑷韩key</param>
+        /// <param name="value">鍊�</param>
+        public void addNew(string name, string? PKey=null,string? Key=null, string? value = null)
+        {
+            Dictionary Pd = null;
+            if(!string.IsNullOrEmpty(PKey))
+            {
+                Pd= DC.Set<Dictionary>().Where(x => x.IsEn == true && x.Key == PKey).FirstOrDefault();
+                if(Pd==null)
+                {
+                    MSD.AddModelError("ParentId", "娌℃湁鎵惧埌涓婄骇淇℃伅");
+                    return;
+                }
+                
+            }
+            Entity = new Dictionary()
+            {
+                Key = Key?? utilsFun.GenerateRandomString(10),
+                Value = value,
+                Name = name,
+                IsEn = true,
+                ParentId = Pd == null ? null : Pd.ID,
+
+
+
+            };
+            SetDuplicatedCheck();
+            Validate();
+            base.DoAdd();
+            
+
+
+
+        }
+        public override void Validate()
+        {
+            base.Validate();
+        }
+        public override DuplicatedInfo<Dictionary> SetDuplicatedCheck()
+        {
+            var rv = CreateFieldsInfo(SimpleField(x => x.Name), SimpleField(x=>x.ParentId));
+            rv.AddGroup(SimpleField(x => x.Key));
+           
+            return rv;
+        }
+   
+        public override void DoEdit(bool updateAllFields = false)
+        {
+            base.DoEdit(updateAllFields);
+        }
+
+        public override void DoDelete()
+        {
+            base.DoDelete();
+        }
+
+
+  
+
+     
+      
+      
+     
+      
+    }
+}
diff --git a/cy_scdz.ViewModel/cy_scdz.ViewModel.csproj b/cy_scdz.ViewModel/cy_scdz.ViewModel.csproj
index cf35f82..1535a38 100644
--- a/cy_scdz.ViewModel/cy_scdz.ViewModel.csproj
+++ b/cy_scdz.ViewModel/cy_scdz.ViewModel.csproj
@@ -9,6 +9,7 @@
 
   <ItemGroup>
     <ProjectReference Include="..\cy_scdz.Model\cy_scdz.Model.csproj" />
-  </ItemGroup >
+    <ProjectReference Include="..\utils\utils.csproj" />
+  </ItemGroup>
 </Project>
 
diff --git a/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryBatchVM.cs b/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryBatchVM.cs
new file mode 100644
index 0000000..ae71f3f
--- /dev/null
+++ b/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryBatchVM.cs
@@ -0,0 +1,35 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+using WalkingTec.Mvvm.Core;
+using WalkingTec.Mvvm.Core.Extensions;
+using cy_scdz.Model.Set;
+
+
+namespace cy_scdz.ViewModel.dictionary.DictionaryVMs
+{
+    public partial class DictionaryBatchVM : BaseBatchVM<Dictionary, Dictionary_BatchEdit>
+    {
+        public DictionaryBatchVM()
+        {
+            ListVM = new DictionaryListVM();
+            LinkedVM = new Dictionary_BatchEdit();
+        }
+
+    }
+
+	/// <summary>
+    /// Class to define batch edit fields
+    /// </summary>
+    public class Dictionary_BatchEdit : BaseVM
+    {
+
+        protected override void InitVM()
+        {
+        }
+
+    }
+
+}
diff --git a/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryImportVM.cs b/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryImportVM.cs
new file mode 100644
index 0000000..db4f7e9
--- /dev/null
+++ b/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryImportVM.cs
@@ -0,0 +1,39 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+using WalkingTec.Mvvm.Core;
+using WalkingTec.Mvvm.Core.Extensions;
+using cy_scdz.Model.Set;
+
+
+namespace cy_scdz.ViewModel.dictionary.DictionaryVMs
+{
+    public partial class DictionaryTemplateVM : BaseTemplateVM
+    {
+        [Display(Name = "鍚嶇О")]
+        public ExcelPropety Name_Excel = ExcelPropety.CreateProperty<Dictionary>(x => x.Name);
+        [Display(Name = "Key")]
+        public ExcelPropety Key_Excel = ExcelPropety.CreateProperty<Dictionary>(x => x.Key);
+        [Display(Name = "鍊�")]
+        public ExcelPropety Value_Excel = ExcelPropety.CreateProperty<Dictionary>(x => x.Value);
+        [Display(Name = "鏄惁鏈夋晥")]
+        public ExcelPropety IsEn_Excel = ExcelPropety.CreateProperty<Dictionary>(x => x.IsEn);
+        [Display(Name = "_Admin.Parent")]
+        public ExcelPropety Parent_Excel = ExcelPropety.CreateProperty<Dictionary>(x => x.ParentId);
+
+	    protected override void InitVM()
+        {
+            Parent_Excel.DataType = ColumnDataType.ComboBox;
+            Parent_Excel.ListItems = DC.Set<Dictionary>().GetSelectListItems(Wtm, y => y.Name);
+        }
+
+    }
+
+    public class DictionaryImportVM : BaseImportVM<DictionaryTemplateVM, Dictionary>
+    {
+
+    }
+
+}
diff --git a/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryListVM.cs b/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryListVM.cs
new file mode 100644
index 0000000..e01cf20
--- /dev/null
+++ b/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryListVM.cs
@@ -0,0 +1,71 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using WalkingTec.Mvvm.Core;
+using WalkingTec.Mvvm.Core.Extensions;
+using Microsoft.EntityFrameworkCore;
+using System.ComponentModel.DataAnnotations;
+using cy_scdz.Model.Set;
+
+
+namespace cy_scdz.ViewModel.dictionary.DictionaryVMs
+{
+    public partial class DictionaryListVM : BasePagedListVM<Dictionary_View, DictionarySearcher>
+    {
+        protected override List<GridAction> InitGridAction()
+        {
+            return new List<GridAction>
+            {
+                this.MakeStandardAction("Dictionary", GridActionStandardTypesEnum.Create, Localizer["Sys.Create"],"dictionary", dialogWidth: 800),
+                this.MakeStandardAction("Dictionary", GridActionStandardTypesEnum.Edit, Localizer["Sys.Edit"], "dictionary", dialogWidth: 800),
+                this.MakeStandardAction("Dictionary", GridActionStandardTypesEnum.Delete, Localizer["Sys.Delete"], "dictionary", dialogWidth: 800),
+                this.MakeStandardAction("Dictionary", GridActionStandardTypesEnum.Details, Localizer["Sys.Details"], "dictionary", dialogWidth: 800),
+                this.MakeStandardAction("Dictionary", GridActionStandardTypesEnum.BatchEdit, Localizer["Sys.BatchEdit"], "dictionary", dialogWidth: 800),
+                this.MakeStandardAction("Dictionary", GridActionStandardTypesEnum.BatchDelete, Localizer["Sys.BatchDelete"], "dictionary", dialogWidth: 800),
+                this.MakeStandardAction("Dictionary", GridActionStandardTypesEnum.Import, Localizer["Sys.Import"], "dictionary", dialogWidth: 800),
+                this.MakeStandardAction("Dictionary", GridActionStandardTypesEnum.ExportExcel, Localizer["Sys.Export"], "dictionary"),
+            };
+        }
+
+
+        protected override IEnumerable<IGridColumn<Dictionary_View>> InitGridHeader()
+        {
+            return new List<GridColumn<Dictionary_View>>{
+                this.MakeGridHeader(x => x.Name),
+                this.MakeGridHeader(x => x.Key),
+                this.MakeGridHeader(x => x.Value),
+                this.MakeGridHeader(x => x.IsEn),
+                this.MakeGridHeader(x => x.Name_view),
+                this.MakeGridHeaderAction(width: 200)
+            };
+        }
+
+        public override IOrderedQueryable<Dictionary_View> GetSearchQuery()
+        {
+            var query = DC.Set<Dictionary>()
+                .CheckContain(Searcher.Name, x=>x.Name)
+                .CheckContain(Searcher.Key, x=>x.Key)
+                .CheckEqual(Searcher.IsEn, x=>x.IsEn)
+                .CheckEqual(Searcher.ParentId, x=>x.ParentId)
+                .Select(x => new Dictionary_View
+                {
+				    ID = x.ID,
+                    Name = x.Name,
+                    Key = x.Key,
+                    Value = x.Value,
+                    IsEn = x.IsEn,
+                    Name_view = x.Parent.Name,
+                })
+                .OrderBy(x => x.ID);
+            return query;
+        }
+
+    }
+
+    public class Dictionary_View : Dictionary{
+        [Display(Name = "涓婄骇鍚嶇О")]
+        public String Name_view { get; set; }
+
+    }
+}
diff --git a/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionarySearcher.cs b/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionarySearcher.cs
new file mode 100644
index 0000000..3afaed1
--- /dev/null
+++ b/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionarySearcher.cs
@@ -0,0 +1,31 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+using WalkingTec.Mvvm.Core;
+using WalkingTec.Mvvm.Core.Extensions;
+using cy_scdz.Model.Set;
+
+
+namespace cy_scdz.ViewModel.dictionary.DictionaryVMs
+{
+    public partial class DictionarySearcher : BaseSearcher
+    {
+        [Display(Name = "鍚嶇О")]
+        public String Name { get; set; }
+        [Display(Name = "Key")]
+        public String Key { get; set; }
+        [Display(Name = "鏄惁鏈夋晥")]
+        public Boolean? IsEn { get; set; }
+        public List<ComboSelectListItem> AllParents { get; set; }
+        [Display(Name = "_Admin.Parent")]
+        public Guid? ParentId { get; set; }
+
+        protected override void InitVM()
+        {
+            AllParents = DC.Set<Dictionary>().Where(x=>x.Parent==null).GetSelectListItems(Wtm, y => y.Name);
+        }
+
+    }
+}
diff --git a/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryVM.cs b/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryVM.cs
new file mode 100644
index 0000000..ff76c45
--- /dev/null
+++ b/cy_scdz.ViewModel/dictionary/DictionaryVMs/DictionaryVM.cs
@@ -0,0 +1,86 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.ComponentModel.DataAnnotations;
+using WalkingTec.Mvvm.Core;
+using WalkingTec.Mvvm.Core.Extensions;
+using cy_scdz.Model.Set;
+using utils;
+
+namespace cy_scdz.ViewModel.dictionary.DictionaryVMs
+{
+    public partial class DictionaryVM : BaseCRUDVM<Dictionary>
+    {
+        public List<ComboSelectListItem> AllParents { get; set; }
+
+        public DictionaryVM()
+        {
+            SetInclude(x => x.Parent);
+        }
+
+        protected override void InitVM()
+        {
+            AllParents = DC.Set<Dictionary>().Where(x => x.Parent == null).GetSelectListItems(Wtm, y => y.Name);
+        }
+
+        public override void DoAdd()
+        {           
+            base.DoAdd();
+        }
+        public override DuplicatedInfo<Dictionary> SetDuplicatedCheck()
+        {
+            var rv = CreateFieldsInfo(SimpleField(x => x.Name));
+            rv.AddGroup(SimpleField(x => x.Key));
+
+            return rv;
+
+        }
+        public override void DoEdit(bool updateAllFields = false)
+        {
+            base.DoEdit(updateAllFields);
+        }
+
+        public override void DoDelete()
+        {
+            base.DoDelete();
+        }
+        /// <summary>
+        /// 澧炲姞涓�涓柊鐨勫瓧鍏�
+        /// </summary>
+        /// <param name="name">鍚嶇О</param>
+        /// <param name="PKey">鐖跺缓key</param>
+        /// <param name="Key">鑷韩key</param>
+        /// <param name="value">鍊�</param>
+        public void addNew(string name, string? PKey = null, string? Key = null, string? value = null)
+        {
+            Dictionary Pd = null;
+            if (!string.IsNullOrEmpty(PKey))
+            {
+                Pd = DC.Set<Dictionary>().Where(x => x.IsEn == true && x.Key == PKey).FirstOrDefault();
+                if (Pd == null)
+                {
+                    MSD.AddModelError("ParentId", "娌℃湁鎵惧埌涓婄骇淇℃伅");
+                    return;
+                }
+
+            }
+            Entity = new Dictionary()
+            {
+                Key = Key ?? utilsFun.GenerateRandomString(10),
+                Value = value,
+                Name = name,
+                IsEn = true,
+                ParentId = Pd == null ? null : Pd.ID,
+
+
+
+            };
+            base.DoAdd();
+
+
+
+
+        }
+    }
+}
diff --git a/cy_scdz.sln b/cy_scdz.sln
index 2edcbca..bbee705 100644
--- a/cy_scdz.sln
+++ b/cy_scdz.sln
@@ -1,41 +1,50 @@
 锘�
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.28307.329
+# Visual Studio Version 17
+VisualStudioVersion = 17.7.33913.275
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cy_scdz", "cy_scdz\cy_scdz.csproj", "{35deb565-b3c8-49dc-9fc4-19e977787c6b}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cy_scdz", "cy_scdz\cy_scdz.csproj", "{35DEB565-B3C8-49DC-9FC4-19E977787C6B}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cy_scdz.Model", "cy_scdz.Model\cy_scdz.Model.csproj", "{cc774f56-bf88-4dd3-8ffc-87ceb3fe52a3}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cy_scdz.Model", "cy_scdz.Model\cy_scdz.Model.csproj", "{CC774F56-BF88-4DD3-8FFC-87CEB3FE52A3}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cy_scdz.DataAccess", "cy_scdz.DataAccess\cy_scdz.DataAccess.csproj", "{ccbaa8ef-1f00-4cce-bdc8-9e96bd5bcdf0}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cy_scdz.DataAccess", "cy_scdz.DataAccess\cy_scdz.DataAccess.csproj", "{CCBAA8EF-1F00-4CCE-BDC8-9E96BD5BCDF0}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cy_scdz.ViewModel", "cy_scdz.ViewModel\cy_scdz.ViewModel.csproj", "{7475cd53-adf6-4b85-a508-033c92b6c150}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cy_scdz.ViewModel", "cy_scdz.ViewModel\cy_scdz.ViewModel.csproj", "{7475CD53-ADF6-4B85-A508-033C92B6C150}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cy_scdz.Test", "cy_scdz.Test\cy_scdz.Test.csproj", "{d2ded4e0-0b1b-4822-9dd7-4a531dea14af}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cy_scdz.Test", "cy_scdz.Test\cy_scdz.Test.csproj", "{D2DED4E0-0B1B-4822-9DD7-4A531DEA14AF}"
 EndProject
-
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "utils", "utils\utils.csproj", "{C4D69150-D72A-463D-A026-9F5785677495}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{35deb565-b3c8-49dc-9fc4-19e977787c6b}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{35deb565-b3c8-49dc-9fc4-19e977787c6b}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{35deb565-b3c8-49dc-9fc4-19e977787c6b}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{35deb565-b3c8-49dc-9fc4-19e977787c6b}.Release|Any CPU.Build.0 = Release|Any CPU
-		{cc774f56-bf88-4dd3-8ffc-87ceb3fe52a3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{cc774f56-bf88-4dd3-8ffc-87ceb3fe52a3}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{cc774f56-bf88-4dd3-8ffc-87ceb3fe52a3}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{cc774f56-bf88-4dd3-8ffc-87ceb3fe52a3}.Release|Any CPU.Build.0 = Release|Any CPU
-		{ccbaa8ef-1f00-4cce-bdc8-9e96bd5bcdf0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{ccbaa8ef-1f00-4cce-bdc8-9e96bd5bcdf0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{ccbaa8ef-1f00-4cce-bdc8-9e96bd5bcdf0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{ccbaa8ef-1f00-4cce-bdc8-9e96bd5bcdf0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{7475cd53-adf6-4b85-a508-033c92b6c150}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{7475cd53-adf6-4b85-a508-033c92b6c150}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{7475cd53-adf6-4b85-a508-033c92b6c150}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{7475cd53-adf6-4b85-a508-033c92b6c150}.Release|Any CPU.Build.0 = Release|Any CPU
+		{35DEB565-B3C8-49DC-9FC4-19E977787C6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{35DEB565-B3C8-49DC-9FC4-19E977787C6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{35DEB565-B3C8-49DC-9FC4-19E977787C6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{35DEB565-B3C8-49DC-9FC4-19E977787C6B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CC774F56-BF88-4DD3-8FFC-87CEB3FE52A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CC774F56-BF88-4DD3-8FFC-87CEB3FE52A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CC774F56-BF88-4DD3-8FFC-87CEB3FE52A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CC774F56-BF88-4DD3-8FFC-87CEB3FE52A3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CCBAA8EF-1F00-4CCE-BDC8-9E96BD5BCDF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CCBAA8EF-1F00-4CCE-BDC8-9E96BD5BCDF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CCBAA8EF-1F00-4CCE-BDC8-9E96BD5BCDF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CCBAA8EF-1F00-4CCE-BDC8-9E96BD5BCDF0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7475CD53-ADF6-4B85-A508-033C92B6C150}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7475CD53-ADF6-4B85-A508-033C92B6C150}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7475CD53-ADF6-4B85-A508-033C92B6C150}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7475CD53-ADF6-4B85-A508-033C92B6C150}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D2DED4E0-0B1B-4822-9DD7-4A531DEA14AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D2DED4E0-0B1B-4822-9DD7-4A531DEA14AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D2DED4E0-0B1B-4822-9DD7-4A531DEA14AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D2DED4E0-0B1B-4822-9DD7-4A531DEA14AF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C4D69150-D72A-463D-A026-9F5785677495}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C4D69150-D72A-463D-A026-9F5785677495}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C4D69150-D72A-463D-A026-9F5785677495}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C4D69150-D72A-463D-A026-9F5785677495}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/cy_scdz/Areas/Setting/Controllers/SettingController.cs b/cy_scdz/Areas/Setting/Controllers/SettingController.cs
new file mode 100644
index 0000000..c7f426e
--- /dev/null
+++ b/cy_scdz/Areas/Setting/Controllers/SettingController.cs
@@ -0,0 +1,65 @@
+锘縰sing cy_scdz.ViewModel.dictionary.DictionaryVMs;
+using cy_scdz.ViewModel.Setting;
+using Microsoft.AspNetCore.Mvc;
+using System.ComponentModel.DataAnnotations;
+using WalkingTec.Mvvm.Core;
+using WalkingTec.Mvvm.Mvc;
+
+namespace cy_scdz.Areas.Setting.Controllers
+{
+    [Area("Setting")]
+    [ActionDescription("绯荤粺璁剧疆")]
+    public class SettingController : BaseController
+    {
+        #region Edit
+        [ActionDescription("绯荤粺璁剧疆")]
+        public ActionResult Index()
+        {
+            var vm = Wtm.CreateVM<SettingVm>();
+            return PartialView(vm);
+        }
+
+        
+
+
+   
+
+        [ActionDescription("绯荤粺璁剧疆")]
+        [HttpPost]     
+        public ActionResult Edit ([FromBody]EditSettingParam Param)
+        {
+            if (string.IsNullOrEmpty(Param.key))
+                return Ok(new { code = 0});
+            var vm= Wtm.CreateVM<SettingVm>(passInit:true);
+          
+            vm.addNew(Param.name, Param.key);
+            if(vm.MSD.IsValid)
+            {
+                return Ok(new { code = 1 });
+            }
+            else
+
+            return Ok(new { code = 0,msg=vm.MSD.GetFirstError()});
+        }
+
+
+        #endregion
+    }
+    /// <summary>
+    /// 澧炲姞璁剧疆杈撳叆鍙傛暟妯″瀷
+    /// </summary>
+    public class EditSettingParam
+    {
+        /// <summary>
+        /// keyname
+        /// </summary>
+        [Required]
+        public string key { get; set; }
+        /// <summary>
+        /// 鍚嶇О
+        /// </summary>
+        [Required]
+        public string name { get; set; }
+
+    }
+}
diff --git a/cy_scdz/Areas/Setting/Views/Setting/index.cshtml b/cy_scdz/Areas/Setting/Views/Setting/index.cshtml
new file mode 100644
index 0000000..7fe57a9
--- /dev/null
+++ b/cy_scdz/Areas/Setting/Views/Setting/index.cshtml
@@ -0,0 +1,169 @@
+锘緻model cy_scdz.ViewModel.Setting.SettingVm
+@inject IStringLocalizer<Program> Localizer;
+
+
+
+@for (int i = 0; i < Model.allNodesWithChildren.Count; i++)
+{
+    <div class="setfix set_allitem">
+        <div class="content">
+            <div class="text-justified bold-text tabsetsys">  @Model.allNodesWithChildren[i].Name:</div>
+        </div>
+        <div class="setfix">
+            @for (int ix = 0; ix < Model.allNodesWithChildren[i].Children.Count; ix++)
+            {
+
+
+                <div class="content">
+                    <div class="text-justified  itemsetsys">  @Model.allNodesWithChildren[i].Children.ToArray()[ix].Name</div>
+                </div>
+
+            }
+            @if (Model.allNodesWithChildren[i].Key == "zbgys" || Model.allNodesWithChildren[i].Key == "fmzz" || Model.allNodesWithChildren[i].Key == "nyzz")
+            {
+                <button class="itemsetbutsys layui-btn-submit" id="@Model.allNodesWithChildren[i].Key">鑷畾涔夊鍔�</button>
+            }
+        </div>
+    </div>
+
+}
+
+
+<style>
+    .set_allitem {
+        margin: 5px 0px;
+    }
+
+    .set_content {
+        width: 100%;
+        text-align: justify;
+    }
+
+    .text-justified {
+        text-align: justify;
+    }
+
+        /* 瀵逛簬鐜颁唬娴忚鍣紙鍖呮嫭IE10+锛夌殑瀹屾暣鏀寔锛屽彲浠ユ坊鍔犱互涓嬫牱寮忎互澶勭悊鏈�鍚庝竴琛� */
+        .text-justified:last-child::after {
+            content: "";
+            display: inline-block;
+            width: 100%;
+        }
+
+    .font-black {
+        color: #000000;
+        /* 鎴栬�呯畝鍐欎负 */
+        color: black;
+    }
+
+    .bold-text {
+        font-weight: bold;
+    }
+
+    .setfix {
+        display: flex;
+        height: 20px;
+    }
+
+    .tabsetsys {
+        /* 鏍囬鍋忕Щ*/
+        padding-left: 10px;
+        width: 80px;
+    }
+
+    .itemsetbutsys {
+        margin: 0px 10px;
+    }
+
+    .itemsetsys {
+        /* 鏍囬鍋忕Щ*/
+        padding: 0px 10px;
+    }
+</style>
+
+
+<script>
+    layui.use(['layer', 'jquery'], function () {
+        var layer = layui.layer;
+        var $ = layui.jquery;
+
+        // 涓烘墍鏈夊叿鏈夌壒瀹氱被鍚嶏紙濡傦細layui-btn-submit锛夌殑鎸夐挳缁戝畾鐐瑰嚮浜嬩欢
+        $('.layui-btn-submit').on('click', function (event) {
+            event.preventDefault(); // 闃绘榛樿琛屼负
+
+            // 鑾峰彇褰撳墠鐐瑰嚮鎸夐挳鐨刬d灞炴�у��
+            var buttonId = "";
+            switch (this.id) {
+                case 'zbgys':
+                    buttonId = "璇疯緭鍏ユ柊澧炰腑鏍囦緵搴斿晢鍚嶇О";
+                    break;
+                case 'fmzz':
+                    buttonId = "璇疯緭鍏ユ柊澧炲皝闈㈢焊寮犺鏍�";
+                    break;
+                case 'nyzz':
+                    buttonId = "璇疯緭鍏ユ柊澧炲唴椤电焊寮犺鏍�";
+                    break;
+                default:
+                    buttonId = "";
+                    break;
+
+            }
+
+            var btid = this.id;
+
+            // 寮瑰嚭涓�涓璇濇璁╃敤鎴疯緭鍏ュ唴瀹�
+            layer.prompt({
+                title: buttonId,
+                formType: 0 // 0 琛ㄧず鏂囨湰杈撳叆妗�
+            }, function (value, index, elem) {
+                // 鍦ㄨ繖閲屾墽琛屾彁浜ら�昏緫锛屼緥濡傚悜鏈嶅姟鍣ㄥ彂閫佹暟鎹瓑
+                submitData(btid, value, index);
+
+            });
+        });
+
+        function submitData(id, value, index) {
+           
+            $.ajax({
+                url: "/Setting/Setting/Edit",
+                type: "POST"
+                , contentType: "application/json; charset=utf-8"
+                , dataType: "json"
+                , data: JSON.stringify({ key: id, name: value })
+
+
+                , success: function (result) {
+                    debugger
+                    if (result.code == 1) {
+                        window.location.reload();
+                        layer.alert(`鍐欏叆鎴愬姛`, {
+                            icon: 0, // 璁剧疆鍥炬爣涓鸿鍛婂浘鏍�
+                            title: '鎻愮ず'
+                        });
+
+
+                        // 鍏抽棴瀵硅瘽妗�
+                        layer.close(index);
+                        return;
+                    }
+                    else {
+                        layer.alert(`鍐欏叆澶辫触:${result.msg}`, {
+                            icon: 2, // 璁剧疆鍥炬爣涓鸿鍛婂浘鏍�
+                            title: '鎻愮ず'
+                        });
+
+                        return;
+                    }
+                },
+                    error: function (xhr, status, error) {
+                        layer.alert(`绯荤粺閿欒:${error}`, {
+                            icon: 2, // 璁剧疆鍥炬爣涓鸿鍛婂浘鏍�
+                            title: '鎻愮ず'
+                        });
+                        return;
+                    }
+                });
+
+        }
+    });
+</script>
\ No newline at end of file
diff --git a/cy_scdz/Areas/dictionary/Controllers/DictionaryController.cs b/cy_scdz/Areas/dictionary/Controllers/DictionaryController.cs
new file mode 100644
index 0000000..47c5459
--- /dev/null
+++ b/cy_scdz/Areas/dictionary/Controllers/DictionaryController.cs
@@ -0,0 +1,219 @@
+锘縰sing Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using WalkingTec.Mvvm.Core;
+using WalkingTec.Mvvm.Mvc;
+using WalkingTec.Mvvm.Core.Extensions;
+using cy_scdz.ViewModel.dictionary.DictionaryVMs;
+
+namespace cy_scdz.Controllers
+{
+    [Area("dictionary")]
+    [ActionDescription("瀛楀吀绠$悊")]
+    public partial class DictionaryController : BaseController
+    {
+        #region Search
+        [ActionDescription("Sys.Search")]
+        public ActionResult Index()
+        {
+            var vm = Wtm.CreateVM<DictionaryListVM>();
+            return PartialView(vm);
+        }
+
+        [ActionDescription("Sys.Search")]
+        [HttpPost]
+        public string Search(DictionarySearcher searcher)
+        {
+            var vm = Wtm.CreateVM<DictionaryListVM>(passInit: true);
+            if (ModelState.IsValid)
+            {
+                vm.Searcher = searcher;
+                return vm.GetJson(false);
+            }
+            else
+            {
+                return vm.GetError();
+            }
+        }
+
+        #endregion
+
+        #region Create
+        [ActionDescription("Sys.Create")]
+        public ActionResult Create()
+        {
+            var vm = Wtm.CreateVM<DictionaryVM>();
+            return PartialView(vm);
+        }
+
+        [HttpPost]
+        [ActionDescription("Sys.Create")]
+        public ActionResult Create(DictionaryVM vm)
+        {
+            if (!ModelState.IsValid)
+            {
+                return PartialView(vm);
+            }
+            else
+            {
+                vm.DoAdd();
+                if (!ModelState.IsValid)
+                {
+                    vm.DoReInit();
+                    return PartialView(vm);
+                }
+                else
+                {
+                    return FFResult().CloseDialog().RefreshGrid();
+                }
+            }
+        }
+        #endregion
+
+        #region Edit
+        [ActionDescription("Sys.Edit")]
+        public ActionResult Edit(string id)
+        {
+            var vm = Wtm.CreateVM<DictionaryVM>(id);
+            return PartialView(vm);
+        }
+
+        [ActionDescription("Sys.Edit")]
+        [HttpPost]
+        [ValidateFormItemOnly]
+        public ActionResult Edit(DictionaryVM vm)
+        {
+            if (!ModelState.IsValid)
+            {
+                return PartialView(vm);
+            }
+            else
+            {
+                vm.DoEdit();
+                if (!ModelState.IsValid)
+                {
+                    vm.DoReInit();
+                    return PartialView(vm);
+                }
+                else
+                {
+                    return FFResult().CloseDialog().RefreshGridRow(vm.Entity.ID);
+                }
+            }
+        }
+        #endregion
+
+        #region Delete
+        [ActionDescription("Sys.Delete")]
+        public ActionResult Delete(string id)
+        {
+            var vm = Wtm.CreateVM<DictionaryVM>(id);
+            return PartialView(vm);
+        }
+
+        [ActionDescription("Sys.Delete")]
+        [HttpPost]
+        public ActionResult Delete(string id, IFormCollection nouse)
+        {
+            var vm = Wtm.CreateVM<DictionaryVM>(id);
+            vm.DoDelete();
+            if (!ModelState.IsValid)
+            {
+                return PartialView(vm);
+            }
+            else
+            {
+                return FFResult().CloseDialog().RefreshGrid();
+            }
+        }
+        #endregion
+
+        #region Details
+        [ActionDescription("Sys.Details")]
+        public ActionResult Details(string id)
+        {
+            var vm = Wtm.CreateVM<DictionaryVM>(id);
+            return PartialView(vm);
+        }
+        #endregion
+
+        #region BatchEdit
+        [HttpPost]
+        [ActionDescription("Sys.BatchEdit")]
+        public ActionResult BatchEdit(string[] IDs)
+        {
+            var vm = Wtm.CreateVM<DictionaryBatchVM>(Ids: IDs);
+            return PartialView(vm);
+        }
+
+        [HttpPost]
+        [ActionDescription("Sys.BatchEdit")]
+        public ActionResult DoBatchEdit(DictionaryBatchVM vm, IFormCollection nouse)
+        {
+            if (!ModelState.IsValid || !vm.DoBatchEdit())
+            {
+                return PartialView("BatchEdit",vm);
+            }
+            else
+            {
+                return FFResult().CloseDialog().RefreshGrid().Alert(Localizer["Sys.BatchEditSuccess", vm.Ids.Length]);
+            }
+        }
+        #endregion
+
+        #region BatchDelete
+        [HttpPost]
+        [ActionDescription("Sys.BatchDelete")]
+        public ActionResult BatchDelete(string[] IDs)
+        {
+            var vm = Wtm.CreateVM<DictionaryBatchVM>(Ids: IDs);
+            return PartialView(vm);
+        }
+
+        [HttpPost]
+        [ActionDescription("Sys.BatchDelete")]
+        public ActionResult DoBatchDelete(DictionaryBatchVM vm, IFormCollection nouse)
+        {
+            if (!ModelState.IsValid || !vm.DoBatchDelete())
+            {
+                return PartialView("BatchDelete",vm);
+            }
+            else
+            {
+                return FFResult().CloseDialog().RefreshGrid().Alert(Localizer["Sys.BatchDeleteSuccess", vm.Ids.Length]);
+            }
+        }
+        #endregion
+
+        #region Import
+		[ActionDescription("Sys.Import")]
+        public ActionResult Import()
+        {
+            var vm = Wtm.CreateVM<DictionaryImportVM>();
+            return PartialView(vm);
+        }
+
+        [HttpPost]
+        [ActionDescription("Sys.Import")]
+        public ActionResult Import(DictionaryImportVM vm, IFormCollection nouse)
+        {
+            if (vm.ErrorListVM.EntityList.Count > 0 || !vm.BatchSaveData())
+            {
+                return PartialView(vm);
+            }
+            else
+            {
+                return FFResult().CloseDialog().RefreshGrid().Alert(Localizer["Sys.ImportSuccess", vm.EntityList.Count.ToString()]);
+            }
+        }
+        #endregion
+
+        [ActionDescription("Sys.Export")]
+        [HttpPost]
+        public IActionResult ExportExcel(DictionaryListVM vm)
+        {
+            return vm.GetExportData();
+        }
+
+    }
+}
diff --git a/cy_scdz/Areas/dictionary/Views/Dictionary/BatchDelete.cshtml b/cy_scdz/Areas/dictionary/Views/Dictionary/BatchDelete.cshtml
new file mode 100644
index 0000000..792b5f8
--- /dev/null
+++ b/cy_scdz/Areas/dictionary/Views/Dictionary/BatchDelete.cshtml
@@ -0,0 +1,12 @@
+锘緻model cy_scdz.ViewModel.dictionary.DictionaryVMs.DictionaryBatchVM
+@inject IStringLocalizer<Program> Localizer;
+
+<wt:form vm="@Model">
+	<wt:quote>@Localizer["Sys.BatchDeleteConfirm"]</wt:quote>
+    <wt:hidden field="Ids" />
+    <wt:grid vm="ListVM" use-local-data="true" height="300"  hidden-checkbox="true" hidden-panel="true"/>
+    <wt:row align="AlignEnum.Right">
+        <wt:submitbutton theme=" ButtonThemeEnum.Warm" text="@Localizer["Sys.Delete"]"/>
+        <wt:closebutton />
+    </wt:row>
+</wt:form>
diff --git a/cy_scdz/Areas/dictionary/Views/Dictionary/BatchEdit.cshtml b/cy_scdz/Areas/dictionary/Views/Dictionary/BatchEdit.cshtml
new file mode 100644
index 0000000..7bf939d
--- /dev/null
+++ b/cy_scdz/Areas/dictionary/Views/Dictionary/BatchEdit.cshtml
@@ -0,0 +1,14 @@
+锘緻model cy_scdz.ViewModel.dictionary.DictionaryVMs.DictionaryBatchVM
+@inject IStringLocalizer<Program> Localizer;
+
+<wt:form vm="@Model">
+    <div style="margin-bottom:10px">@Localizer["Sys.BatchEditConfirm"] </div>
+<wt:row items-per-row="ItemsPerRowEnum.Two">
+</wt:row>
+    <wt:hidden field="Ids" />
+    <wt:grid vm="ListVM" use-local-data="true" height="300"  hidden-checkbox="true" hidden-panel="true"/>
+    <wt:row align="AlignEnum.Right">
+        <wt:submitbutton />
+        <wt:closebutton />
+    </wt:row>
+</wt:form>
diff --git a/cy_scdz/Areas/dictionary/Views/Dictionary/Create.cshtml b/cy_scdz/Areas/dictionary/Views/Dictionary/Create.cshtml
new file mode 100644
index 0000000..6a2b5e1
--- /dev/null
+++ b/cy_scdz/Areas/dictionary/Views/Dictionary/Create.cshtml
@@ -0,0 +1,16 @@
+锘緻model cy_scdz.ViewModel.dictionary.DictionaryVMs.DictionaryVM
+@inject IStringLocalizer<Program> Localizer;
+
+<wt:form vm="@Model">
+<wt:row items-per-row="ItemsPerRowEnum.Two">
+<wt:textbox field="Entity.Name" />
+<wt:textbox field="Entity.Key" />
+<wt:textbox field="Entity.Value" />
+<wt:switch field="Entity.IsEn" />
+<wt:combobox field="Entity.ParentId" items="AllParents"/>
+</wt:row>
+    <wt:row align="AlignEnum.Right">
+        <wt:submitbutton />
+        <wt:closebutton />
+    </wt:row>
+</wt:form>
diff --git a/cy_scdz/Areas/dictionary/Views/Dictionary/Delete.cshtml b/cy_scdz/Areas/dictionary/Views/Dictionary/Delete.cshtml
new file mode 100644
index 0000000..5a512eb
--- /dev/null
+++ b/cy_scdz/Areas/dictionary/Views/Dictionary/Delete.cshtml
@@ -0,0 +1,18 @@
+锘緻model cy_scdz.ViewModel.dictionary.DictionaryVMs.DictionaryVM
+@inject IStringLocalizer<Program> Localizer;
+
+<wt:form vm="@Model">
+	<wt:quote>@Localizer["Sys.DeleteConfirm"]</wt:quote>
+<wt:row items-per-row="ItemsPerRowEnum.Two">
+<wt:display field="Entity.Name" />
+<wt:display field="Entity.Key" />
+<wt:display field="Entity.Value" />
+<wt:display field="Entity.IsEn" />
+<wt:display field="Entity.Parent.Name" />
+</wt:row>
+    <wt:hidden field="Entity.ID" />
+    <wt:row align="AlignEnum.Right">
+        <wt:submitbutton theme=" ButtonThemeEnum.Warm" text="@Localizer["Sys.Delete"]"/>
+        <wt:closebutton />
+    </wt:row>
+</wt:form>
diff --git a/cy_scdz/Areas/dictionary/Views/Dictionary/Details.cshtml b/cy_scdz/Areas/dictionary/Views/Dictionary/Details.cshtml
new file mode 100644
index 0000000..5c343d0
--- /dev/null
+++ b/cy_scdz/Areas/dictionary/Views/Dictionary/Details.cshtml
@@ -0,0 +1,15 @@
+锘緻model cy_scdz.ViewModel.dictionary.DictionaryVMs.DictionaryVM
+@inject IStringLocalizer<Program> Localizer;
+
+<wt:form vm="@Model">
+<wt:row items-per-row="ItemsPerRowEnum.Two">
+<wt:display field="Entity.Name" />
+<wt:display field="Entity.Key" />
+<wt:display field="Entity.Value" />
+<wt:display field="Entity.IsEn" />
+<wt:display field="Entity.Parent.Name" />
+</wt:row>
+    <wt:row align="AlignEnum.Right">
+        <wt:closebutton />
+    </wt:row>
+</wt:form>
diff --git a/cy_scdz/Areas/dictionary/Views/Dictionary/Edit.cshtml b/cy_scdz/Areas/dictionary/Views/Dictionary/Edit.cshtml
new file mode 100644
index 0000000..3588a11
--- /dev/null
+++ b/cy_scdz/Areas/dictionary/Views/Dictionary/Edit.cshtml
@@ -0,0 +1,17 @@
+锘緻model cy_scdz.ViewModel.dictionary.DictionaryVMs.DictionaryVM
+@inject IStringLocalizer<Program> Localizer;
+
+<wt:form vm="@Model">
+<wt:row items-per-row="ItemsPerRowEnum.Two">
+<wt:textbox field="Entity.Name" />
+<wt:textbox field="Entity.Key" />
+<wt:textbox field="Entity.Value" />
+<wt:switch field="Entity.IsEn" />
+<wt:combobox field="Entity.ParentId" items="AllParents"/>
+</wt:row>
+    <wt:hidden field="Entity.ID" />
+    <wt:row align="AlignEnum.Right">
+        <wt:submitbutton />
+        <wt:closebutton />
+    </wt:row>
+</wt:form>
diff --git a/cy_scdz/Areas/dictionary/Views/Dictionary/Import.cshtml b/cy_scdz/Areas/dictionary/Views/Dictionary/Import.cshtml
new file mode 100644
index 0000000..c37e331
--- /dev/null
+++ b/cy_scdz/Areas/dictionary/Views/Dictionary/Import.cshtml
@@ -0,0 +1,14 @@
+锘緻model cy_scdz.ViewModel.dictionary.DictionaryVMs.DictionaryImportVM
+@inject IStringLocalizer<Program> Localizer;
+
+<wt:form vm="@Model">
+    <wt:row align="AlignEnum.Right">
+        <wt:downloadTemplateButton vm="@Model" />
+    </wt:row>
+    <wt:upload field="UploadFileId" label-text="@Model.Localizer["Sys.UploadTemplate"]" upload-type="ExcelFile" />
+    <wt:grid vm="ErrorListVM" use-local-data="true" hidden-checkbox="true" hidden-grid-index="true" hidden-panel="true"  height="300"/>
+    <wt:row align="AlignEnum.Right">
+        <wt:submitbutton />
+        <wt:closebutton />
+    </wt:row>
+</wt:form>
diff --git a/cy_scdz/Areas/dictionary/Views/Dictionary/Index.cshtml b/cy_scdz/Areas/dictionary/Views/Dictionary/Index.cshtml
new file mode 100644
index 0000000..9f9e3a6
--- /dev/null
+++ b/cy_scdz/Areas/dictionary/Views/Dictionary/Index.cshtml
@@ -0,0 +1,12 @@
+锘緻model cy_scdz.ViewModel.dictionary.DictionaryVMs.DictionaryListVM
+@inject IStringLocalizer<Program> Localizer;
+
+<wt:searchpanel vm="@Model" reset-btn="true">
+<wt:row items-per-row="ItemsPerRowEnum.Three">
+<wt:textbox field="Searcher.Name" />
+<wt:textbox field="Searcher.Key" />
+<wt:combobox field="Searcher.IsEn" empty-text="@Localizer["Sys.All"]" />
+<wt:combobox field="Searcher.ParentId" items="Searcher.AllParents" empty-text="@Localizer["Sys.All"]" />
+</wt:row>
+</wt:searchpanel>
+<wt:grid vm="@Model" url="/dictionary/Dictionary/Search"/>
diff --git a/cy_scdz/Views/Login/Login.cshtml b/cy_scdz/Views/Login/Login.cshtml
index 7e4b177..30dcf1c 100644
--- a/cy_scdz/Views/Login/Login.cshtml
+++ b/cy_scdz/Views/Login/Login.cshtml
@@ -71,7 +71,7 @@
               <li>
                 <span class="login-error">@Model.MSD.GetFirstError()</span>
                 <button type="submit" class="login-button" style="cursor:pointer">@Model.Localizer["Login.Login"]</button>
-                <wt:linkbutton window-title="@Model.Localizer["Login.Register"]" class="login-button" style="cursor:pointer" target="ButtonTargetEnum.Layer" window-width="500" window-height="500" url="/Login/Reg" text="@Model.Localizer["Login.Register"]" />
+                @* <wt:linkbutton window-title="@Model.Localizer["Login.Register"]" class="login-button" style="cursor:pointer" target="ButtonTargetEnum.Layer" window-width="500" window-height="500" url="/Login/Reg" text="@Model.Localizer["Login.Register"]" /> *@
               </li>
             </ul>
           </form>
diff --git a/cy_scdz/appsettings.json b/cy_scdz/appsettings.json
index eeb67fb..25181c8 100644
--- a/cy_scdz/appsettings.json
+++ b/cy_scdz/appsettings.json
@@ -21,14 +21,14 @@
   "Connections": [
     {
       "Key": "default",
-      "Value": "Server=(localdb)\\mssqllocaldb;Database=cy_scdz_db;Trusted_Connection=True;",
+      "Value": "Server=localhost\\SQLEXPRESS;Database=cy_scdz_db;Trusted_Connection=True;User ID=sa;Password=123456;",
       "DbContext": "DataContext",
       "DBType": "SqlServer" //DataBase, you can choose mysql,sqlserver,pgsql,sqlite,oracle
     }
   ],
   "CookiePre": "cy_scdz", //cookie prefix
   "IsQuickDebug": true, //is debug mode
-   "EnableTenant":  true, //鏄惁鍚姩澶氱鎴�
+   "EnableTenant":  false, //鏄惁鍚姩澶氱鎴�
    "CorsOptions": {
     "EnableAll": true
   },
diff --git a/cy_scdz/cy_scdz.csproj b/cy_scdz/cy_scdz.csproj
index 63523e1..cd2ebfc 100644
--- a/cy_scdz/cy_scdz.csproj
+++ b/cy_scdz/cy_scdz.csproj
@@ -22,7 +22,8 @@
    <ProjectReference Include="..\cy_scdz.Model\cy_scdz.Model.csproj" />
     <ProjectReference Include="..\cy_scdz.DataAccess\cy_scdz.DataAccess.csproj" />
     <ProjectReference Include="..\cy_scdz.ViewModel\cy_scdz.ViewModel.csproj" />
- </ItemGroup >
+    <ProjectReference Include="..\utils\utils.csproj" />
+ </ItemGroup>
 </Project>
 
 
diff --git a/cy_scdz/cy_scdz.csproj.user b/cy_scdz/cy_scdz.csproj.user
new file mode 100644
index 0000000..c0554b1
--- /dev/null
+++ b/cy_scdz/cy_scdz.csproj.user
@@ -0,0 +1,9 @@
+锘�<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Controller_SelectedScaffolderID>MvcControllerEmptyScaffolder</Controller_SelectedScaffolderID>
+    <Controller_SelectedScaffolderCategoryPath>root/Common/MVC/Controller</Controller_SelectedScaffolderCategoryPath>
+    <View_SelectedScaffolderID>RazorViewEmptyScaffolder</View_SelectedScaffolderID>
+    <View_SelectedScaffolderCategoryPath>root/Common/MVC/View</View_SelectedScaffolderCategoryPath>
+  </PropertyGroup>
+</Project>
\ No newline at end of file
diff --git a/utils/utils.csproj b/utils/utils.csproj
new file mode 100644
index 0000000..132c02c
--- /dev/null
+++ b/utils/utils.csproj
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+</Project>
diff --git a/utils/utilsFun.cs b/utils/utilsFun.cs
new file mode 100644
index 0000000..7cb4f99
--- /dev/null
+++ b/utils/utilsFun.cs
@@ -0,0 +1,27 @@
+锘縰sing System.Text;
+
+namespace utils
+{
+    /// <summary>
+    /// 閫氱敤鍑芥暟搴�
+    /// </summary>
+    public static class utilsFun
+    {
+        private const string ValidChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;:',.<>?/`~";
+
+        public static string GenerateRandomString(int length)
+        {
+            StringBuilder builder = new StringBuilder();
+            Random random = new Random();
+
+            for (int i = 0; i < length; i++)
+            {
+                int index = random.Next(ValidChars.Length);
+                char randomChar = ValidChars[index];
+                builder.Append(randomChar);
+            }
+
+            return builder.ToString();
+        }
+    }
+}
\ No newline at end of file

--
Gitblit v1.9.1