diff --git a/FileService/Abstractions/IRootDirectory.cs b/FileService/Abstractions/IRootDirectory.cs new file mode 100644 index 0000000..063df51 --- /dev/null +++ b/FileService/Abstractions/IRootDirectory.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Ufangx.FileServices.Abstractions +{ + public interface IRootDirectory + { + Task GetRoot(); + } +} diff --git a/FileService/Abstractions/IUploader.cs b/FileService/Abstractions/IUploader.cs index 1f84fe6..d8e56e0 100644 --- a/FileService/Abstractions/IUploader.cs +++ b/FileService/Abstractions/IUploader.cs @@ -11,7 +11,7 @@ namespace Ufangx.FileServices.Abstractions { FileValidateResult Validate(IFormFile file, string schemeName=null); FileValidateResult Validate(IFormFileCollection files, string schemeName=null); - Task Handle(IFormFileCollection files, string schemeName = null); + Task Handle(IFormFileCollection files, string schemeName = null, string dir = null); Task Handle(IFormFile file,string schemeName=null, string dir=null,string name=null); } } diff --git a/FileService/FileServices.csproj b/FileService/FileServices.csproj index eb83785..3b4e0a6 100644 --- a/FileService/FileServices.csproj +++ b/FileService/FileServices.csproj @@ -13,7 +13,7 @@ git file service web uploader html5 uploader breakpoint renewal Copyright (c) 2020-$([System.DateTime]::Now.Year) Jackson.Bruce - 1.0.2-beta + 1.0.5 @@ -41,4 +41,8 @@ + + + + diff --git a/FileService/Local/LocalFileService.cs b/FileService/Local/LocalFileService.cs index c8a572f..f937842 100644 --- a/FileService/Local/LocalFileService.cs +++ b/FileService/Local/LocalFileService.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.IO; @@ -6,23 +7,34 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Ufangx.FileServices.Abstractions; +using Microsoft.Extensions.DependencyInjection; namespace Ufangx.FileServices.Local { public class LocalFileService : IFileService { private readonly LocalFileOption option; + private readonly IHttpContextAccessor httpContextAccessor; - public LocalFileService(IOptions option) { + public LocalFileService(IOptions option,IHttpContextAccessor httpContextAccessor) { this.option = option.Value; // option??new LocalFileOption(); if (string.IsNullOrWhiteSpace(this.option.StorageRootDir)) { this.option.StorageRootDir = AppContext.BaseDirectory; } - } - protected string physicalPath(string path) { - return Path.Combine(option.StorageRootDir, path.Trim().Replace('\\', '/').TrimStart('/')); + this.httpContextAccessor = httpContextAccessor; + } + protected async Task physicalPath(string path) { + string root; + var rootService = httpContextAccessor.HttpContext.RequestServices.GetService(); + if (rootService == null || string.IsNullOrWhiteSpace(root = await rootService.GetRoot())) + { + return Path.Combine(option.StorageRootDir, path.Trim().Replace('\\', '/').TrimStart('/')).Replace('\\', '/'); + } + return Path.Combine(option.StorageRootDir, + root.Trim().Replace('\\', '/').TrimStart('/'), + path.Trim().Replace('\\', '/').TrimStart('/')).Replace('\\', '/'); } protected bool CreateDirIfNonexistence(string path) { @@ -34,7 +46,7 @@ namespace Ufangx.FileServices.Local } public async Task Delete(string path, CancellationToken token = default(CancellationToken)) { - string p = physicalPath(path); + string p = await physicalPath(path); if (File.Exists(p)) { File.Delete(p); @@ -45,12 +57,13 @@ namespace Ufangx.FileServices.Local public async Task Exists(string path, CancellationToken token = default(CancellationToken)) { - return await Task.FromResult(File.Exists(physicalPath(path))); + var filePath = await physicalPath(path); + return File.Exists(filePath); } public async Task GetStream(string path, CancellationToken token = default(CancellationToken)) { - var p = physicalPath(path); + var p =await physicalPath(path); if (!File.Exists(p)) return null; return await Task.FromResult(new FileStream(p, FileMode.Open, FileAccess.Read,FileShare.ReadWrite| FileShare.Delete)); @@ -58,7 +71,7 @@ namespace Ufangx.FileServices.Local public async Task GetFileData(string path, CancellationToken token = default(CancellationToken)) { - var p = physicalPath(path); + var p =await physicalPath(path); if (!File.Exists(p)) return null; #if netstandard20 return await Task.FromResult(File.ReadAllBytes(p)); @@ -70,7 +83,7 @@ namespace Ufangx.FileServices.Local public async Task Save(string path, Stream stream, CancellationToken token = default(CancellationToken)) { - var p = physicalPath(path); + var p =await physicalPath(path); if (CreateDirIfNonexistence(p)) { if (stream.CanSeek && stream.Position > 0) { stream.Position = 0; } @@ -95,7 +108,7 @@ namespace Ufangx.FileServices.Local public async Task Save(string path, byte[] data, CancellationToken token = default(CancellationToken)) { - var p = physicalPath(path); + var p = await physicalPath(path); if (CreateDirIfNonexistence(p)) { #if netstandard20 @@ -110,19 +123,20 @@ namespace Ufangx.FileServices.Local return false; } public async Task Move(string sourceFileName,string destFileName) { - sourceFileName = physicalPath(sourceFileName); - destFileName = physicalPath(destFileName); + sourceFileName = await physicalPath(sourceFileName); + destFileName = await physicalPath(destFileName); File.Move(sourceFileName, destFileName); await Task.CompletedTask; } public async Task GetModifyDate(string path, CancellationToken token = default(CancellationToken)) { - return await Task.FromResult(File.GetLastWriteTime(physicalPath(path))); + var filePath = await physicalPath(path); + return File.GetLastWriteTime(filePath); } public async Task Append(string path, Stream stream, CancellationToken token = default(CancellationToken)) { - var p = physicalPath(path); + var p = await physicalPath(path); if (CreateDirIfNonexistence(p)) { if (stream.CanSeek && stream.Position > 0) { stream.Position = 0; } @@ -146,7 +160,7 @@ namespace Ufangx.FileServices.Local public async Task Append(string path, byte[] data, CancellationToken token = default(CancellationToken)) { - var p = physicalPath(path); + var p = await physicalPath(path); if (CreateDirIfNonexistence(p)) { using (var fs = new FileStream(p, FileMode.Append, FileAccess.Write, FileShare.Read)) diff --git a/FileService/Local/LocalResumableService.cs b/FileService/Local/LocalResumableService.cs index 210b7c4..18fa01d 100644 --- a/FileService/Local/LocalResumableService.cs +++ b/FileService/Local/LocalResumableService.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Diagnostics; @@ -14,7 +15,7 @@ namespace Ufangx.FileServices.Local public class LocalResumableService : LocalFileService, IResumableService { private readonly IResumableInfoService resumableInfoService; - public LocalResumableService(IResumableInfoService resumableInfoService, IOptions option):base(option) { + public LocalResumableService(IResumableInfoService resumableInfoService, IOptions option, IHttpContextAccessor httpContextAccessor) :base(option, httpContextAccessor) { this.resumableInfoService = resumableInfoService; } FileStream GetFileStream(string path) { @@ -86,7 +87,7 @@ namespace Ufangx.FileServices.Local if (info == null) { throw new Exception($"无效的{nameof(blob.ResumableKey)}"); } - var p = physicalPath(info.StoreName); + var p =await physicalPath(info.StoreName); string tempdir = GetTempDir(p,info.Key); var tmp = Path.Combine(tempdir, $"{blob.BlobIndex}").Replace('\\','/'); if (CreateDirIfNonexistence(tmp)) @@ -141,7 +142,7 @@ namespace Ufangx.FileServices.Local } if (await resumableInfoService.Delete(info)) { - string tempdir = GetTempDir(physicalPath(info.StoreName), info.Key); + string tempdir = GetTempDir(await physicalPath(info.StoreName), info.Key); try { Directory.Delete(tempdir, true); diff --git a/FileService/Middlewares/FileServiceUploaderMiddleware.cs b/FileService/Middlewares/FileServiceUploaderMiddleware.cs index fe01aa3..7eb6e6c 100644 --- a/FileService/Middlewares/FileServiceUploaderMiddleware.cs +++ b/FileService/Middlewares/FileServiceUploaderMiddleware.cs @@ -30,7 +30,7 @@ namespace Ufangx.FileServices.Middlewares //如果有文件验证失败则返回 return; } - await WriteJsonAsync(context, await uploader.Handle(context.Request.Form.Files, _scheme)); + await WriteJsonAsync(context, await uploader.Handle(context.Request.Form.Files, _scheme,dir)); return; } @@ -40,7 +40,7 @@ namespace Ufangx.FileServices.Middlewares { return; } - await WriteJsonAsync(context, await uploader.Handle(context.Request.Form.Files[0], _scheme)); + await WriteJsonAsync(context, await uploader.Handle(context.Request.Form.Files[0], _scheme,dir,fileName)); } } } diff --git a/FileService/Models/FileServiceBuilder.cs b/FileService/Models/FileServiceBuilder.cs index e15d814..c4b98f5 100644 --- a/FileService/Models/FileServiceBuilder.cs +++ b/FileService/Models/FileServiceBuilder.cs @@ -42,7 +42,7 @@ namespace Ufangx.FileServices.Models { Services.Configure(opt => opt.AddScheme(name, storeDirectory, supportExtensions, LimitedSize)); - Services.AddTransient(); + //Services.AddTransient();//外面注入 return this; } } diff --git a/FileService/Services/Uploader.cs b/FileService/Services/Uploader.cs index b5a0ded..ec9fd57 100644 --- a/FileService/Services/Uploader.cs +++ b/FileService/Services/Uploader.cs @@ -76,12 +76,12 @@ namespace Ufangx.FileServices.Services //否则生成文件名称 return await GenerateFileName(scheme, originName, dir); } - public async Task Handle(IFormFileCollection files, string schemeName = null) + public async Task Handle(IFormFileCollection files, string schemeName = null, string dir = null) { List results = new List(); foreach (var file in files) { - var result = await Handle(file, schemeName); + var result = await Handle(file, schemeName, dir); if (result != null){ results.Add(result); } } return results; diff --git a/Qiniu/FileService.cs b/Qiniu/FileService.cs index 9eaa912..a30dc43 100644 --- a/Qiniu/FileService.cs +++ b/Qiniu/FileService.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; using Qiniu.Http; using Qiniu.Storage; using Qiniu.Util; @@ -8,6 +9,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Ufangx.FileServices.Abstractions; +using Microsoft.Extensions.DependencyInjection; namespace Qiniu { @@ -16,8 +18,9 @@ namespace Qiniu protected readonly FileServiceOptions options; protected readonly Mac mac; protected readonly Config config; + protected readonly IHttpContextAccessor contextAccessor; - public FileService(IOptions options) + public FileService(IOptions options, IHttpContextAccessor contextAccessor) { if (options is null) { @@ -67,6 +70,8 @@ namespace Qiniu break; } } + + this.contextAccessor = contextAccessor; } public Task Append(string path, Stream stream, CancellationToken token = default) @@ -85,7 +90,7 @@ namespace Qiniu => await Append(path, new MemoryStream(data), token); public async Task Delete(string path, CancellationToken token = default) - => (await GetBucketManager().Delete(options.Bucket, GetSaveKey(path))).Code == (int)HttpCode.OK; + => (await GetBucketManager().Delete(options.Bucket,await GetSaveKey(path))).Code == (int)HttpCode.OK; //(await Task.FromResult(GetBucketManager().Delete(options.Bucket, GetSaveKey(path)))).Code == (int)HttpCode.OK; public async Task Exists(string path, CancellationToken token = default) @@ -93,9 +98,9 @@ namespace Qiniu var result = await GetInfo(path); return result.Code == (int)HttpCode.OK; } - string GetDownloadUrl(string path) + async Task GetDownloadUrl(string path) { - var key = GetSaveKey(path); + var key =await GetSaveKey(path); string baseUrl = options.Domain.Trim(); baseUrl = baseUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || baseUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase) ? baseUrl : "http://" + baseUrl; @@ -105,13 +110,13 @@ namespace Qiniu } public async Task GetFileData(string path, CancellationToken token = default) { - var url = GetDownloadUrl(path); + var url =await GetDownloadUrl(path); HttpClient client = new HttpClient(); return await client.GetByteArrayAsync(url); } async Task GetInfo(string path) => await - GetBucketManager().Stat(options.Bucket, GetSaveKey(path)); + GetBucketManager().Stat(options.Bucket,await GetSaveKey(path)); //Task.FromResult(GetBucketManager().Stat(options.Bucket, GetSaveKey(path))); public async Task GetModifyDate(string path, CancellationToken token = default) { @@ -124,7 +129,7 @@ namespace Qiniu } public async Task GetStream(string path, CancellationToken token = default) { - var url = GetDownloadUrl(path); + var url =await GetDownloadUrl(path); HttpClient client = new HttpClient(); return await client.GetStreamAsync(url); @@ -135,15 +140,15 @@ namespace Qiniu { BucketManager bucket = GetBucketManager(); //var result = await Task.FromResult(bucket.Move(options.Bucket, GetSaveKey(sourceFileName), options.Bucket, GetSaveKey(destFileName))); - var result = await bucket.Move(options.Bucket, GetSaveKey(sourceFileName), options.Bucket, GetSaveKey(destFileName)); + var result = await bucket.Move(options.Bucket,await GetSaveKey(sourceFileName), options.Bucket,await GetSaveKey(destFileName)); if (result.Code != (int)HttpCode.OK) { throw new Exception(result.Text); } } - string GetSaveKey(string path) + Task GetSaveKey(string path) { - return Utils.GetSaveKey(options.BasePath, path); + return contextAccessor.GetSaveKey(options.BasePath, path); } string GetToken(string savekey) { @@ -179,7 +184,7 @@ namespace Qiniu public async Task Save(string path, byte[] data, CancellationToken token = default) { - var key = GetSaveKey(path); + var key =await GetSaveKey(path); var uploadManager = GetUploadManager(); //var result = await Task.FromResult(uploadManager.UploadData(data, key, GetToken(key), null)); var result = await uploadManager.UploadData(data, key, GetToken(key), null); diff --git a/Qiniu/Qiniu.FileService.csproj b/Qiniu/Qiniu.FileService.csproj index 6f8a333..061f64d 100644 --- a/Qiniu/Qiniu.FileService.csproj +++ b/Qiniu/Qiniu.FileService.csproj @@ -15,7 +15,7 @@ 1.0.0-beta.1 - + diff --git a/Qiniu/QiniuResumableInfoService.cs b/Qiniu/QiniuResumableInfoService.cs index 040533d..326f2cb 100644 --- a/Qiniu/QiniuResumableInfoService.cs +++ b/Qiniu/QiniuResumableInfoService.cs @@ -31,7 +31,7 @@ namespace Qiniu info = (ResumableInfo)(await base.Create(storeName, fileName, fileSize, fileType, blobCount, blobSize)); } if (string.IsNullOrWhiteSpace(info.UploadToken)) { - info.UploadToken = Utils.GetToken(Utils.GetSaveKey(options.BasePath, info.StoreName), options.AccessKey, options.SecretKey, options.Bucket); + info.UploadToken = Utils.GetToken(await contextAccessor.GetSaveKey(options.BasePath, info.StoreName), options.AccessKey, options.SecretKey, options.Bucket); await Update(info); } return info; diff --git a/Qiniu/ResumableService.cs b/Qiniu/ResumableService.cs index fe955e1..d54695e 100644 --- a/Qiniu/ResumableService.cs +++ b/Qiniu/ResumableService.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Qiniu.Http; @@ -20,7 +21,7 @@ namespace Qiniu private readonly ILogger logger; private readonly HttpManager _httpManager; - public ResumableService(IResumableInfoService resumableInfoService,ILogger logger, IOptions options) : base(options) + public ResumableService(IResumableInfoService resumableInfoService,ILogger logger, IOptions options, IHttpContextAccessor contextAccessor) : base(options, contextAccessor) { this.resumableInfoService = resumableInfoService; this.logger = logger; @@ -129,7 +130,7 @@ namespace Qiniu } private async Task MakeFile(ResumableInfo info) { - string key = Utils.GetSaveKey(options.BasePath, info.StoreName); + string key = await contextAccessor.GetSaveKey(options.BasePath, info.StoreName); string fileName = key; long size = info.FileSize; string upToken = info.UploadToken; diff --git a/Qiniu/Utils.cs b/Qiniu/Utils.cs index 3b903ee..0556d63 100644 --- a/Qiniu/Utils.cs +++ b/Qiniu/Utils.cs @@ -1,21 +1,34 @@ -using Qiniu.Storage; +using Microsoft.AspNetCore.Http; +using Qiniu.Storage; using Qiniu.Util; using System; using System.Collections.Generic; using System.IO; using System.Text; +using System.Threading.Tasks; +using Ufangx.FileServices.Abstractions; +using Microsoft.Extensions.DependencyInjection; namespace Qiniu { internal static class Utils { - public static string GetSaveKey(string basePath, string path) + static async Task GetRootDir(IHttpContextAccessor contextAccessor,string basePath) + { + string root; + var rootService = contextAccessor.HttpContext.RequestServices.GetService(); + if (rootService == null || string.IsNullOrWhiteSpace(root = await rootService.GetRoot())) return basePath; + return Path.Combine(basePath, root.Trim().Replace('\\', '/').TrimStart('/')).Replace('\\', '/'); + } + + public static async Task GetSaveKey(this IHttpContextAccessor contextAccessor, string basePath, string path) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("message", nameof(path)); } - return Path.Combine(basePath, path.TrimStart('/', '\\')).Trim().ToLower().Replace('\\', '/'); + var root =await GetRootDir(contextAccessor, basePath); + return Path.Combine(root, path.TrimStart('/', '\\')).Trim().ToLower().Replace('\\', '/'); } public static string GetToken(string savekey,string ak,string sk,string bucket,int expires=3600) { diff --git a/TestWeb/Properties/launchSettings.json b/TestWeb/Properties/launchSettings.json index b8a6b49..6501e34 100644 --- a/TestWeb/Properties/launchSettings.json +++ b/TestWeb/Properties/launchSettings.json @@ -21,7 +21,7 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "https://localhost:5001;http://localhost:5000" + "applicationUrl": "https://localhost:8001;http://localhost:8000" }, "Docker": { "commandName": "Docker", diff --git a/TestWeb/Startup.cs b/TestWeb/Startup.cs index e258350..bbafb70 100644 --- a/TestWeb/Startup.cs +++ b/TestWeb/Startup.cs @@ -95,6 +95,7 @@ namespace TestWeb app.UseRouting(); app.UseAuthorization(); + app.UseFileServices("/api"); //app.Use(next => async ctx => //{ // try @@ -105,12 +106,11 @@ namespace TestWeb // throw ex; // } //}); - app.UseFileServices("/api"); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", - pattern: "api/{controller=Home}/{action=Index}/{id?}"); + pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } diff --git a/TestWeb/Views/Home/Index.cshtml b/TestWeb/Views/Home/Index.cshtml index d2d19bd..2376ef7 100644 --- a/TestWeb/Views/Home/Index.cshtml +++ b/TestWeb/Views/Home/Index.cshtml @@ -5,4 +5,5 @@

Welcome

Learn about building Web apps with ASP.NET Core.

+ test
diff --git a/TestWeb/wwwroot/documents/20210720141529_xx_菜单(1) - 副本.json b/TestWeb/wwwroot/documents/20210720141529_xx_菜单(1) - 副本.json new file mode 100644 index 0000000..678a352 --- /dev/null +++ b/TestWeb/wwwroot/documents/20210720141529_xx_菜单(1) - 副本.json @@ -0,0 +1,2 @@ +categories +[{"order":1,"name":"运营","path":"","icon":"operating","notes":"","enabled":true,"children":[{"order":1,"name":"订单","path":"","icon":"order","notes":"","enabled":true,"children":[{"order":1,"name":"待发订单","path":"/orders/unconsigned","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"orders:unconsigned","notes":"","enabled":true,"default":true}]},{"order":2,"name":"订单查询","path":"/orders","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"orders","notes":"","enabled":true,"default":true},{"name":"移至回收站","code":"移至回收站","key":"orders:rem","notes":"","enabled":true,"default":false},{"name":"彻底删除","code":"彻底删除","key":"orders:del","notes":"","enabled":true,"default":false}]},{"order":3,"name":"订单审核","path":"/orders/auditing","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"审核","code":"审核","key":"orders:audit","notes":"","enabled":true,"default":true}]}],"actions":[]},{"order":2,"name":"商品","path":"","icon":"goods","notes":"","enabled":true,"children":[{"order":1,"name":"商品管理","path":"/goods","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"goods","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"goods:del","notes":"","enabled":true,"default":false},{"name":"编辑","code":"编辑","key":"goods:mod","notes":"","enabled":true,"default":false}]},{"order":2,"name":"辅助设置","path":"","icon":"","notes":"","enabled":true,"children":[{"order":1,"name":"品牌","path":"/brands","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"brands","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"brands:del","notes":"","enabled":true,"default":false}]},{"order":2,"name":"类目","path":"/categories","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"categories","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"categories:del","notes":"","enabled":true,"default":false}]},{"order":3,"name":"分组","path":"/groups","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"groups","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"groups:del","notes":"","enabled":true,"default":false}]},{"order":4,"name":"标签","path":"/tags","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"tags","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"tags:del","notes":"","enabled":true,"default":false}]},{"order":5,"name":"规格","path":"/specifications","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"specifications","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"specifications:del","notes":"","enabled":true,"default":false}]},{"order":6,"name":"单位","path":"/units","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"units","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"units:del","notes":"","enabled":true,"default":false}]}],"actions":[]}],"actions":[]},{"order":3,"name":"售后","path":"","icon":"aftersales","notes":"","enabled":true,"children":[{"order":1,"name":"审核申请","path":"/aftersales","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"aftersales","notes":"","enabled":true,"default":true}]},{"order":2,"name":"待受理","path":"/aftersales/amjne","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"aftersales:amine","notes":"","enabled":true,"default":true}]},{"order":3,"name":"受理中","path":"/aftersales/processing","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"aftersales:processing","notes":"","enabled":true,"default":true}]},{"order":4,"name":"已完成","path":"/aftersales/finished","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"aftersales:finished","notes":"","enabled":true,"default":true}]},{"order":5,"name":"单据回收站","path":"/aftersales/recycle","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"aftersales:recycle","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"aftersales:del","notes":"","enabled":true,"default":false}]}],"actions":[]}],"actions":[]},{"order":2,"name":"营销","path":"","icon":"trumpet","notes":"","enabled":true,"children":[{"order":1,"name":"促销方案","path":"/promotes","icon":"promote","notes":"","enabled":true,"children":[],"actions":[{"name":"商品管理","code":"商品管理","key":"promotes:goods","notes":"","enabled":true,"default":false},{"name":"数据接口","code":"数据接口","key":"promotes","notes":"","enabled":true,"default":true},{"name":"状态维护","code":"状态维护","key":"promotes:state","notes":"","enabled":true,"default":false},{"name":"编辑","code":"编辑","key":"promotes:mod","notes":"","enabled":true,"default":false},{"name":"删除","code":"删除","key":"promotes:del","notes":"","enabled":true,"default":false},{"name":"批量调价","code":"批量调价","key":"promotes:goods:price","notes":"","enabled":true,"default":false},{"name":"移除商品","code":"移除商品","key":"promotes:goods:del","notes":"","enabled":true,"default":false}]},{"order":2,"name":"积分管理","path":"/integral","icon":"integral","notes":"","enabled":true,"children":[],"actions":[{"name":"积分配置","code":"积分配置","key":"integral:config","notes":"","enabled":true,"default":false},{"name":"数据接口","code":"数据接口","key":"integral","notes":"","enabled":true,"default":true}]},{"order":3,"name":"优惠券","path":"","icon":"coupons","notes":"","enabled":true,"children":[{"order":1,"name":"优惠券管理","path":"/coupons","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"coupons","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"coupons:del","notes":"","enabled":true,"default":false},{"name":"状态","code":"状态","key":"coupons:status","notes":"","enabled":true,"default":false}]},{"order":2,"name":"领取记录","path":"/coupons/takes","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"coupons:takes","notes":"","enabled":true,"default":true}]}],"actions":[]}],"actions":[]},{"order":3,"name":"客户","path":"","icon":"customers","notes":"","enabled":true,"children":[{"order":1,"name":"客户管理","path":"/customers","icon":"customer-mgr","notes":"","enabled":true,"children":[],"actions":[{"name":"删除","code":"删除","key":"customers:del","notes":"","enabled":true,"default":false},{"name":"数据接口","code":"数据接口","key":"customers","notes":"","enabled":true,"default":true}]},{"order":2,"name":"客户类型","path":"/customers/ranks","icon":"customer-ranks","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"customer:ranks","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"customer:ranks:del","notes":"","enabled":true,"default":false}]},{"order":3,"name":"分销经纪人","path":"","icon":"brokers","notes":"","enabled":true,"children":[{"order":1,"name":"计佣规则","path":"/brokers/rules","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"broker:rule","notes":"","enabled":true,"default":true},{"name":"状态","code":"状态","key":"broker:rule:stat","notes":"","enabled":true,"default":false},{"name":"删除","code":"删除","key":"broker:rule:del","notes":"","enabled":true,"default":false},{"name":"设置","code":"设置","key":"broker:settings","notes":"","enabled":true,"default":false}]},{"order":2,"name":"经纪人列表","path":"/brokers","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"删除","code":"删除","key":"broker:del","notes":"","enabled":true,"default":false},{"name":"数据接口","code":"数据接口","key":"broker","notes":"","enabled":true,"default":true}]},{"order":3,"name":"结佣申请","path":"/brokers/closes","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"broker:closes","notes":"","enabled":true,"default":true},{"name":"结佣","code":"结佣","key":"broker:close","notes":"","enabled":true,"default":false}]},{"order":4,"name":"提现申请","path":"/brokers/withdrawal","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"withdrawals","notes":"","enabled":true,"default":true},{"name":"审核","code":"审核","key":"withdrawals:auditing","notes":"","enabled":true,"default":false}]}],"actions":[]}],"actions":[]},{"order":4,"name":"资源","path":"","icon":"resoures","notes":"","enabled":true,"children":[{"order":1,"name":"照片","path":"/pictures","icon":"img","notes":"","enabled":true,"children":[],"actions":[{"name":"删除","code":"删除","key":"resource:pictures:del","notes":"","enabled":true,"default":false},{"name":"数据接口","code":"数据接口","key":"resource:pictures","notes":"","enabled":true,"default":true}]},{"order":2,"name":"视频","path":"/videos","icon":"video1","notes":"","enabled":true,"children":[],"actions":[{"name":"列表","code":"列表","key":"resource:videos","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"resource:videos:del","notes":"","enabled":true,"default":false}]},{"order":3,"name":"文档","path":"/documents","icon":"file","notes":"","enabled":true,"children":[],"actions":[{"name":"列表","code":"列表","key":"resource:documents","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"resource:documents:del","notes":"","enabled":true,"default":false}]}],"actions":[]},{"order":5,"name":"系统","path":"","icon":"configs","notes":"","enabled":true,"children":[{"order":1,"name":"认证","path":"","icon":"authentication","notes":"","enabled":true,"children":[{"order":1,"name":"用户管理","path":"/authentication","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"authenticate:memberships","notes":"","enabled":true,"default":true},{"name":"状态维护","code":"状态维护","key":"authenticate:memberships:state","notes":"","enabled":true,"default":false}]},{"order":2,"name":"开放认证","path":"/authentication/external","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"authenticate:external","notes":"","enabled":true,"default":true},{"name":"编辑","code":"编辑","key":"authenticate:external:mod","notes":"","enabled":true,"default":false},{"name":"删除","code":"删除","key":"authenticate:external:del","notes":"","enabled":true,"default":false}]}],"actions":[]},{"order":2,"name":"授权","path":"","icon":"authorizations","notes":"","enabled":true,"children":[{"order":1,"name":"项目","path":"/authorizations","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"authorise:projects","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"authorise:projects:del","notes":"","enabled":true,"default":false},{"name":"添加/编辑","code":"添加/编辑","key":"authorise:projects:mod","notes":"","enabled":true,"default":false},{"name":"菜单管理","code":"菜单管理","key":"authorise:projects:menus","notes":"","enabled":true,"default":false},{"name":"删除菜单","code":"删除菜单","key":"authorise:projects:menus:del","notes":"","enabled":true,"default":false},{"name":"更新菜单","code":"更新菜单","key":"authorise:projects:menus:mod","notes":"","enabled":true,"default":false}]},{"order":2,"name":"角色","path":"/authorizations/roles","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"authorise:roles","notes":"","enabled":true,"default":true},{"name":"添加/编辑","code":"添加/编辑","key":"authorise:roles:mod","notes":"","enabled":true,"default":false},{"name":"删除","code":"删除","key":"authorise:roles:del","notes":"","enabled":true,"default":false}]},{"order":3,"name":"角色授权","path":"/authorizations/authorize","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"authorise","notes":"","enabled":true,"default":true},{"name":"编辑","code":"编辑","key":"authorise:mod","notes":"","enabled":true,"default":false}]}],"actions":[]},{"order":3,"name":"短信","path":"","icon":"sms","notes":"","enabled":true,"children":[{"order":1,"name":"短信模板","path":"/sms/templates","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"列表","code":"列表","key":"sms:templates","notes":"","enabled":true,"default":true},{"name":"编辑","code":"编辑","key":"sms:templates:mod","notes":"","enabled":true,"default":false},{"name":"删除","code":"删除","key":"sms:templates:del","notes":"","enabled":true,"default":false}]},{"order":2,"name":"模板映射","path":"/sms/templates/maps","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"列表","code":"列表","key":"sms:maps","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"sms:maps:del","notes":"","enabled":true,"default":false},{"name":"编辑","code":"编辑","key":"sms:maps:mod","notes":"","enabled":true,"default":false}]},{"order":3,"name":"发送日志","path":"/sms/logs","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"sms:logs","notes":"","enabled":true,"default":true},{"name":"详情","code":"详情","key":"sms:logs:view","notes":"","enabled":true,"default":false},{"name":"删除","code":"删除","key":"sms:logs:del","notes":"","enabled":true,"default":false}]}],"actions":[]},{"order":4,"name":"配置","path":"","icon":"settings","notes":"","enabled":true,"children":[{"order":1,"name":"页面配置","path":"/pageconfig","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"数据接口","code":"数据接口","key":"pageconfig","notes":"","enabled":true,"default":true}]}],"actions":[]},{"order":5,"name":"组织","path":"","icon":"organization","notes":"","enabled":true,"children":[{"order":1,"name":"部门管理","path":"/organization/departments","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"删除","code":"删除","key":"departments:del","notes":"","enabled":true,"default":false},{"name":"数据接口","code":"数据接口","key":"departments","notes":"","enabled":true,"default":true}]},{"order":2,"name":"员工管理","path":"/organization/admins","icon":"","notes":"","enabled":true,"children":[],"actions":[{"name":"角色维护","code":"角色维护","key":"authenticate:memberships:roles","notes":"","enabled":true,"default":false},{"name":"数据接口","code":"数据接口","key":"admins","notes":"","enabled":true,"default":true},{"name":"删除","code":"删除","key":"admins:del","notes":"","enabled":true,"default":false}]}],"actions":[]},{"order":6,"name":"全球化","path":"","icon":"","notes":"","enabled":false,"children":[{"order":1,"name":"语言支持","path":"","icon":"","notes":"","enabled":false,"children":[],"actions":[{"name":"列表","code":"列表","key":"non","notes":"","enabled":true,"default":true}]}],"actions":[]}],"actions":[]}] \ No newline at end of file diff --git a/TestWeb/wwwroot/documents/20210720142003_xx_分享海报 (1).png b/TestWeb/wwwroot/documents/20210720142003_xx_分享海报 (1).png new file mode 100644 index 0000000..e88e650 Binary files /dev/null and b/TestWeb/wwwroot/documents/20210720142003_xx_分享海报 (1).png differ diff --git a/TestWeb/wwwroot/documents/test/kkk/20210720144348_xx_客户端哈希加密.zip b/TestWeb/wwwroot/documents/test/kkk/20210720144348_xx_客户端哈希加密.zip new file mode 100644 index 0000000..21f6492 Binary files /dev/null and b/TestWeb/wwwroot/documents/test/kkk/20210720144348_xx_客户端哈希加密.zip differ