DNTFrameworkCore

其他类别 2025-08-21

什么是DNTFrameworkCore ?

DNTFrameworkCore是一种基于ASP.NET Core的高质量Web应用程序的轻巧且可扩展的基础架构,并具有以下目标:

  • 在各种应用中的常见结构,例如横切问题等
  • 遵循干燥原则以关注主要业务逻辑
  • 减少开发时间
  • 较少的错误和停止错误传播
  • 减少对OOP和OOD了解的新开发人员的培训时间

基于Crud的思维

申请服务

 public interface IBlogService : IEntityService < int , BlogModel >
{
}

public class BlogService : EntityService < Blog , int , BlogModel > , IBlogService
{
    private readonly IMapper _mapper ;

    public BlogService (
        IDbContext dbContext ,
        IEventBus bus ,
        IMapper mapper ) : base ( dbContext , bus )
    {
        _mapper = mapper ?? throw new ArgumentNullException ( nameof ( mapper ) ) ;
    }

    public override Task < IPagedResult < BlogModel > > FetchPagedListAsync ( FilteredPagedRequest request ,
        CancellationToken cancellationToken = default )
    {
        return EntitySet . AsNoTracking ( )
            . Select ( b => new BlogModel
            {
                Id = b . Id ,
                Version = b . Version ,
                Url = b . Url ,
                Title = b . Title
            } ) . ToPagedListAsync ( request , cancellationToken ) ;
    }

    protected override void MapToEntity ( BlogModel model , Blog blog )
    {
        _mapper . Map ( model , blog ) ;
    }

    protected override BlogModel MapToModel ( Blog blog )
    {
        return _mapper . Map < BlogModel > ( blog ) ;
    }
}

ASP.NET Core WebAPI

{ public BlogsController(IBlogService service) : base(service) { } protected override string CreatePermissionName => PermissionNames.Blogs_Create; protected override string EditPermissionName => PermissionNames.Blogs_Edit; protected override string ViewPermissionName => PermissionNames.Blogs_View; protected override string DeletePermissionName => PermissionNames.Blogs_Delete; }">
 [ Route ( "api/[controller]" ) ]
public class BlogsController : EntityController < IBlogService , int , BlogModel >
{
    public BlogsController ( IBlogService service ) : base ( service )
    {
    }

    protected override string CreatePermissionName => PermissionNames . Blogs_Create ;
    protected override string EditPermissionName => PermissionNames . Blogs_Edit ;
    protected override string ViewPermissionName => PermissionNames . Blogs_View ;
    protected override string DeletePermissionName => PermissionNames . Blogs_Delete ;
}

ASP.NET核心MVC

 public class BlogsController : EntityController < IBlogService , int , BlogModel >
{
   public BlogsController ( IBlogService service ) : base ( service )
   {
   }

   protected override string CreatePermissionName => PermissionNames . Blogs_Create ;
   protected override string EditPermissionName => PermissionNames . Blogs_Edit ;
   protected override string ViewPermissionName => PermissionNames . Blogs_View ;
   protected override string DeletePermissionName => PermissionNames . Blogs_Delete ;
   protected override string ViewName => "_BlogPartial" ;
}

_blogpartial.cshtml

">
 @inherits EntityFormRazorPage < BlogModel >
@{
   Layout = " _EntityFormLayout " ;
   EntityName = " Blog " ;
   DeletePermission = PermissionNames . Blogs_Delete ;
   CreatePermission = PermissionNames . Blogs_Create ;
   EditPermission = PermissionNames . Blogs_Edit ;
   EntityDisplayName = " Blog " ;
}

< div class = " form-group row " >
   < div class = " col col-md-8 " >
       < label asp-for = " Title " class = " col-form-label text-md-left " >label >
       < input asp-for = " Title " autocomplete = " off " class = " form-control " />
       < span asp-validation-for = " Title " class = " text-danger " >span >
   div >
div >
< div class = " form-group row " >
   < div class = " col " >
       < label asp-for = " Url " class = " col-form-label text-md-left " >label >
       < input asp-for = " Url " class = " form-control " type = " url " />
       < span asp-validation-for = " Url " class = " text-danger " >span >
   div >
div >

安装

要根据DNTFrameworkCore创建您的第一个项目,您可以安装以下软件包:

DNTFrameworkCore PM> Install-Package DNTFrameworkCore .EFCore PM> Install-Package DNTFrameworkCore .EFCore.SqlServer PM> Install-Package DNTFrameworkCore .Web PM> Install-Package DNTFrameworkCore .Web.Tenancy PM> Install-Package DNTFrameworkCore .Web.EFCore PM> Install-Package DNTFrameworkCore .Licensing PM> Install-Package DNTFrameworkCore .FluentValidation ">
 PM> Install-Package DNTFrameworkCore
PM> Install-Package DNTFrameworkCore .EFCore
PM> Install-Package DNTFrameworkCore .EFCore.SqlServer
PM> Install-Package DNTFrameworkCore .Web
PM> Install-Package DNTFrameworkCore .Web.Tenancy
PM> Install-Package DNTFrameworkCore .Web.EFCore
PM> Install-Package DNTFrameworkCore .Licensing
PM> Install-Package DNTFrameworkCore .FluentValidation

或者

1-运行以下命令以基于ASP.NET Core Web API和DNTFrameworkCore安装样板项目模板:

dotnet new --install DNTFrameworkCore TemplateAPI::*‌‌

2-使用安装模板创建新项目:

dotnet new dntcore-api

现在,您有了下面的解决方案,其中包含完整的身份管理功能包括用户,角色和动态许可管理,并与持续的JWT身份验证机制集成在一起:

有关模板的更多信息,您可以观看DNTFrameworkCore模板存储库

特征

  • 应用程序输入验证
  • 交易管理
  • 事件
  • EntityGraph Tracking(Master-detail)
  • 编号
  • 功能编程错误处理
  • 许可授权
  • 实体服务
  • EntityController(API和MVC)
  • 基于EFCORE的DBLOGGER提供商
  • protectionKey Efcore商店
  • 钩子
  • SoftDelete
  • 租赁
  • 跟踪机制(iCreationTracking,Imodification Tracking)
  • 荧光验证整合
  • BackowdTaskqueue
  • Rowintegrity
  • 起始仪机制
  • CQRS(即将推出)
  • 实体历史(即将推出)

用法

DNTFrameworkCore .testapi完成ASP.NET核心Web API

创建实体

 public class Task : Entity < int > , INumberedEntity , IHasRowVersion , IHasRowIntegrity , ICreationTracking , IModificationTracking
{
    public const int MaxTitleLength = 256 ;
    public const int MaxDescriptionLength = 1024 ;

    public string Title { get ; set ; }
    public string NormalizedTitle { get ; set ; }
    public string Number { get ; set ; }
    public string Description { get ; set ; }
    public TaskState State { get ; set ; } = TaskState . Todo ;
    public byte [ ] Version { get ; set ; }
}

实现从DBContextCore继承的ProjectDbContext

 public class ProjectDbContext : DbContextCore
{
    public ProjectDbContext ( DbContextOptions < ProjectDbContext > options , IEnumerable < IHook > hooks ) : base ( options , hooks )
    {
    }

    protected override void OnModelCreating ( ModelBuilder modelBuilder )
    {               
        modelBuilder . ApplyConfigurationsFromAssembly ( Assembly . GetExecutingAssembly ( ) ) ;

        modelBuilder . AddJsonFields ( ) ;
        modelBuilder . AddTrackingFields < long > ( ) ;
        modelBuilder . AddIsDeletedField ( ) ;
        modelBuilder . AddRowVersionField ( ) ;
        modelBuilder . AddRowIntegrityField ( ) ;
            
        modelBuilder . NormalizeDateTime ( ) ;
        modelBuilder . NormalizeDecimalPrecision ( ) ;
            
        base . OnModelCreating ( modelBuilder ) ;
    }
}

创建模型/DTO

DNTFrameworkCore.TestAPI")] public class TaskModel : MasterModel, IValidatableObject { public string Title { get; set; } [MaxLength(50, ErrorMessage = "Validation from DataAnnotations")] public string Number { get; set; } public string Description { get; set; } public TaskState State { get; set; } = TaskState.Todo; public IEnumerable Validate(ValidationContext validationContext) { if (Title == "IValidatableObject") { yield return new ValidationResult("Validation from IValidatableObject"); } } }">
 [ LocalizationResource ( Name = "SharedResource" , Location = " DNTFrameworkCore .TestAPI" ) ]
public class TaskModel : MasterModel < int > , IValidatableObject
{
    public string Title { get ; set ; }

    [ MaxLength ( 50 , ErrorMessage = "Validation from DataAnnotations" ) ]
    public string Number { get ; set ; }

    public string Description { get ; set ; }
    public TaskState State { get ; set ; } = TaskState . Todo ;

    public IEnumerable < ValidationResult > Validate ( ValidationContext validationContext )
    {
        if ( Title == "IValidatableObject" )
        {
            yield return new ValidationResult ( "Validation from IValidatableObject" ) ;
        }
    }
}

注意:基于验证基础结构,您可以使用多种方法验证模型/DTO,使用DataAnnotation ValidateAttribute,实现IvalIdatableObject,或实现DNTFrameworkCore软件包中存在的Imodelvalidator。

 public class TaskValidator : ModelValidator < TaskModel >
{
    public override IEnumerable < ModelValidationResult > Validate ( TaskModel model )
    {
        if ( ! Enum . IsDefined ( typeof ( TaskState ) , model . State ) )
        {
            yield return new ModelValidationResult ( nameof ( TaskModel . State ) , "Validation from IModelValidator" ) ;
        }
    }
}

同样,在大多数情况下,一种模型/DTO可以满足您对创建/编辑/查看实体的要求。但是,您可以创建以下方式创建重新模型:

 public class TaskReadModel : ReadModel < int >
{
    public string Title { get ; set ; }
    public string Number { get ; set ; }
    public TaskState State { get ; set ; } = TaskState . Todo ;
}

实施服务

 public interface ITaskService : IEntityService < int , TaskReadModel , TaskModel , TaskFilteredPagedRequest >
{
}

public class TaskService : EntityService < Task , int , TaskReadModel , TaskModel , TaskFilteredPagedRequest > ,
    ITaskService
{
    private readonly IMapper _mapper ;
    public TaskService ( IDbContext dbContext , IEventBus bus , IMapper mapper ) : base ( dbContext , bus )
    {
        _mapper = mapper ?? throw new ArgumentNullException ( nameof ( mapper ) ;
    }

    public override Task < IPagedResult < TaskReadModel > > FetchPagedListAsync ( TaskFilteredPagedRequest request ,
        CancellationToken cancellationToken = default )
    {
        return EntitySet . AsNoTracking ( )
            . WhereIf ( model . State . HasValue , t => t . State == model . State )
            . Select ( t => new TaskReadModel
            {
                Id = t . Id ,
                Title = t . Title ,
                State = t . State ,
                Number = t . Number
            } ) . ToPagedListAsync ( request , cancellationToken ) ;
    }

    protected override void MapToEntity ( TaskModel model , Task task )
    {
        _mapper . Map ( model , task ) ;
    }

    protected override TaskModel MapToModel ( Task task )
    {
        return _mapper . Map < TaskModel > ( task ) ;
    }
}

在DNTFrameworkCore .efcore中,自动应用程序或其他映射器库没有依赖性,然后您可以通过实现maptomodel和maptoentity抽象方法来手动进行映射。

实现API控制器

{ public TasksController(ITaskService service) : base(service) { } protected override string CreatePermissionName => PermissionNames.Tasks_Create; protected override string EditPermissionName => PermissionNames.Tasks_Edit; protected override string ViewPermissionName => PermissionNames.Tasks_View; protected override string DeletePermissionName => PermissionNames.Tasks_Delete; }">
 [ Route ( "api/[controller]" ) ]
public class
    TasksController : EntityController < ITaskService , int , TaskReadModel , TaskModel , TaskFilteredPagedRequest >
{
    public TasksController ( ITaskService service ) : base ( service )
    {
    }

    protected override string CreatePermissionName => PermissionNames . Tasks_Create ;
    protected override string EditPermissionName => PermissionNames . Tasks_Edit ;
    protected override string ViewPermissionName => PermissionNames . Tasks_View ;
    protected override string DeletePermissionName => PermissionNames . Tasks_Delete ;
} 
{ public BlogsController(IBlogService service) : base(service) { } protected override string CreatePermissionName => PermissionNames.Blogs_Create; protected override string EditPermissionName => PermissionNames.Blogs_Edit; protected override string ViewPermissionName => PermissionNames.Blogs_View; protected override string DeletePermissionName => PermissionNames.Blogs_Delete; } ">
 [ Route ( "api/[controller]" ) ]
public class BlogsController : EntityController < IBlogService , int , BlogModel >
{
    public BlogsController ( IBlogService service ) : base ( service )
    {
    }

    protected override string CreatePermissionName => PermissionNames . Blogs_Create ;
    protected override string EditPermissionName => PermissionNames . Blogs_Edit ;
    protected override string ViewPermissionName => PermissionNames . Blogs_View ;
    protected override string DeletePermissionName => PermissionNames . Blogs_Delete ;
} 

基于任务的思维

丰富的领域模型

New(Title title, IPriceTypePolicy policy) // { // if (title == null) throw new ArgumentNullException(nameof(title)); // if (policy == null) throw new ArgumentNullException(nameof(policy)); // // var priceType = new PriceType(title); // if (!policy.IsUnique(priceType)) return Fail("PriceType Title Should Be Unique"); // // priceType.AddDomainEvent(new PriceTypeCreatedDomainEvent(priceType)); // // return Ok(priceType); // } }">
 public class PriceType : Entity < long > , IAggregateRoot
{
    private PriceType ( Title title )
    {
        Title = title ;
    }
    
    public PriceType ( Title title , IPriceTypePolicy policy )
    {
        if ( title == null ) throw new ArgumentNullException ( nameof ( title ) ) ;
        if ( policy == null ) throw new ArgumentNullException ( nameof ( policy ) ) ;

        Title = title ;

        if ( ! policy . IsUnique ( this ) ) ThrowDomainException ( "PriceType Title Should Be Unique" ) ;

        AddDomainEvent ( new PriceTypeCreatedDomainEvent ( this ) ) ;
    }

    public Title Title { get ; private set ; }

    // public static Result New(Title title, IPriceTypePolicy policy)
    // {
    //     if (title == null) throw new ArgumentNullException(nameof(title));
    //     if (policy == null) throw new ArgumentNullException(nameof(policy));
    //
    //     var priceType = new PriceType(title);
    //     if (!policy.IsUnique(priceType)) return Fail("PriceType Title Should Be Unique");
    //
    //     priceType.AddDomainEvent(new PriceTypeCreatedDomainEvent(priceType));
    //
    //     return Ok(priceType);
    // }
}

ValueObject

100: ThrowDomainException("title is too long"); break; } } public string Value { get; private set; } protected override IEnumerable EqualityValues { get { yield return Value; } } // public static Result New(string value) // { // value ??= string.Empty; // // if (value.Length == 0) return Fail<Title>("title should not be empty"); // // return value.Length > 100 ? Fail<Title>("title is too long") : Ok(new Title { Value = value }); // } public static implicit operator string(Title title) { return title.Value; } public static explicit operator Title(string title) { return new(title); } }"><pre> <span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">Title</span> <span class="pl-c1">:</span> <span class="pl-smi">ValueObject</span> <span class="pl-kos">{</span> <span class="pl-k">private</span> <span class="pl-v">Title</span> <span class="pl-kos">(</span> <span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-kos">}</span> <span class="pl-k">public</span> <span class="pl-v">Title</span> <span class="pl-kos">(</span> <span class="pl-smi">string</span> <span class="pl-s1">value</span> <span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-s1">value</span> <span class="pl-c1">??=</span> <span class="pl-smi">string</span> <span class="pl-kos">.</span> <span class="pl-s1">Empty</span> <span class="pl-kos">;</span> <span class="pl-k">switch</span> <span class="pl-kos">(</span> <span class="pl-s1">value</span> <span class="pl-kos">.</span> <span class="pl-s1">Length</span> <span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">case</span> <span class="pl-c1">0</span> <span class="pl-c1">:</span> <span class="pl-s1">ThrowDomainException</span> <span class="pl-kos">(</span> <span class="pl-s">"title should not be empty"</span> <span class="pl-kos">)</span> <span class="pl-kos">;</span> <span class="pl-k">break</span> <span class="pl-kos">;</span> <span class="pl-k">case</span> <span class="pl-c1">></span> <span class="pl-c1">100</span> <span class="pl-c1">:</span> <span class="pl-s1">ThrowDomainException</span> <span class="pl-kos">(</span> <span class="pl-s">"title is too long"</span> <span class="pl-kos">)</span> <span class="pl-kos">;</span> <span class="pl-k">break</span> <span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">public</span> <span class="pl-smi">string</span> <span class="pl-s1">Value</span> <span class="pl-kos">{</span> <span class="pl-k">get</span> <span class="pl-kos">;</span> <span class="pl-k">private</span> <span class="pl-k">set</span> <span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-k">protected</span> <span class="pl-k">override</span> <span class="pl-smi">IEnumerable</span> <span class="pl-c1"><</span> <span class="pl-smi">object</span> <span class="pl-c1">></span> <span class="pl-s1">EqualityValues</span> <span class="pl-kos">{</span> <span class="pl-k">get</span> <span class="pl-kos">{</span> <spa </article> <!-- --> <div class="shadow_box bg-white rounded-xl shadow-sm p-8"> <div class="title text-lg"><i class="fa fa-download text-primary mr-2"></i>下载源码</div> <div class="share_box"> <div class="share_item"> <span class="share_list active github"><i class="fa fa-github mr-2 text-xl"></i><a href="https://github.com/rabbal/DNTFrameworkCore.git" id="btnPos" rel="noreferrer nofollow" target="_blank">从 GitHub 克隆</a></span> </div> </div> <div class="copy_box"> <p>通过命令行克隆项目:</p> <div class="input_box"> <span class="text">git clone https://github.com/rabbal/DNTFrameworkCore.git</span> <span title="复制" class="copy_btn"></span> </div> </div> </div> </div> <!-- right-aside --> <div class="space-y-8"> <!-- 搜索框(移动端) --> <div class="md:hidden bg-white rounded-xl shadow-sm p-4 mb-8"> <div class="relative"> <input type="text" placeholder="搜索Python文章..." class="w-full pl-10 pr-4 py-2 rounded-full border border-gray-200 focus:outline-none focus:border-primary focus:ring-2 focus:ring-primary/20 text-sm"> <button class="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted"> <i class="fa fa-search"></i> </button> </div> </div> <!-- 最新文章 --> <div class="bg-white rounded-xl shadow-sm p-6" style="margin-top: 0;"> <h3 class="text-lg font-bold mb-4 border-b pb-3">相关文章</h3> <div class="space-y-4"> <a href="/download/209081.html" class="flex group"> <div class="flex-shrink-0 w-20 h-20 bg-primary/10 rounded-lg overflow-hidden flex items-center justify-center" style="position: relative;"> <div class="lazy-src" lazy-src="https://images.downcodes.com/uploads/20250728/logo_68871768b0c791.png" alt="Awesome Nuget Packages"> </div> </div> <div class="ml-4"> <h4 class="font-medium text-dark group-hover:text-primary transition-colors line-clamp-2"> Awesome Nuget Packages</h4> <p class="text-sm text-muted mt-1">2025-08-21</p> </div> </a> <a href="/download/209078.html" class="flex group"> <div class="flex-shrink-0 w-20 h-20 bg-primary/10 rounded-lg overflow-hidden flex items-center justify-center" style="position: relative;"> <div class="lazy-src" lazy-src="https://images.downcodes.com/uploads/20250728/logo_688717620bb331.png" alt="blazor samples"> </div> </div> <div class="ml-4"> <h4 class="font-medium text-dark group-hover:text-primary transition-colors line-clamp-2"> blazor samples</h4> <p class="text-sm text-muted mt-1">2025-08-21</p> </div> </a> <a href="/download/209070.html" class="flex group"> <div class="flex-shrink-0 w-20 h-20 bg-primary/10 rounded-lg overflow-hidden flex items-center justify-center" style="position: relative;"> <div class="lazy-src" lazy-src="https://images.downcodes.com/uploads/20250728/logo_6887174a71e9d1.png" alt="IdentityServer4AspNetCoreIdentityTemplate"> </div> </div> <div class="ml-4"> <h4 class="font-medium text-dark group-hover:text-primary transition-colors line-clamp-2"> IdentityServer4AspNetCoreIdentityTemplate</h4> <p class="text-sm text-muted mt-1">2025-08-21</p> </div> </a> <a href="/download/209067.html" class="flex group"> <div class="flex-shrink-0 w-20 h-20 bg-primary/10 rounded-lg overflow-hidden flex items-center justify-center" style="position: relative;"> <div class="lazy-src" lazy-src="https://images.downcodes.com/uploads/20250728/logo_688717428eaa91.png" alt="Mockaco"> </div> </div> <div class="ml-4"> <h4 class="font-medium text-dark group-hover:text-primary transition-colors line-clamp-2"> Mockaco</h4> <p class="text-sm text-muted mt-1">2025-08-21</p> </div> </a> </div> </div> <!-- 推荐阅读 --> <div class="bg-white rounded-xl shadow-sm p-6"> <h3 class="text-lg font-bold mb-4 border-b pb-3">推荐阅读</h3> <div class="space-y-4"> <a href="/download/226184.html" class="flex group"> <div class="flex-shrink-0 w-20 h-20 bg-primary/10 rounded-lg overflow-hidden flex items-center justify-center" style="position: relative;"> <div class="lazy-src" lazy-src="https://images.downcodes.com/uploads/20260115/logo_69687066211c51.jpg" alt="向上:银河游戏免安装正式版"> </div> </div> <div class="ml-4"> <h4 class="font-medium text-dark group-hover:text-primary transition-colors line-clamp-2"> 向上:银河游戏免安装正式版</h4> <p class="text-sm text-muted mt-1">2026-01-23</p> </div> </a> <a href="/download/226185.html" class="flex group"> <div class="flex-shrink-0 w-20 h-20 bg-primary/10 rounded-lg overflow-hidden flex items-center justify-center" style="position: relative;"> <div class="lazy-src" lazy-src="https://images.downcodes.com/uploads/20260115/logo_6968706c955e21.jpg" alt="风暴驭使正式中文版"> </div> </div> <div class="ml-4"> <h4 class="font-medium text-dark group-hover:text-primary transition-colors line-clamp-2"> 风暴驭使正式中文版</h4> <p class="text-sm text-muted mt-1">2026-01-23</p> </div> </a> <a href="/download/226206.html" class="flex group"> <div class="flex-shrink-0 w-20 h-20 bg-primary/10 rounded-lg overflow-hidden flex items-center justify-center" style="position: relative;"> <div class="lazy-src" lazy-src="https://images.downcodes.com/uploads/20260115/logo_696876727dcb61.jpg" alt="冥河:贪婪之刃中文试玩版"> </div> </div> <div class="ml-4"> <h4 class="font-medium text-dark group-hover:text-primary transition-colors line-clamp-2"> 冥河:贪婪之刃中文试玩版</h4> <p class="text-sm text-muted mt-1">2026-01-23</p> </div> </a> <a href="/download/226207.html" class="flex group"> <div class="flex-shrink-0 w-20 h-20 bg-primary/10 rounded-lg overflow-hidden flex items-center justify-center" style="position: relative;"> <div class="lazy-src" lazy-src="https://images.downcodes.com/uploads/20260115/logo_6968767dddbfc1.jpg" alt="超级键盘侠免安装绿色中文版"> </div> </div> <div class="ml-4"> <h4 class="font-medium text-dark group-hover:text-primary transition-colors line-clamp-2"> 超级键盘侠免安装绿色中文版</h4> <p class="text-sm text-muted mt-1">2026-01-23</p> </div> </a> </div> </div> </div> </div> </main> <!-- footer --> <footer class="bg-neutral-800 text-white pt-12 pb-6"> <div class="container mx-auto px-4 sm:px-6 lg:px-8"> <div class="copyright"> <a href="javascript:void(0)">关于本站</a> |  <a href="javascript:void(0)">版权声明</a> | <a href="javascript:void(0)">合作联系</a> | <a href="/download/allcategory.html">网站地图</a> |  <a href="javascript:void(0)">帮助中心</a>  </div> <p class="text_info">Copyright © 2006-2025 downcodes.com | 联系:ymdowncodes@163.com</p> <p class="text_info">备案:<a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">湘ICP备2022016001号-1</a> </p> </div> </footer> </body> <script type="text/javascript" src="/index/js/jquery-1.8.3.min.js"></script> <script src="/assets/ymzy/js/index.js"></script> <script src="/assets/ymzy/prism.min.js"></script> <script> // document.querySelectorAll('.copy-btn').forEach(btn => { btn.addEventListener('click', function() { const textElement = this.closest('.code-block').querySelector('.code-body pre code'); const textarea = document.createElement('textarea'); textarea.value = textElement.textContent; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); const originalHTML = this.innerHTML; this.innerHTML = '✓ Copied!'; setTimeout(() => { this.innerHTML = originalHTML; }, 3000); }); }); // document.querySelectorAll('.copy_btn').forEach(btn => { btn.addEventListener('click', function() { const textElement = this.closest('.input_box').querySelector('.text'); const textarea = document.createElement('textarea'); textarea.value = textElement.textContent; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); const originalHTML = this.innerHTML; this.innerHTML = '✓ Copied!'; this.classList.add('copied'); setTimeout(() => { this.innerHTML = originalHTML; this.classList.remove('copied'); }, 3000); }); }); </script> </html>