Forráskód Böngészése

优化前端字典,添加导入、导出功能。并提供示例

闫腾 2 éve
szülő
commit
6de5088def

+ 1 - 0
.gitignore

@@ -34,3 +34,4 @@ node_modules/
 /Web/package-lock.json
 .DS_Store
 /Web/public/config.js
+/Web/npminstall-debug.log

+ 5 - 0
Admin.NET/Admin.NET.Application/Admin.NET.Application.csproj

@@ -77,4 +77,9 @@
     </None>
   </ItemGroup>
 
+  <ItemGroup>
+    <Folder Include="Entity\" />
+    <Folder Include="Service\" />
+  </ItemGroup>
+
 </Project>

+ 193 - 0
Admin.NET/Admin.NET.Application/Demo/Dm_ApplyDemoService.cs

@@ -0,0 +1,193 @@
+using Admin.NET.Core.Service;
+using Admin.NET.Application.Const;
+using Admin.NET.Application.Entity;
+using Microsoft.AspNetCore.Http;
+using Magicodes.ExporterAndImporter.Core.Models;
+using Furion.Logging;
+namespace Admin.NET.Application;
+/// <summary>
+/// 申请示例服务
+/// </summary>
+[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
+public class Dm_ApplyDemoService : IDynamicApiController, ITransient
+{
+    private readonly SqlSugarRepository<Dm_ApplyDemo> _rep;
+    public Dm_ApplyDemoService(SqlSugarRepository<Dm_ApplyDemo> rep)
+    {
+        _rep = rep;
+    }
+
+    /// <summary>
+    /// 分页查询申请示例
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [HttpPost]
+    [ApiDescriptionSettings(Name = "Page")]
+    public async Task<SqlSugarPagedList<Dm_ApplyDemoOutput>> Page(Dm_ApplyDemoInput input)
+    {
+        ISugarQueryable<Dm_ApplyDemoOutput> query = Query(input).Select<Dm_ApplyDemoOutput>();
+        return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
+    }
+
+    /// <summary>
+    /// 查询
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    private ISugarQueryable<Dm_ApplyDemo> Query(Dm_ApplyDemoInput input)
+    {
+        var query = _rep.AsQueryable()
+            .WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), u =>
+                u.ApplyNO.Contains(input.SearchKey.Trim())
+                || u.Remark.Contains(input.SearchKey.Trim())
+            )
+            .WhereIF(input.OrgType > 0, u => u.OrgType == input.OrgType)
+            .WhereIF(!string.IsNullOrWhiteSpace(input.ApplyNO), u => u.ApplyNO.Contains(input.ApplyNO.Trim()))
+            .WhereIF(!string.IsNullOrWhiteSpace(input.Remark), u => u.Remark.Contains(input.Remark.Trim()))
+            ;
+        if (input.ApplicatDateRange != null && input.ApplicatDateRange.Count > 0)
+        {
+            DateTime? start = input.ApplicatDateRange[0];
+            query = query.WhereIF(start.HasValue, u => u.ApplicatDate > start);
+            if (input.ApplicatDateRange.Count > 1 && input.ApplicatDateRange[1].HasValue)
+            {
+                var end = input.ApplicatDateRange[1].Value.AddDays(1);
+                query = query.Where(u => u.ApplicatDate < end);
+            }
+        }
+
+        return query;
+    }
+
+    /// <summary>
+    /// 导出查询数据
+    /// </summary>
+    /// <returns></returns> 
+    [HttpPost]
+    public async Task<IActionResult> Export(Dm_ApplyDemoInput input)
+    { 
+        //如果想速度更快,推荐使用存储过程查询导出;如果想自定义导出样式,推荐使用模板。
+        return await CommonUtil.ExportExcelData<Dm_ApplyDemo, Dm_ApplyDemoInport>(Query(input));
+    }
+
+    /// <summary>
+    /// 增加申请示例
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [HttpPost]
+    [ApiDescriptionSettings(Name = "Add")]
+    public async Task<long> Add(AddDm_ApplyDemoInput input)
+    {
+        var entity = input.Adapt<Dm_ApplyDemo>();
+        await _rep.InsertAsync(entity);
+        return entity.Id;
+    }
+
+    /// <summary>
+    /// 删除申请示例
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [HttpPost]
+    [ApiDescriptionSettings(Name = "Delete")]
+    public async Task Delete(DeleteDm_ApplyDemoInput input)
+    {
+        var entity = await _rep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
+        await _rep.FakeDeleteAsync(entity);   //假删除
+        //await _rep.DeleteAsync(entity);   //真删除
+    }
+
+    /// <summary>
+    /// 更新申请示例
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [HttpPost]
+    [ApiDescriptionSettings(Name = "Update")]
+    public async Task Update(UpdateDm_ApplyDemoInput input)
+    {
+        var entity = input.Adapt<Dm_ApplyDemo>();
+        await _rep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
+    }
+
+    /// <summary>
+    /// 获取申请示例
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [HttpGet]
+    [ApiDescriptionSettings(Name = "Detail")]
+    public async Task<Dm_ApplyDemo> Detail([FromQuery] QueryByIdDm_ApplyDemoInput input)
+    {
+        return await _rep.GetFirstAsync(u => u.Id == input.Id);
+    }
+
+    /// <summary>
+    /// 获取申请示例列表
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [HttpGet]
+    [HttpPost]
+    [ApiDescriptionSettings(Name = "List")]
+    public async Task<List<Dm_ApplyDemoOutput>> List([FromQuery] Dm_ApplyDemoInput input)
+    {
+        ISugarQueryable<Dm_ApplyDemoOutput> query = Query(input).Select<Dm_ApplyDemoOutput>();
+        return await query.Select<Dm_ApplyDemoOutput>().ToListAsync();
+    }
+
+
+    /// <summary>
+    /// 导入数据
+    /// </summary>
+    /// <param name="file">Excel文件</param> 
+    /// <returns></returns> 
+    [AllowAnonymous]
+    public async Task<AdminResult<string>> Import([Required] IFormFile file)
+    {
+        if (file == null) throw Oops.Oh(ErrorCodeEnum.D8000);
+        var Importer = new Magicodes.ExporterAndImporter.Excel.ExcelImporter();
+        var importResult = await CommonUtil.ImportExcelData<Dm_ApplyDemoInport>(file);
+        string message=string.Empty;
+        if (importResult != null)
+        {
+            //TODO 自定义校验 
+            int errorCount = 0;
+
+            //导入数据转为对象实例 
+            var ysLs = new List<Dm_ApplyDemo>();
+            var ls = CommonUtil.ParseList<Dm_ApplyDemoInport, Dm_ApplyDemo>(importResult, (source, target) =>
+            {
+                if (target.Id == 0)
+                {
+                    return target;
+                }
+                else
+                {
+                    _rep.Context.Updateable(target).IgnoreColumns(true).ExecuteCommand();
+                    return null;
+                }
+            });
+            if (ls.Count > 0)
+            {
+                await _rep.Context.Insertable(ls).UseParameter().ExecuteCommandAsync();
+            }
+            _rep.Context.Ado.CommitTran();
+            message = $"导入总数:{importResult.Count},导入成功:{importResult.Count- errorCount},导入失败:{ errorCount}。";
+        }
+
+        var ret = new AdminResult<string>()
+        {
+            Code = 200,
+            Type = "success",
+            Message = message,
+            Result = message
+        };
+        return ret;
+    }
+
+
+}
+

+ 78 - 0
Admin.NET/Admin.NET.Application/Demo/Dto/Dm_ApplyDemoDto.cs

@@ -0,0 +1,78 @@
+namespace Admin.NET.Application;
+
+/// <summary>
+/// 申请示例输出参数
+/// </summary>
+public class Dm_ApplyDemoDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    public long Id { get; set; }
+
+    /// <summary>
+    /// 机构类型 详见字典类型 org_type
+    /// </summary>
+    public long? OrgType { get; set; }
+
+    /// <summary>
+    /// 申请号
+    /// </summary>
+    public string ApplyNO { get; set; }
+
+    /// <summary>
+    /// 申请时间
+    /// </summary>
+    public DateTime ApplicatDate { get; set; }
+
+    /// <summary>
+    /// 申请金额
+    /// </summary>
+    public decimal Amount { get; set; }
+
+    /// <summary>
+    /// 是否通知
+    /// </summary>
+    public bool IsNotice { get; set; }
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    public string Remark { get; set; }
+
+    /// <summary>
+    /// CreateTime
+    /// </summary>
+    public DateTime? CreateTime { get; set; }
+
+    /// <summary>
+    /// UpdateTime
+    /// </summary>
+    public DateTime? UpdateTime { get; set; }
+
+    /// <summary>
+    /// CreateUserId
+    /// </summary>
+    public long? CreateUserId { get; set; }
+
+    /// <summary>
+    /// CreateUserName
+    /// </summary>
+    public string? CreateUserName { get; set; }
+
+    /// <summary>
+    /// UpdateUserId
+    /// </summary>
+    public long? UpdateUserId { get; set; }
+
+    /// <summary>
+    /// UpdateUserName
+    /// </summary>
+    public string? UpdateUserName { get; set; }
+
+    /// <summary>
+    /// IsDelete
+    /// </summary>
+    public bool IsDelete { get; set; }
+
+}

+ 50 - 0
Admin.NET/Admin.NET.Application/Demo/Dto/Dm_ApplyDemoInport.cs

@@ -0,0 +1,50 @@
+using Magicodes.ExporterAndImporter.Core;
+
+namespace Admin.NET.Application;
+
+/// <summary>
+/// 导入对象
+/// </summary>
+public class Dm_ApplyDemoInport
+{
+    public long Id { get; set; }
+
+    /// <summary>
+    /// 机构类型
+    /// </summary>
+    [ImportDict(TargetPropName = "OrgType", TypeCode = "org_type")]
+    [Required(ErrorMessage = "机构类型为必填内容")] 
+    [ExporterHeader(DisplayName = "机构类型")]
+    [ImporterHeader(Name = "机构类型")]
+    public string OrgType { get; set; }
+
+    /// <summary>
+    /// 申请号
+    /// </summary>
+    [ImporterHeader(Name = "申请号")]
+    [ExporterHeader(DisplayName = "申请号")]
+    public string? ApplyNO { get; set; }
+     
+
+    /// <summary>
+    /// 申请时间
+    /// </summary>
+    [ImporterHeader(Name = "申请时间")]
+    [ExporterHeader(DisplayName = "申请时间")]
+    public DateTime? ApplicatDate { get; set; }
+
+    /// <summary>
+    /// 申请金额
+    /// </summary>
+    [ImporterHeader(Name = "申请金额")]
+    [ExporterHeader(DisplayName = "申请金额")]
+    public DateTime Amount { get; set; }
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    [ImporterHeader(Name = "备注")]
+    [ExporterHeader(DisplayName = "备注")]
+    public string Remark { get; set; }
+
+}

+ 193 - 0
Admin.NET/Admin.NET.Application/Demo/Dto/Dm_ApplyDemoInput.cs

@@ -0,0 +1,193 @@
+using Admin.NET.Core;
+using System.ComponentModel.DataAnnotations;
+
+namespace Admin.NET.Application;
+
+/// <summary>
+/// 申请示例基础输入参数
+/// </summary>
+public class Dm_ApplyDemoBaseInput
+{
+    /// <summary>
+    /// 机构类型 详见字典类型 org_type
+    /// </summary>
+    public virtual long? OrgType { get; set; }
+
+    /// <summary>
+    /// 申请号
+    /// </summary>
+    public virtual string ApplyNO { get; set; }
+
+    /// <summary>
+    /// 申请时间
+    /// </summary>
+    public virtual DateTime ApplicatDate { get; set; }
+
+    /// <summary>
+    /// 申请金额
+    /// </summary>
+    public virtual decimal Amount { get; set; }
+
+    /// <summary>
+    /// 是否通知
+    /// </summary>
+    public virtual bool IsNotice { get; set; }
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    public virtual string Remark { get; set; }
+
+    /// <summary>
+    /// CreateTime
+    /// </summary>
+    public virtual DateTime? CreateTime { get; set; }
+
+    /// <summary>
+    /// UpdateTime
+    /// </summary>
+    public virtual DateTime? UpdateTime { get; set; }
+
+    /// <summary>
+    /// CreateUserId
+    /// </summary>
+    public virtual long? CreateUserId { get; set; }
+
+    /// <summary>
+    /// CreateUserName
+    /// </summary>
+    public virtual string? CreateUserName { get; set; }
+
+    /// <summary>
+    /// UpdateUserId
+    /// </summary>
+    public virtual long? UpdateUserId { get; set; }
+
+    /// <summary>
+    /// UpdateUserName
+    /// </summary>
+    public virtual string? UpdateUserName { get; set; }
+
+    /// <summary>
+    /// IsDelete
+    /// </summary>
+    public virtual bool IsDelete { get; set; }
+
+}
+
+/// <summary>
+/// 申请示例分页查询输入参数
+/// </summary>
+public class Dm_ApplyDemoInput : BasePageInput
+{
+    /// <summary>
+    /// 关键字查询
+    /// </summary>
+    public string? SearchKey { get; set; }
+
+    /// <summary>
+    /// 机构类型 详见字典类型 org_type
+    /// </summary>
+    public long? OrgType { get; set; }
+
+    /// <summary>
+    /// 申请号
+    /// </summary>
+    public string ApplyNO { get; set; }
+
+    /// <summary>
+    /// 申请时间
+    /// </summary>
+    public DateTime ApplicatDate { get; set; }
+
+    /// <summary>
+    /// 申请金额
+    /// </summary>
+    public decimal Amount { get; set; }
+
+    /// <summary>
+    /// 是否通知
+    /// </summary>
+    public bool IsNotice { get; set; }
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    public string Remark { get; set; }
+
+    /// <summary>
+    /// 申请时间范围
+    /// </summary>
+    public List<DateTime?> ApplicatDateRange { get; set; }
+}
+
+    /// <summary>
+    /// 申请示例增加输入参数
+    /// </summary>
+    public class AddDm_ApplyDemoInput : Dm_ApplyDemoBaseInput
+    {
+        /// <summary>
+        /// ApplyNO
+        /// </summary>
+        [Required(ErrorMessage = "ApplyNO不能为空")]
+        public override string ApplyNO { get; set; }
+        
+        /// <summary>
+        /// ApplicatDate
+        /// </summary>
+        [Required(ErrorMessage = "ApplicatDate不能为空")]
+        public override DateTime ApplicatDate { get; set; }
+        
+        /// <summary>
+        /// Amount
+        /// </summary>
+        [Required(ErrorMessage = "Amount不能为空")]
+        public override decimal Amount { get; set; }
+        
+        /// <summary>
+        /// IsNotice
+        /// </summary>
+        [Required(ErrorMessage = "IsNotice不能为空")]
+        public override bool IsNotice { get; set; }
+        
+        /// <summary>
+        /// Remark
+        /// </summary>
+        [Required(ErrorMessage = "Remark不能为空")]
+        public override string Remark { get; set; }
+        
+        /// <summary>
+        /// IsDelete
+        /// </summary>
+        [Required(ErrorMessage = "IsDelete不能为空")]
+        public override bool IsDelete { get; set; }
+        
+    }
+
+    /// <summary>
+    /// 申请示例删除输入参数
+    /// </summary>
+    public class DeleteDm_ApplyDemoInput : BaseIdInput
+    {
+    }
+
+    /// <summary>
+    /// 申请示例更新输入参数
+    /// </summary>
+    public class UpdateDm_ApplyDemoInput : Dm_ApplyDemoBaseInput
+    {
+        /// <summary>
+        /// Id
+        /// </summary>
+        [Required(ErrorMessage = "Id不能为空")]
+        public long Id { get; set; }
+        
+    }
+
+    /// <summary>
+    /// 申请示例主键查询输入参数
+    /// </summary>
+    public class QueryByIdDm_ApplyDemoInput : DeleteDm_ApplyDemoInput
+    {
+
+    }

+ 89 - 0
Admin.NET/Admin.NET.Application/Demo/Dto/Dm_ApplyDemoOutput.cs

@@ -0,0 +1,89 @@
+using Magicodes.ExporterAndImporter.Core;
+using Newtonsoft.Json;
+
+namespace Admin.NET.Application;
+
+/// <summary>
+/// 申请示例输出参数
+/// </summary>
+public class Dm_ApplyDemoOutput
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    public long Id { get; set; }
+
+    /// <summary>
+    /// OrgType
+    /// </summary>
+    [ExporterHeader(DisplayName = "机构类型")]
+    public long? OrgType { get; set; }
+
+    /// <summary>
+    /// ApplyNO
+    /// </summary>
+    [ExporterHeader(DisplayName = "申请号")]
+    public string ApplyNO { get; set; }
+
+    /// <summary>
+    /// ApplicatDate
+    /// </summary>
+    [JsonConverter(typeof(ChinaDateTimeConverterDate))]
+    [ExporterHeader("申请时间",format:"yyyy-MM-dd")]
+    public DateTime ApplicatDate { get; set; }
+
+    /// <summary>
+    /// Amount
+    /// </summary>
+    [ExporterHeader(DisplayName = "申请金额")]
+    public decimal Amount { get; set; }
+    
+    /// <summary>
+    /// IsNotice
+    /// </summary>
+    public bool IsNotice { get; set; }
+
+    /// <summary>
+    /// Remark
+    /// </summary>
+    [ExporterHeader(DisplayName = "备注")]
+    public string Remark { get; set; }
+    
+    /// <summary>
+    /// CreateTime
+    /// </summary>
+    public DateTime? CreateTime { get; set; }
+    
+    /// <summary>
+    /// UpdateTime
+    /// </summary>
+    public DateTime? UpdateTime { get; set; }
+    
+    /// <summary>
+    /// CreateUserId
+    /// </summary>
+    public long? CreateUserId { get; set; }
+    
+    /// <summary>
+    /// CreateUserName
+    /// </summary>
+    public string? CreateUserName { get; set; }
+    
+    /// <summary>
+    /// UpdateUserId
+    /// </summary>
+    public long? UpdateUserId { get; set; }
+    
+    /// <summary>
+    /// UpdateUserName
+    /// </summary>
+    public string? UpdateUserName { get; set; }
+    
+    /// <summary>
+    /// IsDelete
+    /// </summary>
+    public bool IsDelete { get; set; }
+    
+    }
+ 
+

+ 63 - 0
Admin.NET/Admin.NET.Application/Demo/Entity/Dm_ApplyDemo.cs

@@ -0,0 +1,63 @@
+// 麻省理工学院许可证
+//
+// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司  联系电话/微信:18020030720  QQ:515096995
+//
+// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
+//
+// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
+// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
+
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Admin.NET.Application.Entity;
+/// <summary>
+/// 申请示例(测试对象)
+/// </summary>
+[SugarTable(null, "申请示例")]
+[SysTable]
+public class Dm_ApplyDemo : EntityBase
+{
+    /// <summary>
+    /// 机构类型 详见字典类型 org_type
+    /// </summary>
+    [SugarColumn(ColumnDescription = "机构类型")]
+    [Required]
+    public int? OrgType { get; set; }
+
+    /// <summary>
+    /// 申请号
+    /// </summary>
+    [SugarColumn(ColumnDescription = "申请号", Length = 32)]
+    [Required]
+    public string ApplyNO { get; set; } 
+
+    /// <summary>
+    /// 申请时间
+    /// </summary>
+    [SugarColumn(ColumnDescription = "申请时间")]
+    [JsonConverter(typeof(ChinaDateTimeConverter))]
+    public DateTime ApplicatDate { get; set; } = DateTime.Now;
+
+    /// <summary>
+    /// 申请金额
+    /// </summary>
+    [SugarColumn(ColumnDescription = "申请金额")]
+    public decimal Amount { get; set; }
+
+    /// <summary>
+    /// 是否通知
+    /// </summary>
+    [SugarColumn(ColumnDescription = "是否通知")]
+    public bool IsNotice { get; set; }
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    [SugarColumn(ColumnDescription = "备注", Length = 2000)]
+    public string Remark { get; set; }
+}

+ 20 - 0
Admin.NET/Admin.NET.Core/Attribute/ImportDictAttribute.cs

@@ -0,0 +1,20 @@
+namespace Admin.NET.Core;
+
+/// <summary>
+/// 属性字典配置
+/// </summary>
+[AttributeUsage(AttributeTargets.Property)]
+public class ImportDictAttribute : Attribute
+{
+    /// <summary>
+    /// 字典Code
+    /// </summary>
+    public string TypeCode { get; set; }
+
+    ///// <summary>
+    ///// 目标对象类型
+    ///// </summary>
+    //public Type TargetType { get; set; }
+
+    public string TargetPropName { get; set; }
+}

+ 124 - 0
Admin.NET/Admin.NET.Core/Extension/ObjectExtension.cs

@@ -331,4 +331,128 @@ public static partial class ObjectExtension
         var masks = mask.ToString().PadLeft(4, mask);
         return bankCard.Replace("(\\d{6})\\d{9}(\\d{4})", $"$1{masks}$2");
     }
+
+    /// <summary>
+    /// 将字符串转为值类型,如果没有得到或者错误返回为空
+    /// </summary>
+    /// <typeparam name="T">指定值类型</typeparam>
+    /// <param name="str">传入字符串</param>
+    /// <returns>可空值</returns>
+    public static Nullable<T> ParseTo<T>(this string str) where T : struct
+    {
+        try
+        {
+            if (!string.IsNullOrWhiteSpace(str))
+            {
+                MethodInfo method = typeof(T).GetMethod("Parse", new Type[] { typeof(string) });
+                if (method != null)
+                {
+                    T result = (T)method.Invoke(null, new string[] { str });
+                    return result;
+                }
+            }
+        }
+        catch
+        {
+        }
+        return null;
+    }
+
+    /// <summary>
+    /// 将字符串转为值类型,如果没有得到或者错误返回为空
+    /// </summary>
+    /// <typeparam name="T">指定值类型</typeparam>
+    /// <param name="str">传入字符串</param>
+    /// <param name="type">目标类型</param>
+    /// <returns>可空值</returns>
+    public static object ParseTo(this string str, Type type)
+    {
+        try
+        {
+            if (type.Name == "String")
+            {
+                return str;
+            }
+            if (!string.IsNullOrWhiteSpace(str))
+            {
+                var _type = type;
+                if (type.Name.StartsWith("Nullable"))
+                {
+                    _type = type.GetGenericArguments()[0];
+                }
+                MethodInfo method = _type.GetMethod("Parse", new Type[] { typeof(string) });
+                if (method != null)
+                {
+                    return method.Invoke(null, new string[] { str });
+                }
+            }
+        }
+        catch
+        {
+        }
+        return null;
+    }
+
+
+    /// <summary>
+    /// 将一个的对象属性值赋给另一个制定的对象属性, 只复制相同属性的
+    /// </summary>
+    /// <param name="src">原数据对象</param>
+    /// <param name="target">目标数据对象</param>
+    /// <param name="changeProperties">属性集,键为原属性,值为目标属性</param>
+    /// <param name="unChangeProperties">属性集,目标不修改的属性</param>
+    public static void CopyTo(object src, object target, Dictionary<string, string> changeProperties = null, string[] unChangeProperties = null)
+    {
+        if (src == null || target == null)
+            throw new ArgumentException("src == null || target == null ");
+
+        var SourceType = src.GetType();
+        var TargetType = target.GetType();
+
+        if (changeProperties == null || changeProperties.Count == 0)
+        {
+            var fields = TargetType.GetProperties();
+            changeProperties = fields.Select(m => m.Name).ToDictionary(m => m);
+        }
+
+        if (unChangeProperties == null || unChangeProperties.Length == 0)
+        {
+            foreach (var item in changeProperties)
+            {
+                var srcProperty = SourceType.GetProperty(item.Key);
+                if (srcProperty != null)
+                {
+                    var sourceVal = srcProperty
+                        .GetValue(src, null);
+
+                    var tarProperty = TargetType.GetProperty(item.Value);
+                    if (tarProperty != null)
+                    {
+                        tarProperty.SetValue(target, sourceVal, null);
+                    }
+                }
+            }
+        }
+        else
+        {
+            foreach (var item in changeProperties)
+            {
+                if (!unChangeProperties.Any(m => m == item.Value))
+                {
+                    var srcProperty = SourceType.GetProperty(item.Key);
+                    if (srcProperty != null)
+                    {
+                        var sourceVal = srcProperty
+                            .GetValue(src, null);
+
+                        var tarProperty = TargetType.GetProperty(item.Value);
+                        if (tarProperty != null)
+                        {
+                            tarProperty.SetValue(target, sourceVal, null);
+                        }
+                    }
+                }
+            }
+        }
+    }
 }

+ 94 - 0
Admin.NET/Admin.NET.Core/Service/Common/Dto/ProcDto.cs

@@ -0,0 +1,94 @@
+// 麻省理工学院许可证
+//
+// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司  联系电话/微信:18020030720  QQ:515096995
+//
+// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
+//
+// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
+// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
+
+using Magicodes.ExporterAndImporter.Core.Filters;
+using Magicodes.ExporterAndImporter.Core.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+namespace Admin.NET.Core.Service;
+
+/// <summary>
+/// 基础存储过程输入类
+/// </summary> 
+public class BaseProcInput
+{
+    /// <summary>
+    /// ProcId
+    /// </summary>
+    public string ProcId { get; set; }
+
+    /// <summary>
+    /// 数据库配置ID
+    /// </summary>
+    public string ConfigId { get; set; }
+
+    /// <summary>
+    /// 存储过程输入参数
+    /// </summary>
+    /// <example>{"id":"351060822794565"}</example>
+    public Dictionary<string, object> ProcParams { get; set; }
+}
+
+/// <summary>
+/// 带表头名称存储过程输入类
+/// </summary>
+public class ExportProcByTMPInput : BaseProcInput
+{
+    /// <summary>
+    /// 模板名称
+    /// </summary>
+    public string Template { get; set; }
+}
+
+/// <summary>
+/// 带表头名称存储过程输入类
+/// </summary>
+public class ExportProcInput : BaseProcInput
+{
+    public Dictionary<string, string> EHeader { get; set; }
+}
+/// <summary>
+/// 指定导出类名(有排序)存储过程输入类
+/// </summary>
+public class ExportProcInput2 : BaseProcInput
+{
+    public List<string> EHeader { get; set; }
+}
+
+/// <summary>
+/// 前端指定列
+/// </summary>
+public class ProcExporterHeaderFilter : IExporterHeaderFilter
+{
+    private Dictionary<string, Tuple<string, int>> _includeHeader;
+    public ProcExporterHeaderFilter(Dictionary<string, Tuple<string, int>> includeHeader)
+    {
+        _includeHeader = includeHeader;
+    }
+    public ExporterHeaderInfo Filter(ExporterHeaderInfo exporterHeaderInfo)
+    {
+        if (_includeHeader != null && _includeHeader.Count > 0)
+        {
+            var key = exporterHeaderInfo.PropertyName.ToUpper();
+            if (_includeHeader.ContainsKey(key))
+            {
+                exporterHeaderInfo.DisplayName = _includeHeader[key].Item1;
+                return exporterHeaderInfo;
+            }
+            else
+            {
+                exporterHeaderInfo.ExporterHeaderAttribute.Hidden = true;
+            }
+        }
+        return exporterHeaderInfo;
+    }
+}

+ 118 - 0
Admin.NET/Admin.NET.Core/Service/Common/ProcService.cs

@@ -0,0 +1,118 @@
+// 麻省理工学院许可证
+//
+// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司  联系电话/微信:18020030720  QQ:515096995
+//
+// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
+//
+// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
+// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Admin.NET.Core.Service;
+
+/// <summary>
+/// 存储过程服务
+/// 适用于导出、图表查询
+/// </summary>
+public class ProcService : IDynamicApiController, ITransient
+{
+
+    /// <summary>
+    /// Post导出存储过程数据,指定导出列,没有指定的字段会被隐藏
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet]
+    [HttpPost]
+    public async Task<IActionResult> PocExport2(ExportProcInput input)
+    {
+        ISqlSugarClient _db = App.GetService<ISqlSugarClient>();
+        var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
+        var rs = await db.Ado.UseStoredProcedure()
+                .GetDataTableAsync(input.ProcId, input.ProcParams);
+
+        var excelExporter = new Magicodes.ExporterAndImporter.Excel.ExcelExporter();
+        Dictionary<string, Tuple<string, int>> headers = new Dictionary<string, Tuple<string, int>>();
+        var i = 1;
+        foreach (var val in input.EHeader)
+        {
+            headers.Add(val.Key.ToUpper(), new Tuple<string, int>(val.Value, i));
+            i++;
+        }
+        var da = await excelExporter.ExportAsByteArray(rs, new ProcExporterHeaderFilter(headers));
+
+        return new FileContentResult(da, "application/octet-stream") { FileDownloadName = input.ProcId + ".xlsx" };
+    }
+
+    /// <summary>
+    /// 根据模板导出存储过程数据
+    /// </summary>
+    /// <returns></returns> 
+    [HttpGet]
+    [HttpPost]
+    public async Task<IActionResult> PocExport(ExportProcByTMPInput input)
+    {
+        ISqlSugarClient _db = App.GetService<ISqlSugarClient>();
+        var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
+        var rs = await db.Ado.UseStoredProcedure()
+                .GetDataTableAsync(input.ProcId, input.ProcParams);
+
+        var excelExporter = new Magicodes.ExporterAndImporter.Excel.ExcelExporter();
+
+        string template = AppDomain.CurrentDomain.BaseDirectory + "/wwwroot/Template/" + input.Template + ".xlsx";
+        var bs = await excelExporter.ExportBytesByTemplate(rs, template);
+        return new FileContentResult(bs, "application/octet-stream") { FileDownloadName = input.ProcId + ".xlsx" };
+    }
+    /// <summary>
+    /// 读取存储过程返回表
+    /// 注意Oracle,达梦参数顺序不能错
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns> 
+    [HttpPost]
+    public async Task<DataTable> ProcTable(BaseProcInput input)
+    { 
+        ISqlSugarClient _db = App.GetService<ISqlSugarClient>();
+        var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
+        return await db.Ado.UseStoredProcedure()
+                .GetDataTableAsync(input.ProcId, input.ProcParams);
+    }
+
+    /// <summary>
+    /// 读取存储过程返回数据集
+    /// 注意Oracle,达梦参数顺序不能错;Oracle 返回table、table1,其他返回table1、table2
+    /// 适用于报表、复杂详细页面等
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [HttpPost]
+    public async Task<DataSet> CommonDataSet(BaseProcInput input)
+    {
+        ISqlSugarClient _db = App.GetService<ISqlSugarClient>();
+        var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
+        return await db.Ado.UseStoredProcedure()
+            .GetDataSetAllAsync(input.ProcId, input.ProcParams);
+    }
+    /*
+     * 
+    //根据配置表读取对映存储过程
+    public async Task<DataTable> ProcEnitybyConfig(BaseProcInput input)
+    {
+        string key = "ProcConfig";
+        var ds = _sysCacheService.Get<Dictionary<string, string>>(key);
+        if (ds == null || ds.Count == 0 || !ds.ContainsKey(input.ProcId))
+        {
+            var datas = await _db.Queryable<ProcConfig>().ToListAsync();
+            ds = datas.ToDictionary(m => m.ProcId, m => m.ProcName);
+            _sysCacheService.Set(key, ds);
+        }
+        string procName = ds[input.ProcId];
+        return await _db.Ado.UseStoredProcedure()
+            .GetDataTableAsync(procName, input.ProcParams);
+    }
+    */
+}

+ 10 - 7
Admin.NET/Admin.NET.Core/Service/Dict/SysDictTypeService.cs

@@ -150,20 +150,23 @@ public class SysDictTypeService : IDynamicApiController, ITransient
         await _sysDictTypeRep.UpdateAsync(dictType);
     }
 
+
     /// <summary>
     /// 获取所有字典集合
     /// </summary>
     /// <returns></returns>
     [AllowAnonymous]
     [DisplayName("获取所有字典集合")]
-    public async Task<List<SysDictType>> GetAllDictList()
+    public async Task<dynamic> GetAllDictList()
     {
-        var dictList = await _sysDictTypeRep.AsQueryable()
-            .Includes(u => u.Children)
-            .OrderBy(u => new { u.OrderNo, u.Code })
+        var ds = await _sysDictTypeRep.AsQueryable()
+            .InnerJoin<SysDictData>((m, n) => m.Id == n.DictTypeId)
+            .Where((m, n) => m.IsDelete == false && n.IsDelete == false && n.Status == StatusEnum.Enable)
+            .Select((m, n) => new { TypeCode = m.Code,  n.Code, n.Value, n.Remark, n.OrderNo,n.TagType })
             .ToListAsync();
-        // 字典数据项排序
-        dictList.ForEach(u => u.Children = u.Children.OrderBy(c => c.OrderNo).ThenBy(c => c.Code).ToList());
-        return dictList;
+        return ds
+            .OrderBy(s => s.OrderNo).GroupBy(m => m.TypeCode)
+            .ToDictionary(m => m.Key, m => m);
     }
+
 }

+ 100 - 0
Admin.NET/Admin.NET.Core/Util/ChinaDateTimeConverter.cs

@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json.Converters;
+using Newtonsoft.Json;
+
+namespace Admin.NET.Core
+{
+    /// <summary>
+    /// JSON时间序列化yyyy-MM-dd HH:mm:ss
+    /// </summary>
+    public class ChinaDateTimeConverter : DateTimeConverterBase
+    {
+        private static IsoDateTimeConverter dtConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
+        /// <summary>
+        /// ReadJson
+        /// </summary>
+        /// <param name="reader"></param>
+        /// <param name="objectType"></param>
+        /// <param name="existingValue"></param>
+        /// <param name="serializer"></param>
+        /// <returns></returns>
+        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+        {
+            return dtConverter.ReadJson(reader, objectType, existingValue, serializer);
+        }
+        /// <summary>
+        /// WriteJson
+        /// </summary>
+        /// <param name="writer"></param>
+        /// <param name="value"></param>
+        /// <param name="serializer"></param>
+        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+        {
+            dtConverter.WriteJson(writer, value, serializer);
+        }
+    }
+
+    /// <summary>
+    /// JSON时间序列化yyyy-MM-dd HH:mm
+    /// </summary>
+    public class ChinaDateTimeConverterHH : DateTimeConverterBase
+    {
+        private static IsoDateTimeConverter dtConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm" };
+        /// <summary>
+        /// ReadJson
+        /// </summary>
+        /// <param name="reader"></param>
+        /// <param name="objectType"></param>
+        /// <param name="existingValue"></param>
+        /// <param name="serializer"></param>
+        /// <returns></returns>
+        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+        {
+            return dtConverter.ReadJson(reader, objectType, existingValue, serializer);
+        }
+        /// <summary>
+        /// WriteJson
+        /// </summary>
+        /// <param name="writer"></param>
+        /// <param name="value"></param>
+        /// <param name="serializer"></param>
+        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+        {
+            dtConverter.WriteJson(writer, value, serializer);
+        }
+    }
+
+    /// <summary>
+    /// JSON时间序列化yyyy-MM-dd
+    /// </summary>
+    public class ChinaDateTimeConverterDate : DateTimeConverterBase
+    {
+        private static IsoDateTimeConverter dtConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd" };
+        /// <summary>
+        /// ReadJson
+        /// </summary>
+        /// <param name="reader"></param>
+        /// <param name="objectType"></param>
+        /// <param name="existingValue"></param>
+        /// <param name="serializer"></param>
+        /// <returns></returns>
+        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+        {
+            return dtConverter.ReadJson(reader, objectType, existingValue, serializer);
+        }
+        /// <summary>
+        /// WriteJson
+        /// </summary>
+        /// <param name="writer"></param>
+        /// <param name="value"></param>
+        /// <param name="serializer"></param>
+        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+        {
+            dtConverter.WriteJson(writer, value, serializer);
+        }
+    }
+}

+ 278 - 21
Admin.NET/Admin.NET.Core/Util/CommonUtil.cs

@@ -7,9 +7,13 @@
 // 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
 // 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
 
+using Magicodes.ExporterAndImporter.Core.Models;
+using Nest;
+using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
 using System.Xml;
 using System.Xml.Linq;
 using System.Xml.Serialization;
+using static SKIT.FlurlHttpClient.Wechat.Api.Models.CgibinTagsMembersGetBlackListResponse.Types;
 
 namespace Admin.NET.Core;
 
@@ -100,39 +104,292 @@ public static class CommonUtil
     /// <summary>
     /// 导出模板Excel
     /// </summary>
-    /// <param name="fileName"></param>
-    /// <param name="fileDto"></param>
     /// <returns></returns>
-    public static async Task<IActionResult> ExportExcelTemplate(string fileName, dynamic fileDto)
-    {
-        fileName = $"{fileName}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx";
-
+    public static async Task<IActionResult> ExportExcelTemplate<T>() where T : class,new()
+    { 
         IImporter importer = new ExcelImporter();
-        MethodInfo generateTemplateMethod = importer.GetType().GetMethod("GenerateTemplate");
-        MethodInfo closedGenerateTemplateMethod = generateTemplateMethod.MakeGenericMethod(fileDto.GetType());
-        var res = await (Task<dynamic>)closedGenerateTemplateMethod.Invoke(importer, new object[] { Path.Combine(App.WebHostEnvironment.WebRootPath, fileName) });
+        var res=await importer.GenerateTemplateBytes<T>();  
 
-        return new FileStreamResult(new FileStream(res.FileName, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName };
+        return new FileContentResult(res, "application/octet-stream") { FileDownloadName = typeof(T).Name+".xlsx" };
     }
 
     /// <summary>
-    /// 导入数据Excel
+    /// 导出数据excel
     /// </summary>
-    /// <param name="file"></param>
-    /// <param name="dataDto"></param>
     /// <returns></returns>
-    public static async Task<dynamic> ImportExcelData([Required] IFormFile file, dynamic dataDto)
+    public static async Task<IActionResult> ExportExcelData<T>(ICollection<T> data) where T : class, new()
     {
-        var newFile = await App.GetRequiredService<SysFileService>().UploadFile(file, "");
-        var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, newFile.FilePath, newFile.Name);
+        var export = new ExcelExporter();
+        var res = await export.ExportAsByteArray<T>(data);
+
+        return new FileContentResult(res, "application/octet-stream") { FileDownloadName = typeof(T).Name + ".xlsx" };
+    }
 
+    /// <summary>
+    /// 导出数据excel,包括字典转换
+    /// </summary>
+    /// <returns></returns>
+    public static async Task<IActionResult> ExportExcelData<TSource, TTarget>(ISugarQueryable<TSource> query, Func<TSource, TTarget, TTarget> action = null) 
+        where TSource : class, new() where TTarget : class, new ()
+    {
+        var PropMappings = GetExportPropertMap< TSource, TTarget >(); 
+        var data = query.ToList();
+        //相同属性复制值,字典值转换
+        var result = new List<TTarget>();
+        foreach (var item in data)
+        {
+            var newData = new TTarget();
+            foreach (var dict in PropMappings)
+            {
+                var targeProp = dict.Value.Item3;
+                if (targeProp != null)
+                {
+                    var propertyInfo = dict.Value.Item2;
+                    var sourceVal = propertyInfo.GetValue(item, null);
+                    if (sourceVal == null)
+                    {
+                        continue;
+                    }
+
+                    var map = dict.Value.Item1;
+                    if (map != null && map.ContainsKey(sourceVal))
+                    {
+                        var newVal = map[sourceVal];
+                        targeProp.SetValue(newData, newVal);
+                    }
+                    else
+                    {
+                        if (targeProp.PropertyType.FullName == propertyInfo.PropertyType.FullName)
+                        {
+                            targeProp.SetValue(newData, sourceVal);
+                        }
+                        else
+                        {
+                            var newVal = sourceVal.ToString().ParseTo(targeProp.PropertyType);
+                            targeProp.SetValue(newData, newVal);
+                        }
+                    }
+                }
+                if (action != null)
+                {
+                    newData = action(item, newData);
+                }
+            } 
+            result.Add(newData);
+        } 
+        var export = new ExcelExporter();
+        var res = await export.ExportAsByteArray(result);
+
+        return new FileContentResult(res, "application/octet-stream") { FileDownloadName = typeof(TTarget).Name + ".xlsx" };
+    }
+
+    /// <summary>
+    /// 导入数据Excel
+    /// </summary>
+    /// <param name="file"></param> 
+    /// <returns></returns>
+    public static async Task<ICollection<T>> ImportExcelData<T>([Required] IFormFile file) where T : class, new()
+    {  
         IImporter importer = new ExcelImporter();
-        MethodInfo importMethod = importer.GetType().GetMethod("Import");
-        MethodInfo closedImportMethod = importMethod.MakeGenericMethod(dataDto.GetType());
-        var res = await (Task<dynamic>)closedImportMethod.Invoke(importer, new object[] { filePath });
-        if (res == null || res.Exception != null)
-            throw Oops.Oh("导入异常:" + res.Exception);
+        var res = await importer.Import<T>(file.OpenReadStream());
+        string message = string.Empty;
+        if (res.HasError)
+        {
+            if (res.Exception != null)
+                message += $"\r\n{res.Exception.Message}";
+            foreach (DataRowErrorInfo drErrorInfo in res.RowErrors)
+            {
+                int rowNum = drErrorInfo.RowIndex;
+                foreach (var item in drErrorInfo.FieldErrors)
+                    message += $"\r\n{item.Key}:{item.Value}(文件第{drErrorInfo.RowIndex}行)";
+            }
+            message += "字段缺失:" + string.Join(",", res.TemplateErrors.Select(m => m.RequireColumnName).ToList());
 
+            throw Oops.Oh("导入异常:" + message);
+        }
         return res.Data;
     }
+
+    //例:List<Dm_ApplyDemo> ls = CommonUtil.ParseList<Dm_ApplyDemoInport, Dm_ApplyDemo>(importResult.Data);
+    /// <summary>
+    /// 对象转换 含字典转换
+    /// </summary>
+    /// <typeparam name="TSource"></typeparam>
+    /// <typeparam name="TTarget"></typeparam>
+    /// <param name="data"></param>
+    /// <param name="action"></param>
+    /// <returns></returns>
+    public static List<TTarget> ParseList<TSource, TTarget>(IEnumerable<TSource> data, Func<TSource, TTarget, TTarget> action=null) where TTarget : new()
+    {
+        Dictionary<string, Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>> PropMappings = GetImportPropertMap<TSource, TTarget>();
+        //相同属性复制值,字典值转换
+        var result = new List<TTarget>();
+        foreach (var item in data)
+        {
+            var newData = new TTarget();
+            foreach (var dict in PropMappings)
+            {
+                var targeProp = dict.Value.Item3;
+                if (targeProp != null)
+                {
+                    var propertyInfo = dict.Value.Item2;
+                    var sourceVal = propertyInfo.GetValue(item, null);
+                    if (sourceVal == null)
+                    {
+                        continue;
+                    }
+
+                    var map = dict.Value.Item1;
+                    if (map != null && map.ContainsKey(sourceVal.ToString()))
+                    {
+                        var newVal = map[sourceVal.ToString()];
+                        targeProp.SetValue(newData, newVal);
+                    }
+                    else
+                    {
+                        if (targeProp.PropertyType.FullName == propertyInfo.PropertyType.FullName)
+                        {
+                            targeProp.SetValue(newData, sourceVal);
+                        }
+                        else
+                        {
+                            var newVal = sourceVal.ToString().ParseTo(targeProp.PropertyType);
+                            targeProp.SetValue(newData, newVal);
+                        }
+                    }
+                }
+            }
+            if (action != null)
+            {
+                newData = action(item, newData);
+            }
+            if (newData != null)
+                result.Add(newData);
+        }
+        return result;
+    }
+
+
+    /// <summary>
+    /// 获取导入属性映射       
+    /// </summary>
+    /// <typeparam name="TSource"></typeparam>
+    /// <typeparam name="TTarget"></typeparam>
+    /// <returns>整理导入对象的 属性名称, 字典数据,原属性信息,目标属性信息 </returns>
+    private static Dictionary<string, Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>> GetImportPropertMap<TSource, TTarget>() where TTarget : new()
+    {
+        var dictService = App.GetService<SqlSugarRepository<SysDictData>>();
+        //整理导入对象的 属性名称,<字典数据,原属性信息,目标属性信息>
+        Dictionary<string, Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>> PropMappings =
+        new Dictionary<string, Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>>();
+
+        var TSourceProps = typeof(TSource).GetProperties().ToList();
+        var TTargetProps = typeof(TTarget).GetProperties().ToDictionary(m => m.Name);
+
+        foreach (var propertyInfo in TSourceProps)
+        {
+            var attrs = propertyInfo.GetCustomAttribute<ImportDictAttribute>();
+            if (attrs != null && !string.IsNullOrWhiteSpace(attrs.TypeCode))
+            {
+                var targetProp = TTargetProps[attrs.TargetPropName];
+
+                var MappingValues = dictService.Context.Queryable<SysDictType, SysDictData>((a, b) =>
+                    new JoinQueryInfos(JoinType.Inner, a.Id == b.DictTypeId))
+                    .Where(a => a.Code == attrs.TypeCode)
+                    .Where((a, b) => a.Status == StatusEnum.Enable && b.Status == StatusEnum.Enable)
+                    .Select((a, b) => new
+                    {
+                        Label = b.Value,
+                        Value = b.Code
+                    }).ToList()
+                    .ToDictionary(m => m.Label, m => m.Value.ParseTo(targetProp.PropertyType));
+                PropMappings.Add(propertyInfo.Name, new Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>(
+                    MappingValues, propertyInfo, targetProp
+                    ));
+            }
+            else
+            {
+                PropMappings.Add(propertyInfo.Name, new Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>(
+                    null, propertyInfo, TTargetProps.ContainsKey(propertyInfo.Name) ? TTargetProps[propertyInfo.Name] : null
+                    ));
+            }
+        }
+
+        return PropMappings;
+    }
+
+
+
+    /// <summary>
+    /// 获取导出属性映射       
+    /// </summary>
+    /// <typeparam name="TSource"></typeparam>
+    /// <typeparam name="TTarget"></typeparam>
+    /// <returns>整理导入对象的 属性名称, 字典数据,原属性信息,目标属性信息 </returns>
+    private static Dictionary<string, Tuple<Dictionary<object,string>, PropertyInfo, PropertyInfo>> GetExportPropertMap<TSource, TTarget>() where TTarget : new()
+    {
+        var dictService = App.GetService<SqlSugarRepository<SysDictData>>();
+        //整理导入对象的 属性名称,<字典数据,原属性信息,目标属性信息>
+        Dictionary<string, Tuple<Dictionary<object,string>, PropertyInfo, PropertyInfo>> PropMappings =
+        new Dictionary<string, Tuple<Dictionary<object,string>, PropertyInfo, PropertyInfo>>();
+
+        var TargetProps = typeof(TTarget).GetProperties().ToList();
+        var SourceProps = typeof(TSource).GetProperties().ToDictionary(m => m.Name);
+
+        foreach (var propertyInfo in TargetProps)
+        {
+            var attrs = propertyInfo.GetCustomAttribute<ImportDictAttribute>();
+            if (attrs != null && !string.IsNullOrWhiteSpace(attrs.TypeCode))
+            {
+                var targetProp = SourceProps[attrs.TargetPropName];
+
+                var MappingValues = dictService.Context.Queryable<SysDictType, SysDictData>((a, b) =>
+                    new JoinQueryInfos(JoinType.Inner, a.Id == b.DictTypeId))
+                    .Where(a => a.Code == attrs.TypeCode)
+                    .Where((a, b) => a.Status == StatusEnum.Enable && b.Status == StatusEnum.Enable)
+                    .Select((a, b) => new
+                    {
+                        Label = b.Value,
+                        Value = b.Code
+                    }).ToList()
+                    .ToDictionary(m => m.Value.ParseTo(targetProp.PropertyType), m => m.Label);
+                PropMappings.Add(propertyInfo.Name, new Tuple<Dictionary<object,string>, PropertyInfo, PropertyInfo>(
+                    MappingValues, targetProp, propertyInfo
+                    ));
+            }
+            else
+            {
+                PropMappings.Add(propertyInfo.Name, new Tuple<Dictionary<object,string>, PropertyInfo, PropertyInfo>(
+                    null, SourceProps.ContainsKey(propertyInfo.Name) ? SourceProps[propertyInfo.Name] : null, propertyInfo
+                    ));
+            }
+        }
+
+        return PropMappings;
+    }
+
+
+    /// <summary>
+    /// 获取属性映射       
+    /// </summary>
+    /// <typeparam name="TSource"></typeparam>
+    /// <typeparam name="TTarget"></typeparam>
+    /// <returns>整理导入对象的 属性名称, 字典数据,原属性信息,目标属性信息 </returns>
+    private static Dictionary<string, Tuple<string, string>> GetExportDicttMap<  TTarget>() where TTarget : new()
+    {
+        var dictService = App.GetService<SqlSugarRepository<SysDictData>>();
+        //整理导入对象的 属性名称,目标属性名,字典Code
+        Dictionary<string, Tuple<string, string>> PropMappings = new Dictionary<string, Tuple<string, string>>(); 
+        var TTargetProps = typeof(TTarget).GetProperties(); 
+        foreach (var propertyInfo in TTargetProps)
+        {
+            var attrs = propertyInfo.GetCustomAttribute<ImportDictAttribute>();
+            if (attrs != null && !string.IsNullOrWhiteSpace(attrs.TypeCode))
+            { 
+                PropMappings.Add(propertyInfo.Name, new Tuple<string, string>(  attrs.TargetPropName,attrs.TypeCode  )); 
+            } 
+        }
+
+        return PropMappings;
+    }
 }

+ 60 - 0
Web/src/api/main/dm_ApplyDemo.ts

@@ -0,0 +1,60 @@
+import request from '/@/utils/request';
+import { downloadByData } from '/@/utils/download';
+enum Api {
+	AddDm_ApplyDemo = '/api/dm_ApplyDemo/add',
+	DeleteDm_ApplyDemo = '/api/dm_ApplyDemo/delete',
+	UpdateDm_ApplyDemo = '/api/dm_ApplyDemo/update',
+	PageDm_ApplyDemo = '/api/dm_ApplyDemo/page',
+	DetailDm_ApplyDemo = '/api/dm_ApplyDemo/detail',
+}
+
+// 增加申请示例
+export const addDm_ApplyDemo = (params?: any) =>
+	request({
+		url: Api.AddDm_ApplyDemo,
+		method: 'post',
+		data: params,
+	});
+
+// 删除申请示例
+export const deleteDm_ApplyDemo = (params?: any) =>
+	request({
+		url: Api.DeleteDm_ApplyDemo,
+		method: 'post',
+		data: params,
+	});
+
+// 编辑申请示例
+export const updateDm_ApplyDemo = (params?: any) =>
+	request({
+		url: Api.UpdateDm_ApplyDemo,
+		method: 'post',
+		data: params,
+	});
+
+// 分页查询申请示例
+export const pageDm_ApplyDemo = (params?: any) =>
+	request({
+		url: Api.PageDm_ApplyDemo,
+		method: 'post',
+		data: params,
+	});
+
+// 详情申请示例
+export const detailDm_ApplyDemo = (id: any) =>
+	request({
+		url: Api.DetailDm_ApplyDemo,
+		method: 'get',
+		data: { id },
+	});
+
+//导出数据
+export const exportDm_ApplyDemo = (params?: any) =>
+	request({
+		url: '/api/dm_ApplyDemo/export',
+		method: 'post',
+		data: params,
+		responseType: 'arraybuffer',
+	}).then((res) => {
+		downloadByData(res.data, 'export.xlsx', 'application/octet-stream');
+	});

+ 87 - 0
Web/src/components/importButton/index.vue

@@ -0,0 +1,87 @@
+<template>
+	<input class="el-upload__input" ref="reffile" name="file" @change="fileChange($event)" :accept="$props.accept" type="file">
+	<el-button  icon="ele-Upload" @click="onClick">{{$props.btnText}}</el-button>
+</template>
+
+<script setup lang="ts" name="ImportButton">
+
+import { reactive, ref, onMounted, watch } from 'vue';
+import request,{request2} from '/@/utils/request';
+import { ElMessage } from 'element-plus';
+
+// 定义父组件传过来的值
+const props = defineProps({
+	accept: {
+		type: String, 
+	},
+	param: {
+		type: Object,
+		default: () => {},
+	},
+	url: {
+		type: String, 
+	}, 
+	btnText: {
+		type: String, 
+	},
+});
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['success', 'error']);
+const reffile=ref();
+// 定义变量内容 
+const state = reactive({
+	form: {} as any,
+	});
+watch(
+	() => props.param,
+	(value) => {
+		if (value) {
+			state.form = Object.assign({}, { ...value });
+		}
+	},
+	{
+		immediate: true,
+		deep: true,
+	}
+);
+
+// 上传文件
+const onClick = () => {
+	reffile.value.click();
+};
+function fileChange(event) { 
+	if(!event.currentTarget.files 
+	|| event.currentTarget.files.length==0){
+		return;
+	}
+	var file=event.currentTarget.files[0];
+	let formData = new FormData()
+  	formData.append('file', file)
+	for (const key in  state.form) {
+		const element = state.form[key];
+		formData.append(key, element)
+	}
+	request2({
+		url: props.url,
+		method: 'post',
+		data:formData,
+		headers: {
+			'Content-Type': 'multipart/form-data'
+		},
+	}).then((res)=>{
+		console.log(res);
+		ElMessage.success(res);
+		reffile.value.files=null;
+		emit('success',res)
+	}).catch((res)=>{ 
+		console.log('上传错误',res)
+		alert('上传错误')
+	});
+}
+// 页面加载时
+onMounted(() => {
+	// initFormField();
+});
+</script>
+ 

+ 69 - 13
Web/src/stores/userInfo.ts

@@ -14,7 +14,8 @@ export const useUserInfo = defineStore('userInfo', {
 	state: (): UserInfosState => ({
 		userInfos: {} as any,
 		constList: [] as any,
-		dictList: [] as any,
+		dictList: {} as any,
+		dictListInt: {} as any,
 	}),
 	getters: {
 		// // 获取系统常量列表
@@ -46,13 +47,16 @@ export const useUserInfo = defineStore('userInfo', {
 		},
 		async setDictList() {
 			// 存储字典信息到浏览器缓存
-			if (Session.get('dictList')) {
-				this.dictList = Session.get('dictList');
-			} else {
-				const dictList = <any[]>await this.getAllDictList();
-				Session.set('dictList', dictList);
-				this.dictList = dictList;
-			}
+			var res= await getAPI(SysDictTypeApi)
+						.apiSysDictTypeAllDictListGet();
+			this.dictList=res.data.result ;
+			// if (Session.get('dictList')) {
+			// 	this.dictList = Session.get('dictList');
+			// } else {
+			//	const dictList = <any[]>await this.getAllDictList();
+			//	Session.set('dictList', dictList);
+			//	this.dictList = dictList;
+			// }
 		},
 		// 获取当前用户信息
 		getApiUserInfo() {
@@ -115,12 +119,64 @@ export const useUserInfo = defineStore('userInfo', {
 		// 获取字典集合
 		getAllDictList() {
 			return new Promise((resolve) => {
-				getAPI(SysDictTypeApi)
-					.apiSysDictTypeAllDictListGet()
-					.then(async (res: any) => {
-						resolve(res.data.result ?? []);
-					});
+				if (this.dictList) {
+					resolve(this.dictList);
+				} else {
+					getAPI(SysDictTypeApi)
+						.apiSysDictTypeAllDictListGet()
+						.then((res: any) => {
+							resolve(res.data.result ?? []);
+						});
+				}
 			});
 		},
+		
+		//根据字典类型和值取字典项
+		getDictItemByVal( typePCode: string,val: string) {
+			const _val= val.toString();
+			const ds = this.getDictDatasByCode(typePCode);
+			for (let index = 0; index < ds.length; index++) {
+				const element = ds[index];
+				if (element.code == _val) {
+					return element;
+				}
+			}
+			return {};
+		},
+
+		//根据字典类型和值取描述
+		getDictLabelByVal( typePCode: string,val: string) {
+			return this.getDictItemByVal(typePCode,val).value;
+		},
+		//根据字典类型和描述取值
+		getDictValByLabel(typePCode: string,label: string) {
+			const ds = this.getDictDatasByCode(typePCode);
+			for (let index = 0; index < ds.length; index++) {
+				const element = ds[index];
+				if (element.value == label) {
+					return element.code;
+				}
+			}
+		},
+		//根据字典类型字典数据
+		getDictDatasByCode(dictTypeCode: string) {
+			return this.dictList[dictTypeCode] || [];
+		},
+		
+		//根据字典类型字典数据,值转为数字类型
+		getDictIntDatasByCode(dictTypeCode: string) {
+			var ds=this.dictListInt[dictTypeCode];
+			if(ds){
+				return ds;
+			}else{
+				ds=this.dictList[dictTypeCode]
+				.map((element: { code: any; }) => {
+					element.code= element.code-0;
+					return element;
+				});
+				this.dictListInt[dictTypeCode]=ds;
+				return ds ;
+			}
+		},
 	},
 });

+ 2 - 1
Web/src/types/pinia.d.ts

@@ -14,7 +14,8 @@ declare interface UserInfos<T = any> {
 declare interface UserInfosState {
 	userInfos: UserInfos;
 	constList: T[];
-	dictList: T[];
+	dictList: T;
+	dictListInt :T;
 }
 
 // 路由缓存列表

+ 5 - 0
Web/src/utils/axios-utils.ts

@@ -26,6 +26,11 @@ export const getToken = () => {
 	return Local.get(accessTokenKey);
 };
 
+// 获取上传文件Header
+export const getHeader  = () => {
+	return { authorization: 'Bearer ' + getToken() };
+};
+
 // 清除 token
 export const clearAccessTokens = () => {
 	clearTokens();

+ 18 - 17
Web/src/utils/dict-utils.ts

@@ -1,9 +1,7 @@
-import { storeToRefs } from 'pinia';
 import { useUserInfo } from '/@/stores/userInfo';
 
 
-const stores = useUserInfo();
-const { dictList } = storeToRefs(stores);
+const stores = useUserInfo(); 
 
 // 用于在 Table 中把字段的代码转换为名称,示例如下:
 /*
@@ -16,15 +14,17 @@ import { getDictDataItem as di, getDictDataList as dl } from '/@/utils/dict-util
 </el-table-column>
 */
 export function getDictDataItem(dicName:string, dicItemCode:any): any{
-    const dict = dictList.value.filter(item => item.code === dicName);
-    if (dict.length === 0)
-        return null;
-    const dictData = dict[0].children.filter(item => item.code == dicItemCode);
-    if (dictData.length === 0)
-        return null;
-    return dictData[0];
+    return stores.getDictItemByVal(dicName,dicItemCode)
+}
+export function getDictValByLabel(dicName:string, dicItemCode:any): any{
+    return stores.getDictValByLabel(dicName,dicItemCode)
+}
+
+export function getDictLabelByVal(dicName:string, dicItemCode:any): any{
+    return stores.getDictLabelByVal(dicName,dicItemCode)
 }
 
+
 // select 控件使用,用于获取字典列表,示例如下:
 /*
 import { getDictDataItem as di, getDictDataList as dl } from '/@/utils/dict-utils';
@@ -33,14 +33,15 @@ import { getDictDataItem as di, getDictDataList as dl } from '/@/utils/dict-util
     <el-option v-for="(item,index) in  dl('字段名名码')"  :key="index" :value="item.code" :label="`[${item.code}] ${item.value}`"></el-option>
 </el-select>
 */
-export function getDictType(dicName:string): any{
-    const dict = dictList.value.filter(item => item.code === dicName);
-    if (dict.length === 0)
-        return null;
-    return dict[0];
+export function getDictType(dicName:string): any{ 
+    
+    return stores.dictList[dicName];
 }
 
 export function getDictDataList(dicName:string): any{
-    const result = getDictType(dicName)?.children;
-    return result ?? [];
+    return stores.getDictDatasByCode(dicName);
+}
+//获取数字类型的
+export function getDictDataListInt(dicName:string): any{
+    return stores.getDictIntDatasByCode(dicName);
 }

+ 25 - 2
Web/src/utils/request.ts

@@ -201,6 +201,29 @@ export function decryptJWT(token: string): any {
 export function getJWTDate(timestamp: number): Date {
 	return new Date(timestamp * 1000);
 }
-
+/**
+ * Ajax请求,如果成功返回result字段,如果不成功提示错误信息
+ * @description Ajax请求
+ * @config CreateAxiosDefaults 请求参数
+ * @returns 返回对象
+ */
+export function request2(config?: CreateAxiosDefaults): any {
+	return new Promise((resolve, reject) => {
+		service(config)
+			.then((res) => {
+				if (res.data.type == 'success') {
+					resolve(res.data.result);
+				} else {
+					console.log('res', res);
+					ElMessage.success(res.data.message);
+				}
+			})
+			.catch((res) => {
+				console.log('res', res);
+				ElMessage.error(res);
+				reject(res);
+			});
+	});
+}
 // 导出 axios 实例
-export default service;
+export default service;

+ 163 - 0
Web/src/views/main/dm_ApplyDemo/component/editDialog.vue

@@ -0,0 +1,163 @@
+<template>
+	<div class="dm_ApplyDemo-container">
+		<el-dialog v-model="isShowDialog" :width="800" draggable="">
+			<template #header>
+				<div style="color: #fff">
+					<!--<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>-->
+					<span>{{ props.title }}</span>
+				</div>
+			</template>
+			<el-form :model="ruleForm" ref="ruleFormRef" label-width="auto" :rules="rules">
+				<el-row :gutter="35">
+					<el-form-item v-show="false">
+						<el-input v-model="ruleForm.id" />
+					</el-form-item>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="机构类型" prop="orgType">
+							<el-select clearable v-model="ruleForm.orgType" placeholder="请选择机构类型">
+								<el-option v-for="(item,index) in dl('org_type')"  :key="index" :value="item.code" :label="`[${item.code}] ${item.value}`"></el-option>
+								
+							</el-select>
+							
+						</el-form-item>
+						
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="申请号" prop="applyNO">
+							<el-input v-model="ruleForm.applyNO" placeholder="请输入申请号" maxlength="32" show-word-limit clearable />
+							
+						</el-form-item>
+						
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="申请时间" prop="applicatDate">
+							<el-date-picker v-model="ruleForm.applicatDate" type="date" placeholder="申请时间" />
+							
+						</el-form-item>
+						
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="申请金额" prop="amount">
+							<el-input-number v-model="ruleForm.amount" placeholder="请输入申请金额" clearable />
+							
+						</el-form-item>
+						
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="是否通知" prop="isNotice">
+							<el-switch v-model="ruleForm.isNotice" active-text="是" inactive-text="否" />
+							
+						</el-form-item>
+						
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="备注" prop="remark">
+							<el-input v-model="ruleForm.remark" placeholder="请输入备注" maxlength="2000" show-word-limit clearable />
+							
+						</el-form-item>
+						
+					</el-col>
+				</el-row>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel">取 消</el-button>
+					<el-button type="primary" @click="submit">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+<style scoped>
+:deep(.el-select),
+:deep(.el-input-number) {
+	width: 100%;
+}
+</style>
+<script lang="ts" setup>
+	import { ref,onMounted } from "vue";
+	import { getDictDataItem as di, getDictDataListInt as dl } from '/@/utils/dict-utils';
+	import { ElMessage } from "element-plus";
+	import type { FormRules } from "element-plus";
+	import { addDm_ApplyDemo, updateDm_ApplyDemo, detailDm_ApplyDemo } from "/@/api/main/dm_ApplyDemo";
+
+	//父级传递来的参数
+	var props = defineProps({
+		title: {
+		type: String,
+		default: "",
+	},
+	});
+	//父级传递来的函数,用于回调
+	const emit = defineEmits(["reloadTable"]);
+	const ruleFormRef = ref();
+	const isShowDialog = ref(false);
+	const ruleForm = ref<any>({});
+	//自行添加其他规则
+	const rules = ref<FormRules>({
+        applyNO: [{ required: true, message: '请输入申请号!', trigger: 'blur',},],
+        applicatDate: [{ required: true, message: '请选择申请时间!', trigger: 'change',},],
+        amount: [{ required: true, message: '请输入申请金额!', trigger: 'blur',},],
+        remark: [{ required: true, message: '请输入备注!', trigger: 'blur',},],
+	});
+
+	// 打开弹窗
+	const openDialog = async (row: any) => {
+		// ruleForm.value = JSON.parse(JSON.stringify(row));
+		// 改用detail获取最新数据来编辑
+		let rowData = JSON.parse(JSON.stringify(row));
+		if (rowData.id)
+			ruleForm.value = (await detailDm_ApplyDemo(rowData.id)).data.result;
+		else
+			ruleForm.value = rowData;
+		isShowDialog.value = true;
+	};
+
+	// 关闭弹窗
+	const closeDialog = () => {
+		emit("reloadTable");
+		isShowDialog.value = false;
+	};
+
+	// 取消
+	const cancel = () => {
+		isShowDialog.value = false;
+	};
+
+	// 提交
+	const submit = async () => {
+		ruleFormRef.value.validate(async (isValid: boolean, fields?: any) => {
+			if (isValid) {
+				let values = ruleForm.value;
+				if (ruleForm.value.id == undefined || ruleForm.value.id == null || ruleForm.value.id == "" || ruleForm.value.id == 0) {
+					await addDm_ApplyDemo(values);
+				} else {
+					await updateDm_ApplyDemo(values);
+				}
+				closeDialog();
+			} else {
+				ElMessage({
+					message: `表单有${Object.keys(fields).length}处验证失败,请修改后再提交`,
+					type: "error",
+				});
+			}
+		});
+	};
+
+
+
+
+
+
+
+	// 页面加载时
+	onMounted(async () => {
+	});
+
+	//将属性或者函数暴露给父组件
+	defineExpose({ openDialog });
+</script>
+
+
+
+

+ 202 - 0
Web/src/views/main/dm_ApplyDemo/index.vue

@@ -0,0 +1,202 @@
+<template>
+	<div class="dm_ApplyDemo-container">
+		<el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
+			<el-form :model="queryParams" ref="queryForm" labelWidth="90">
+				<el-row>
+					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10">
+						<el-form-item label="关键字">
+							<el-input v-model="queryParams.searchKey" clearable="" placeholder="请输入模糊查询关键字" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10" v-if="showAdvanceQueryUI">
+						<el-form-item label="机构类型">
+							<el-select clearable="" v-model="queryParams.orgType" placeholder="请选择机构类型">
+								<el-option v-for="(item, index) in dl('org_type')" :key="index" :value="item.code" :label="`[${item.code}] ${item.value}`" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10" v-if="showAdvanceQueryUI">
+						<el-form-item label="申请号">
+							<el-input v-model="queryParams.applyNO" clearable="" placeholder="请输入申请号" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10" v-if="showAdvanceQueryUI">
+						<el-form-item label="申请时间">
+							<el-date-picker placeholder="请选择申请时间" value-format="YYYY/MM/DD" type="daterange" v-model="queryParams.applicatDateRange" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10" v-if="showAdvanceQueryUI">
+						<el-form-item label="申请金额">
+							<el-input-number v-model="queryParams.amount" clearable="" placeholder="请输入申请金额" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10" v-if="showAdvanceQueryUI"> </el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10" v-if="showAdvanceQueryUI">
+						<el-form-item label="备注">
+							<el-input v-model="queryParams.remark" clearable="" placeholder="请输入备注" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="6" :lg="6" :xl="6" class="mb10">
+						<el-form-item>
+							<el-button-group>
+								<el-button type="primary" icon="ele-Search" @click="handleQuery" v-auth="'dm_ApplyDemo:page'"> 查询 </el-button>
+								<el-button icon="ele-Refresh" @click="() => (queryParams = {})"> 重置 </el-button>
+								<el-button icon="ele-ZoomIn" @click="changeAdvanceQueryUI" v-if="!showAdvanceQueryUI"> 高级 </el-button>
+								<el-button icon="ele-ZoomOut" @click="changeAdvanceQueryUI" v-if="showAdvanceQueryUI"> 隐藏 </el-button>
+							</el-button-group>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="6" :lg="6" :xl="6" class="mb10"> 
+								<el-button type="primary" icon="ele-Plus" @click="openAddDm_ApplyDemo" v-auth="'dm_ApplyDemo:add'"> 新增 </el-button>
+								
+								<el-button icon="ele-Download" @click="exportData" > 导出数据 </el-button>
+
+								<ImportButton accept=".xlsx" url="/api/dm_ApplyDemo/import" 
+								btnText="导入数据" @success="handleQuery"/> 
+					</el-col>
+				</el-row>
+			</el-form>
+		</el-card>
+		<el-card class="full-table" shadow="hover" style="margin-top: 8px">
+			<el-table :data="tableData" style="width: 100%" v-loading="loading" tooltip-effect="light" row-key="id" @sort-change="sortChange" border="">
+				<el-table-column type="index" label="序号" width="55" align="center" />
+				<el-table-column prop="orgType" label="机构类型" width="105" show-overflow-tooltip="">
+					<template #default="scope">
+						<el-tag :type="di('org_type', scope.row.orgType)?.tagType"> {{ di('org_type', scope.row.orgType)?.value }} </el-tag>
+					</template>
+				</el-table-column>
+				<el-table-column prop="applyNO" label="申请号" width="105" show-overflow-tooltip="" />
+				<el-table-column prop="applicatDate" label="申请时间" width="180" show-overflow-tooltip="" />
+				<el-table-column prop="amount" label="申请金额" width="90" show-overflow-tooltip="" />
+				<el-table-column prop="isNotice" label="是否通知" width="120" show-overflow-tooltip="">
+					<template #default="scope">
+						<el-tag v-if="scope.row.isNotice"> 是 </el-tag>
+						<el-tag type="danger" v-else> 否 </el-tag>
+					</template>
+				</el-table-column>
+				<el-table-column prop="remark" label="备注" width="90" show-overflow-tooltip="" />
+				<el-table-column label="操作" width="140" align="center" fixed="right" show-overflow-tooltip="" v-if="auth('dm_ApplyDemo:edit') || auth('dm_ApplyDemo:delete')">
+					<template #default="scope">
+						<el-button icon="ele-Edit" size="small" text="" type="primary" @click="openEditDm_ApplyDemo(scope.row)" v-auth="'dm_ApplyDemo:edit'"> 编辑 </el-button>
+						<el-button icon="ele-Delete" size="small" text="" type="primary" @click="delDm_ApplyDemo(scope.row)" v-auth="'dm_ApplyDemo:delete'"> 删除 </el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+			<el-pagination
+				v-model:currentPage="tableParams.page"
+				v-model:page-size="tableParams.pageSize"
+				:total="tableParams.total"
+				:page-sizes="[10, 20, 50, 100, 200, 500]"
+				small=""
+				background=""
+				@size-change="handleSizeChange"
+				@current-change="handleCurrentChange"
+				layout="total, sizes, prev, pager, next, jumper"
+			/>
+			<printDialog ref="printDialogRef" :title="printDm_ApplyDemoTitle" @reloadTable="handleQuery" />
+			<editDialog ref="editDialogRef" :title="editDm_ApplyDemoTitle" @reloadTable="handleQuery" />
+		</el-card>
+	</div>
+</template>
+
+<script lang="ts" setup name="dm_ApplyDemo">
+import { ref } from 'vue';
+import { ElMessageBox, ElMessage } from 'element-plus';
+import { auth } from '/@/utils/authFunction';
+import { getDictDataItem as di, getDictDataList as dl } from '/@/utils/dict-utils';
+
+import printDialog from '/@/views/system/print/component/hiprint/preview.vue';
+import editDialog from '/@/views/main/dm_ApplyDemo/component/editDialog.vue';
+import { pageDm_ApplyDemo, deleteDm_ApplyDemo,exportDm_ApplyDemo as exportData } from '/@/api/main/dm_ApplyDemo';
+import ImportButton from '/@/components/importButton/index.vue';
+
+const baseUrl = window.__env__.VITE_API_URL;
+const showAdvanceQueryUI = ref(false);
+const printDialogRef = ref();
+const editDialogRef = ref();
+const loading = ref(false);
+const tableData = ref<any>([]);
+const queryParams = ref<any>({});
+const tableParams = ref({
+	page: 1,
+	pageSize: 10,
+	total: 0,
+});
+
+const printDm_ApplyDemoTitle = ref('');
+const editDm_ApplyDemoTitle = ref('');
+
+// 改变高级查询的控件显示状态
+const changeAdvanceQueryUI = () => {
+	showAdvanceQueryUI.value = !showAdvanceQueryUI.value;
+};
+
+// 查询操作
+const handleQuery = async () => {
+	loading.value = true;
+	var res = await pageDm_ApplyDemo(Object.assign(queryParams.value, tableParams.value));
+	tableData.value = res.data.result?.items ?? [];
+	tableParams.value.total = res.data.result?.total;
+	loading.value = false;
+};
+
+// 列排序
+const sortChange = async (column: any) => {
+	queryParams.value.field = column.prop;
+	queryParams.value.order = column.order;
+	await handleQuery();
+};
+
+// 打开新增页面
+const openAddDm_ApplyDemo = () => {
+	editDm_ApplyDemoTitle.value = '添加申请示例';
+	editDialogRef.value.openDialog({});
+};
+
+// 打开打印页面
+const openPrintDm_ApplyDemo = async (row: any) => {
+	printDm_ApplyDemoTitle.value = '打印申请示例';
+};
+
+// 打开编辑页面
+const openEditDm_ApplyDemo = (row: any) => {
+	editDm_ApplyDemoTitle.value = '编辑申请示例';
+	editDialogRef.value.openDialog(row);
+};
+
+// 删除
+const delDm_ApplyDemo = (row: any) => {
+	ElMessageBox.confirm(`确定要删除吗?`, '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+	})
+		.then(async () => {
+			await deleteDm_ApplyDemo(row);
+			handleQuery();
+			ElMessage.success('删除成功');
+		})
+		.catch(() => {});
+};
+
+// 改变页面容量
+const handleSizeChange = (val: number) => {
+	tableParams.value.pageSize = val;
+	handleQuery();
+};
+
+// 改变页码序号
+const handleCurrentChange = (val: number) => {
+	tableParams.value.page = val;
+	handleQuery();
+};
+
+handleQuery();
+</script>
+<style scoped>
+:deep(.el-ipnut),
+:deep(.el-select),
+:deep(.el-input-number) {
+	width: 100%;
+}
+</style>

+ 4 - 4
Web/src/views/system/dict/index.vue

@@ -424,10 +424,10 @@ const handleDictDataCurrentChange = (val: number) => {
 
 // 更新前端字典缓存
 const updateDictSession = async () => {
-	if (Session.get('dictList')) {
-		const dictList = await useUserInfo().getAllDictList();
-		Session.set('dictList', dictList);
-	}
+	// if (Session.get('dictList')) {
+	// 	const dictList = await useUserInfo().getAllDictList();
+	// 	Session.set('dictList', dictList);
+	// }
 	await useUserInfo().setDictList();
 };
 </script>