From b4e759cf6923f44636c6cf80bd45c54f804be4ae Mon Sep 17 00:00:00 2001 From: lijianyou Date: Tue, 30 Sep 2025 15:00:32 +0800 Subject: [PATCH] init --- .config/dotnet-tools.json | 12 + .dockerignore | 30 + .gitignore | 6 + Appsettings.cs | 77 + Controllers/AuthController.cs | 164 + Controllers/ConfigController.cs | 147 + Controllers/LogsController.cs | 39 + Controllers/VideoController.cs | 56 + Dockerfile | 10 + Program.cs | 326 + .../PublishProfiles/FolderProfile.pubxml | 21 + .../PublishProfiles/FolderProfile.pubxml.user | 11 + Properties/launchSettings.json | 37 + SecUserId.png | Bin 25308 -> 0 bytes app/.babelrc | 3 + app/.env | 2 + app/.env.development | 2 + app/.env.github | 1 + app/.gitignore | 16 + app/.prettierrc.json | 22 + app/LICENSE | 21 + app/README-en_US.md | 83 + app/README.md | 84 + app/gulpfile.babel.js/index.js | 86 + app/gulpfile.babel.js/transform.js | 19 + app/gulpfile.babel.js/vueTemplateTsc.js | 152 + app/index.html | 128 + app/jsconfig.json | 12 + app/logo1.png | Bin 0 -> 3068 bytes app/package.json | 74 + app/pnpm-lock.yaml | 7510 +++++++++++++++++ app/postcss.config.cjs | 3 + app/public/grid.svg | 7 + app/public/logo.png | Bin 0 -> 3828 bytes app/public/vite.svg | 1 + app/src/App.vue | 147 + app/src/assets/avatar.png | Bin 0 -> 3152 bytes app/src/assets/logo.png | Bin 0 -> 5057 bytes app/src/assets/logo1.png | Bin 0 -> 3068 bytes app/src/assets/swagger.png | Bin 0 -> 2234 bytes app/src/assets/theme/china-red.png | Bin 0 -> 59944 bytes app/src/assets/theme/green.png | Bin 0 -> 63463 bytes app/src/assets/theme/header-dark.png | Bin 0 -> 44834 bytes app/src/assets/theme/idea.png | Bin 0 -> 55559 bytes app/src/assets/theme/light.png | Bin 0 -> 42820 bytes app/src/assets/theme/orange.png | Bin 0 -> 62527 bytes app/src/assets/theme/pink.png | Bin 0 -> 63003 bytes app/src/assets/theme/purple.png | Bin 0 -> 61773 bytes app/src/assets/theme/side-dark.png | Bin 0 -> 44534 bytes app/src/assets/theme/vscode.png | Bin 0 -> 59654 bytes app/src/components/avatar/AvatarList.vue | 30 + app/src/components/chart/BarChart.vue | 110 + app/src/components/chart/LineChart.vue | 116 + .../components/editable-cell/EditableCell.vue | 142 + app/src/components/editable-cell/index.ts | 2 + app/src/components/format/Splitter.vue | 49 + app/src/components/fullscreen/Fullscreen.vue | 32 + app/src/components/guider/Guider.vue | 366 + app/src/components/guider/index.ts | 4 + app/src/components/guider/interface.d.ts | 7 + app/src/components/layout/BlankView.vue | 4 + app/src/components/layout/CommonView.vue | 86 + app/src/components/layout/FrontView copy.vue | 118 + app/src/components/layout/FrontView.vue | 65 + app/src/components/layout/HeaderActions.vue | 100 + app/src/components/layout/LinkView.vue | 3 + app/src/components/layout/PageFooter.vue | 41 + app/src/components/layout/index.ts | 5 + app/src/components/list/GridList.vue | 59 + app/src/components/loaders/JumpSquare.vue | 71 + app/src/components/loaders/MatrixLoader.vue | 529 ++ app/src/components/loaders/ReadingLoader.vue | 252 + app/src/components/notice/Notice.vue | 54 + app/src/components/selector/IconSelector.vue | 289 + app/src/components/setting/Setting.vue | 23 + app/src/components/setting/index.ts | 2 + .../statistic/MiniStatisticCard.vue | 31 + .../components/statistic/OverviewTitle.vue | 41 + app/src/components/switch/DayNightSwitch.vue | 85 + app/src/global.d.ts | 28 + app/src/main.ts | 26 + app/src/pages/Demo.vue | 9 + app/src/pages/Exp403.vue | 17 + app/src/pages/Exp404.vue | 42 + app/src/pages/Test.vue | 107 + app/src/pages/cok/CookieTable.vue | 419 + app/src/pages/cok/Table.vue | 8 + app/src/pages/cok/index.ts | 2 + app/src/pages/index.ts | 17 + app/src/pages/init/Init.vue | 129 + app/src/pages/init/index.ts | 3 + app/src/pages/login/Login.vue | 56 + app/src/pages/login/LoginBox.vue | 62 + app/src/pages/login/LoginModal.vue | 50 + app/src/pages/login/index.ts | 3 + app/src/pages/mylogs/MyLogs.vue | 79 + app/src/pages/mylogs/index.ts | 3 + app/src/pages/personal/EmailSet.vue | 173 + app/src/pages/personal/MyPersonal.vue | 206 + app/src/pages/personal/index.ts | 4 + app/src/pages/set/AppSet.vue | 114 + app/src/pages/set/index.ts | 2 + app/src/pages/theme/Theme.vue | 144 + app/src/pages/theme/index.ts | 2 + app/src/pages/workplace/RecordTable.vue | 161 + app/src/pages/workplace/Records.vue | 20 + app/src/pages/workplace/Workplace.vue | 20 + app/src/pages/workplace/index.ts | 2 + app/src/pages/workplace/statics.vue | 922 ++ app/src/plugins/auth/auth-plugin.ts | 128 + app/src/plugins/auth/auth.css | 6 + app/src/plugins/iconfont/IconFont.vue | 10 + app/src/plugins/iconfont/index.ts | 32 + app/src/plugins/index.ts | 2 + app/src/router/dynamicRoutes.ts | 248 + app/src/router/guards.ts | 110 + app/src/router/index.ts | 17 + app/src/router/interface.d.ts | 63 + app/src/router/routes.ts | 175 + app/src/store/account.ts | 79 + app/src/store/coreapi.ts | 181 + app/src/store/http.ts | 76 + app/src/store/index.ts | 10 + app/src/store/menu.ts | 266 + app/src/store/setting.ts | 36 + app/src/theme/antd/card.less | 11 + app/src/theme/antd/description.less | 7 + app/src/theme/antd/index.less | 3 + app/src/theme/antd/table.less | 6 + app/src/theme/index.less | 7 + app/src/theme/index.ts | 109 + app/src/theme/style/component.less | 5 + app/src/theme/style/index.less | 14 + app/src/theme/style/layout.less | 32 + app/src/theme/style/nprogress.less | 3 + app/src/types/index.ts | 14 + app/src/types/theme.d.ts | 9 + app/src/utils/axiosHttp.ts | 161 + app/src/utils/file.ts | 51 + app/src/utils/formatter.ts | 38 + app/src/utils/helpers.ts | 8 + app/src/utils/htmlHelper.ts | 103 + app/src/utils/regexHelper.ts | 49 + app/src/utils/useModelValue.ts | 21 + app/src/utils/useTheme.ts | 21 + app/src/vite-env.d.ts | 16 + app/tailwind.config.cjs | 36 + app/tsconfig.json | 24 + app/tsconfig.node.json | 9 + app/vite.config.ts | 95 + app/yarn | 0 appsettings.json | 4 + configa.png | Bin 103866 -> 0 bytes cookaaaa.png | Bin 88145 -> 0 bytes cookie.png | Bin 194940 -> 0 bytes db/dy.sqlite | Bin 0 -> 155648 bytes dto/CollectVideoInfo.cs | 1252 +++ dto/CollectVideoRequestDto.cs | 10 + dto/InitSystemInfo.cs | 43 + dto/UserDto.cs | 29 + dto/VideoNFOInfo.cs | 126 + dto/VideoNfo.cs | 25 + dto/VideoPageRequestDTO.cs | 26 + dto/VideoStaticsDto.cs | 34 + dy.net.csproj | 92 + dy.net.csproj.user | 12 + dy.net.sln | 25 + extension/ServiceExtension.cs | 477 ++ extension/ServiceLifetimeAttribute.cs | 17 + getcookies.png | Bin 632444 -> 0 bytes homepage.png | Bin 292636 -> 0 bytes image.png | Bin 241915 -> 0 bytes image111.png | Bin 1502982 -> 0 bytes image222.png | Bin 281652 -> 0 bytes image33.png | Bin 103425 -> 0 bytes image4.png | Bin 117586 -> 0 bytes image55.png | Bin 376393 -> 0 bytes job/DouYinCollectSyncJob.cs | 319 + job/DouYinFavoritSyncJob.cs | 328 + logs.png | Bin 250568 -> 0 bytes model/AppConfig.cs | 24 + model/DyCollectVideo.cs | 130 + model/DyUserCookies.cs | 45 + model/LoginUserInfo.cs | 36 + records.png | Bin 291555 -> 0 bytes repository/BaseRepository.cs | 412 + repository/DyCollectVideoRepository.cs | 63 + repository/DyCookieRepository.cs | 29 + repository/UserRepository.cs | 103 + service/CommonService.cs | 67 + service/DyCollectVideoService.cs | 90 + service/DyCookieService.cs | 70 + service/DyHttpClientService.cs | 314 + service/QuartzJobService.cs | 138 + service/UserService.cs | 38 + utils/BogusManager.cs | 174 + utils/ByteToGbConverter.cs | 20 + utils/CookieValidator.cs | 69 + utils/DateTimeUtil.cs | 32 + utils/Md5Util.cs | 37 + utils/NfoFileGenerator.cs | 51 + utils/NfoGenerator.cs | 128 + 202 files changed, 22035 insertions(+) create mode 100644 .config/dotnet-tools.json create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 Appsettings.cs create mode 100644 Controllers/AuthController.cs create mode 100644 Controllers/ConfigController.cs create mode 100644 Controllers/LogsController.cs create mode 100644 Controllers/VideoController.cs create mode 100644 Dockerfile create mode 100644 Program.cs create mode 100644 Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 Properties/PublishProfiles/FolderProfile.pubxml.user create mode 100644 Properties/launchSettings.json delete mode 100644 SecUserId.png create mode 100644 app/.babelrc create mode 100644 app/.env create mode 100644 app/.env.development create mode 100644 app/.env.github create mode 100644 app/.gitignore create mode 100644 app/.prettierrc.json create mode 100644 app/LICENSE create mode 100644 app/README-en_US.md create mode 100644 app/README.md create mode 100644 app/gulpfile.babel.js/index.js create mode 100644 app/gulpfile.babel.js/transform.js create mode 100644 app/gulpfile.babel.js/vueTemplateTsc.js create mode 100644 app/index.html create mode 100644 app/jsconfig.json create mode 100644 app/logo1.png create mode 100644 app/package.json create mode 100644 app/pnpm-lock.yaml create mode 100644 app/postcss.config.cjs create mode 100644 app/public/grid.svg create mode 100644 app/public/logo.png create mode 100644 app/public/vite.svg create mode 100644 app/src/App.vue create mode 100644 app/src/assets/avatar.png create mode 100644 app/src/assets/logo.png create mode 100644 app/src/assets/logo1.png create mode 100644 app/src/assets/swagger.png create mode 100644 app/src/assets/theme/china-red.png create mode 100644 app/src/assets/theme/green.png create mode 100644 app/src/assets/theme/header-dark.png create mode 100644 app/src/assets/theme/idea.png create mode 100644 app/src/assets/theme/light.png create mode 100644 app/src/assets/theme/orange.png create mode 100644 app/src/assets/theme/pink.png create mode 100644 app/src/assets/theme/purple.png create mode 100644 app/src/assets/theme/side-dark.png create mode 100644 app/src/assets/theme/vscode.png create mode 100644 app/src/components/avatar/AvatarList.vue create mode 100644 app/src/components/chart/BarChart.vue create mode 100644 app/src/components/chart/LineChart.vue create mode 100644 app/src/components/editable-cell/EditableCell.vue create mode 100644 app/src/components/editable-cell/index.ts create mode 100644 app/src/components/format/Splitter.vue create mode 100644 app/src/components/fullscreen/Fullscreen.vue create mode 100644 app/src/components/guider/Guider.vue create mode 100644 app/src/components/guider/index.ts create mode 100644 app/src/components/guider/interface.d.ts create mode 100644 app/src/components/layout/BlankView.vue create mode 100644 app/src/components/layout/CommonView.vue create mode 100644 app/src/components/layout/FrontView copy.vue create mode 100644 app/src/components/layout/FrontView.vue create mode 100644 app/src/components/layout/HeaderActions.vue create mode 100644 app/src/components/layout/LinkView.vue create mode 100644 app/src/components/layout/PageFooter.vue create mode 100644 app/src/components/layout/index.ts create mode 100644 app/src/components/list/GridList.vue create mode 100644 app/src/components/loaders/JumpSquare.vue create mode 100644 app/src/components/loaders/MatrixLoader.vue create mode 100644 app/src/components/loaders/ReadingLoader.vue create mode 100644 app/src/components/notice/Notice.vue create mode 100644 app/src/components/selector/IconSelector.vue create mode 100644 app/src/components/setting/Setting.vue create mode 100644 app/src/components/setting/index.ts create mode 100644 app/src/components/statistic/MiniStatisticCard.vue create mode 100644 app/src/components/statistic/OverviewTitle.vue create mode 100644 app/src/components/switch/DayNightSwitch.vue create mode 100644 app/src/global.d.ts create mode 100644 app/src/main.ts create mode 100644 app/src/pages/Demo.vue create mode 100644 app/src/pages/Exp403.vue create mode 100644 app/src/pages/Exp404.vue create mode 100644 app/src/pages/Test.vue create mode 100644 app/src/pages/cok/CookieTable.vue create mode 100644 app/src/pages/cok/Table.vue create mode 100644 app/src/pages/cok/index.ts create mode 100644 app/src/pages/index.ts create mode 100644 app/src/pages/init/Init.vue create mode 100644 app/src/pages/init/index.ts create mode 100644 app/src/pages/login/Login.vue create mode 100644 app/src/pages/login/LoginBox.vue create mode 100644 app/src/pages/login/LoginModal.vue create mode 100644 app/src/pages/login/index.ts create mode 100644 app/src/pages/mylogs/MyLogs.vue create mode 100644 app/src/pages/mylogs/index.ts create mode 100644 app/src/pages/personal/EmailSet.vue create mode 100644 app/src/pages/personal/MyPersonal.vue create mode 100644 app/src/pages/personal/index.ts create mode 100644 app/src/pages/set/AppSet.vue create mode 100644 app/src/pages/set/index.ts create mode 100644 app/src/pages/theme/Theme.vue create mode 100644 app/src/pages/theme/index.ts create mode 100644 app/src/pages/workplace/RecordTable.vue create mode 100644 app/src/pages/workplace/Records.vue create mode 100644 app/src/pages/workplace/Workplace.vue create mode 100644 app/src/pages/workplace/index.ts create mode 100644 app/src/pages/workplace/statics.vue create mode 100644 app/src/plugins/auth/auth-plugin.ts create mode 100644 app/src/plugins/auth/auth.css create mode 100644 app/src/plugins/iconfont/IconFont.vue create mode 100644 app/src/plugins/iconfont/index.ts create mode 100644 app/src/plugins/index.ts create mode 100644 app/src/router/dynamicRoutes.ts create mode 100644 app/src/router/guards.ts create mode 100644 app/src/router/index.ts create mode 100644 app/src/router/interface.d.ts create mode 100644 app/src/router/routes.ts create mode 100644 app/src/store/account.ts create mode 100644 app/src/store/coreapi.ts create mode 100644 app/src/store/http.ts create mode 100644 app/src/store/index.ts create mode 100644 app/src/store/menu.ts create mode 100644 app/src/store/setting.ts create mode 100644 app/src/theme/antd/card.less create mode 100644 app/src/theme/antd/description.less create mode 100644 app/src/theme/antd/index.less create mode 100644 app/src/theme/antd/table.less create mode 100644 app/src/theme/index.less create mode 100644 app/src/theme/index.ts create mode 100644 app/src/theme/style/component.less create mode 100644 app/src/theme/style/index.less create mode 100644 app/src/theme/style/layout.less create mode 100644 app/src/theme/style/nprogress.less create mode 100644 app/src/types/index.ts create mode 100644 app/src/types/theme.d.ts create mode 100644 app/src/utils/axiosHttp.ts create mode 100644 app/src/utils/file.ts create mode 100644 app/src/utils/formatter.ts create mode 100644 app/src/utils/helpers.ts create mode 100644 app/src/utils/htmlHelper.ts create mode 100644 app/src/utils/regexHelper.ts create mode 100644 app/src/utils/useModelValue.ts create mode 100644 app/src/utils/useTheme.ts create mode 100644 app/src/vite-env.d.ts create mode 100644 app/tailwind.config.cjs create mode 100644 app/tsconfig.json create mode 100644 app/tsconfig.node.json create mode 100644 app/vite.config.ts create mode 100644 app/yarn create mode 100644 appsettings.json delete mode 100644 configa.png delete mode 100644 cookaaaa.png delete mode 100644 cookie.png create mode 100644 db/dy.sqlite create mode 100644 dto/CollectVideoInfo.cs create mode 100644 dto/CollectVideoRequestDto.cs create mode 100644 dto/InitSystemInfo.cs create mode 100644 dto/UserDto.cs create mode 100644 dto/VideoNFOInfo.cs create mode 100644 dto/VideoNfo.cs create mode 100644 dto/VideoPageRequestDTO.cs create mode 100644 dto/VideoStaticsDto.cs create mode 100644 dy.net.csproj create mode 100644 dy.net.csproj.user create mode 100644 dy.net.sln create mode 100644 extension/ServiceExtension.cs create mode 100644 extension/ServiceLifetimeAttribute.cs delete mode 100644 getcookies.png delete mode 100644 homepage.png delete mode 100644 image.png delete mode 100644 image111.png delete mode 100644 image222.png delete mode 100644 image33.png delete mode 100644 image4.png delete mode 100644 image55.png create mode 100644 job/DouYinCollectSyncJob.cs create mode 100644 job/DouYinFavoritSyncJob.cs delete mode 100644 logs.png create mode 100644 model/AppConfig.cs create mode 100644 model/DyCollectVideo.cs create mode 100644 model/DyUserCookies.cs create mode 100644 model/LoginUserInfo.cs delete mode 100644 records.png create mode 100644 repository/BaseRepository.cs create mode 100644 repository/DyCollectVideoRepository.cs create mode 100644 repository/DyCookieRepository.cs create mode 100644 repository/UserRepository.cs create mode 100644 service/CommonService.cs create mode 100644 service/DyCollectVideoService.cs create mode 100644 service/DyCookieService.cs create mode 100644 service/DyHttpClientService.cs create mode 100644 service/QuartzJobService.cs create mode 100644 service/UserService.cs create mode 100644 utils/BogusManager.cs create mode 100644 utils/ByteToGbConverter.cs create mode 100644 utils/CookieValidator.cs create mode 100644 utils/DateTimeUtil.cs create mode 100644 utils/Md5Util.cs create mode 100644 utils/NfoFileGenerator.cs create mode 100644 utils/NfoGenerator.cs diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..9d58272 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "8.0.2", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..fe1152b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d1dca08 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +obj +bin +.vs +logs +upload +data1 diff --git a/Appsettings.cs b/Appsettings.cs new file mode 100644 index 0000000..c61c438 --- /dev/null +++ b/Appsettings.cs @@ -0,0 +1,77 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Json; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace dy.net +{ + /// + /// appsettings.json操作类 + /// + public class Appsettings + { + public static IConfiguration Configuration { get; private set; } + + public Appsettings(string contentPath) + { + //如果你把配置文件 是 根据环境变量来分开了,可以这样写 + string Path = $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json"; + + Configuration = new ConfigurationBuilder() + .SetBasePath(contentPath) + .Add(new JsonConfigurationSource { Path = Path, Optional = false, ReloadOnChange = true })//这样的话,可以直接读目录里的json文件,而不是 bin 文件夹下的,所以不用修改复制属性 + .Build(); + } + + public Appsettings(IConfiguration configuration) + { + Configuration = configuration; + } + + /// + /// 封装要操作的字符 + /// + /// 节点配置 + /// + public static string Get(params string[] sections) + { + try + { + + if (sections.Any()) + { + return Configuration[string.Join(":", sections)]; + } + } + catch (Exception) { throw; } + + return ""; + } + + /// + /// 递归获取配置信息数组 + /// + /// + /// + /// + public static List Get(params string[] sections) + { + List list = new List(); + // 引用 Microsoft.Extensions.Configuration.Binder 包 + Configuration.Bind(string.Join(":", sections), list); + return list; + } + + + public static T Get(string key) where T : new() + { + return Configuration.GetSection(key).Get(); + + } + public static string Get(string Key) + { + return Configuration[Key]; + } + } +} diff --git a/Controllers/AuthController.cs b/Controllers/AuthController.cs new file mode 100644 index 0000000..c79a22c --- /dev/null +++ b/Controllers/AuthController.cs @@ -0,0 +1,164 @@ +using ClockSnowFlake; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using dy.net.service; +using dy.net.utils; +using dy.net.dto; + +namespace dy.net.Controllers +{ + [Route("api/[controller]/[action]")] + [ApiController] + public class AuthController : ControllerBase + { + private readonly IWebHostEnvironment webHostEnvironment; + + private readonly UserService _userService; + public AuthController(UserService userService, IWebHostEnvironment webHostEnvironment ) + { + _userService=userService; + this.webHostEnvironment = webHostEnvironment; + } + + + /// + /// 修改密码 + /// + /// + /// + [Authorize] + [HttpPost] + public async Task UpdatePwd(UpdatePwdRequest user) + { + var (code, erro) = await _userService.UpdatePwd(user); + return Ok(new { code, erro }); + } + + + + [Authorize] + [HttpGet] + public async Task GetUserAvatar() + { + var user = await _userService.GetUser(); + return Ok(new { code = 0, error = "", data = new { user?.Avatar, user?.Id,user?.UserName } }); + } + + /// + /// 修改用户头像 + /// + /// + /// + [Authorize] + [HttpPost] + public async Task UpdateUserAvatar(IFormFile file) + { + if (file != null && file.Length > 0) + { + long maxFileSize = 5 * 1024 * 1024; // 限制文件大小为5MB + if (file.Length > maxFileSize) + { + return Ok(new { code = -1, erro = "文件最大只能上传5M" }); + } + var fileName = $"{IdGener.GetGuid()}_{file.FileName}"; + var filePath = webHostEnvironment.IsProduction() ? + Path.Combine(Md5Util.UPLOAD_PATH_PRO, fileName) : Path.Combine(Md5Util.UPLOAD_PATH_DEV, fileName); + using (var stream = new FileStream(filePath, FileMode.Create)) + { + await file.CopyToAsync(stream); + + try + { + // 问了节约空间,删除文件夹下的所有文件 + string[] files = Directory.GetFiles(webHostEnvironment.IsProduction() ? Md5Util.UPLOAD_PATH_PRO : Md5Util.UPLOAD_PATH_DEV); + foreach (string mfile in files) + { + if (!mfile.Contains(fileName)) + System.IO.File.Delete(mfile); + } + } + catch (Exception ex) + { + Serilog.Log.Error($"delete file error ,{ex.Message}"); + } + var update = await _userService.UpdateAvatar( fileName); + + return Ok(new { code = update ? 0 : -1, erro = update ? "" : "上传失败", data = update ? fileName : "" }); + } + } + else + { + return Ok(new { code = -1, erro = "空文件" }); + } + } + + + + /// + /// 登录获取token + /// + /// + /// + [HttpPost] + public async Task Login(LoginRequest loginUserInfo) + { + if (loginUserInfo == null) + { + return Ok(new { code = -1, erro = "参数不能为空" }); + } + else + { + var user = await _userService.GetUser(); + + if (user == null) + { + return Ok(new { code = -1, erro = "用户名或密码不正确" }); + } + else + { + if (user.Password == Md5Util.Md5(loginUserInfo.Password)) + { + + var tokenString = GenerateJwtToken(user.UserName); + + return Ok(new { code = 0, erro = "", token = tokenString, expires = 24 * 60 * 60 * 1000 }); + } + else + { + return Ok(new { code = -1, erro = "用户名或密码不正确" }); + } + } + } + } + + + private string GenerateJwtToken(string username) + { + var claims = new[] + { + new Claim(ClaimTypes.Name, username), + new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) + }; + var k = Md5Util.JWT_TOKEN_KEY; + var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(k)); + var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + + var expires = DateTime.Now.AddDays(1); + + var token = new JwtSecurityToken( + issuer: IdGener.GetLong().ToString(), + audience: IdGener.GetLong().ToString(), + claims: claims, + expires: expires, + signingCredentials: credentials + ); + + var jwtToken = new JwtSecurityTokenHandler().WriteToken(token); + return jwtToken; + } + } +} diff --git a/Controllers/ConfigController.cs b/Controllers/ConfigController.cs new file mode 100644 index 0000000..6644386 --- /dev/null +++ b/Controllers/ConfigController.cs @@ -0,0 +1,147 @@ +using ClockSnowFlake; +using dy.net.dto; +using dy.net.model; +using dy.net.service; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using static Dm.net.buffer.ByteArrayBuffer; + +namespace dy.net.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class ConfigController : ControllerBase + { + private readonly DyCookieService dyCookieService; + + private readonly CommonService commonService; + private readonly QuartzJobService quartzJobService; + + public ConfigController(DyCookieService dyCookieService, CommonService commonService,QuartzJobService quartzJobService) + { + this.dyCookieService = dyCookieService; + this.commonService = commonService; + this.quartzJobService = quartzJobService; + } + + + + + /// + /// 分页查询 + /// + /// 分页结果(视频列表和总数) + [HttpPost("paged")] + public async Task GetPagedAsync( + PageRequestDto dto) + { + var (list, totalCount) = await dyCookieService.GetPagedAsync(dto.PageIndex, dto.PageSize); + return Ok(new + { + code = 0, + data = new + { + data = list, + total=totalCount, + pageIndex= dto.PageIndex, + pageSize= dto.PageSize + } + } + ); + } + /// + /// 新增用户Cookie + /// + [HttpPost("add")] + public async Task AddAsync([FromBody] DyUserCookies dyUserCookies) + { + var result = await dyCookieService.Add(dyUserCookies); + if (result) + { + await ReStartJob(); + return Ok(new { code = 0 }); + } + return BadRequest(new { code=-1, message = "添加失败" }); + } + + /// + /// 更新用户Cookie + /// + [HttpPost("update")] + public async Task UpdateAsync([FromBody] DyUserCookies dyUserCookies) + { + if (dyUserCookies.Id == "0") + { + dyUserCookies.Id=IdGener.GetLong().ToString(); + var result = await dyCookieService.Add(dyUserCookies); + if (result) + { + await ReStartJob(); + return Ok(new { code = 0 }); + } + return BadRequest(new { code = -1, message = "添加失败" }); + } + else { + var result = await dyCookieService.UpdateAsync(dyUserCookies); + if (result) + { + await ReStartJob(); + return Ok(new { code = 0 }); + } + return BadRequest(new { code = -1, message = "更新失败" }); + } + + } + + /// + /// 批量删除用户Cookie + /// + [HttpGet("delete")] + public async Task DeleteAsync(string id) + { + var count = await dyCookieService.DeleteByIdsAsync(new List { id}); + if (count > 0) { + await ReStartJob(); + } + return Ok(new { code = 0, deletedCount = count }); + } + + [HttpGet("GetConfig")] + public IActionResult GetConfig() + { + var data = commonService.GetConfig(); + return Ok(new { code = 0, data = data }); + } + + [HttpPost("UpdateConfig")] + public async Task UpdateConfig(AppConfig config) + { + var data = await commonService.UpdateConfig(config); + if (data) { + await ReStartJob(); + } + return Ok(new { code = 0, data = data }); + } + + /// + /// + /// + /// + [HttpGet("ExecuteJobNow")] + [Authorize] + public async Task ExecuteJobNow() + { + var config = commonService.GetConfig(); + await quartzJobService.StartJob(config.Cron); + return Ok(new { code = 0 , error = "" }); + } + + + private async Task ReStartJob() { + var config= commonService.GetConfig(); + if(config!=null) + await quartzJobService.StartJob(config.Cron); + } + } +} diff --git a/Controllers/LogsController.cs b/Controllers/LogsController.cs new file mode 100644 index 0000000..3bd2145 --- /dev/null +++ b/Controllers/LogsController.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Net.Http; + +namespace dy.net.Controllers +{ + [Route("api/[controller]/[action]")] + [ApiController] + public class LogsController : ControllerBase + { + private readonly IWebHostEnvironment webHostEnvironment; + + public LogsController(IWebHostEnvironment webHostEnvironment) + { + this.webHostEnvironment = webHostEnvironment; + } + + [HttpGet] + public async Task GetLog(string type, string date) + { + var filePath = Path.Combine(webHostEnvironment.IsDevelopment() ? Directory.GetCurrentDirectory() : AppDomain.CurrentDomain.BaseDirectory, "logs", $"log-{type}-{date}.txt"); + if (!System.IO.File.Exists(filePath)) + { + var msg = $"Log file log-{type}-{date}.txt not found."; + //Serilog.Log.Error(msg); + return Ok(msg); + } + return PhysicalFile(filePath, "text/plain; charset=utf-8"); + + //下面的方案提示文件被占用 + //var encoding = Encoding.GetEncoding("UTF-8"); // 指定文本文件的编码 + //var fileBytes = await System.IO.File.ReadAllBytesAsync(filePath); + //var fileContent = encoding.GetString(fileBytes); + //return Content (fileContent, "text/plain", encoding); + } + + + } +} diff --git a/Controllers/VideoController.cs b/Controllers/VideoController.cs new file mode 100644 index 0000000..8f6548e --- /dev/null +++ b/Controllers/VideoController.cs @@ -0,0 +1,56 @@ +using dy.net.dto; +using dy.net.service; +using Microsoft.AspNetCore.Mvc; +using System.Drawing.Printing; + +namespace dy.net.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class VideoController : ControllerBase + { + private readonly DyCollectVideoService dyCollectVideoService; + + public VideoController(DyCollectVideoService dyCollectVideoService) + { + this.dyCollectVideoService = dyCollectVideoService; + } + /// + /// 分页查询收藏视频 + /// + /// + [HttpPost("paged")] + public async Task GetPagedAsync(VideoPageRequestDTO dto) + { + var (list, totalCount) = await dyCollectVideoService.GetPagedAsync(dto.PageIndex, dto.PageSize, dto.Tag, dto.Author,dto.ViedoType,dto.Dates); + return Ok(new + { + code = 0, + data = new + { + data = list, + total=totalCount, + pageIndex=dto.PageIndex, + pageSize=dto.PageSize + } + }); + } + + /// + /// 查询统计数据 + /// + /// + [HttpGet("statics")] + public async Task GetStaticsAsync() + { + var data = await dyCollectVideoService.GetStatics(); + return Ok(new + { + code = 0, + data + }); + } + + + } +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6fa7ada --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 10101 + +COPY . . +ENV ASPNETCORE_URLS http://*:10101 +ENTRYPOINT ["dotnet", "dy.net.dll"] +ENV TZ=Asia/Shanghai \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..731ddd3 --- /dev/null +++ b/Program.cs @@ -0,0 +1,326 @@ +using ClockSnowFlake; +using dy.net.dto; +using dy.net.extension; +using dy.net.model; +using dy.net.service; +using dy.net.utils; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.Extensions.FileProviders; +using Microsoft.IdentityModel.Tokens; +using Serilog; +using SqlSugar; +using System.Reflection; +using System.Text; + +namespace dy.net +{ + public class Program + { + // + private const string DefaultListenUrl = "http://*:10101"; + private const string SpaRootPath = "app/dist"; + private const string SpaSourcePath = "app/"; + private const string SwaggerDocTitle = "dy.net WebApi Docs"; + + public static void Main(string[] args) + { + // ʼṩ + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + + // WebӦ + var builder = WebApplication.CreateBuilder(args); + var isDevelopment = builder.Environment.IsDevelopment(); + + // + ConfigureHost(builder, isDevelopment); + + // ÷ + var services = builder.Services; + ConfigureServices(services, builder.Configuration, isDevelopment); + + // Ӧ + var app = builder.Build(); + + // м + ConfigureMiddleware(app, isDevelopment); + + // ʼӦ÷ + InitApplicationServices(app); + + // Ӧ + Serilog.Log.Debug("dy.net service started successfully"); + app.Run(); + } + + /// + /// + /// + private static void ConfigureHost(WebApplicationBuilder builder, bool isDevelopment) + { + // üַ + builder.WebHost.UseUrls(DefaultListenUrl); + + // ļ + builder.Host.ConfigureAppConfiguration((context, config) => + { + config.SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddEnvironmentVariables(); + }); + + // ־ + builder.Host.ConfigureLogging(logging => logging.ClearProviders()) + .UseSerilog(); + + builder.ConfigureLogging(); + } + + /// + /// ע + /// + private static void ConfigureServices(IServiceCollection services, IConfiguration config, bool isDevelopment) + { + // ѩID + services.AddSnowFlakeId(options => options.WorkId = new Random().Next(1, 127)); + + // MVC + services.AddControllers(); + + // HTTPͻ + services.AddHttpClients(); + + // ݿ + services.AddSqlsugar(config); + + // ʱ + services.AddQuartzService(config); + + // ִͷע + services.AddServicesFromNamespace("dy.net.repository") + .AddServicesFromNamespace("dy.net.service"); + + // SPA̬ļ֧ + services.AddSpaStaticFiles(options => options.RootPath = SpaRootPath); + + // Swagger + if (isDevelopment) + { + services.AddSwagger(); + } + + // Ӧѹ + services.AddResponseCompression(); + + // JWT֤ + ConfigureJwtAuthentication(services); + } + + /// + /// JWT֤ + /// + private static void ConfigureJwtAuthentication(IServiceCollection services) + { + var key = Encoding.ASCII.GetBytes(Md5Util.JWT_TOKEN_KEY); + + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(options => + { + options.Events = new JwtBearerEvents + { + OnMessageReceived = context => + { + context.Token = context.Request.Headers["Authorization"] + .FirstOrDefault()?.Split(" ").Last(); + return Task.CompletedTask; + } + }; + options.RequireHttpsMetadata = false; + options.SaveToken = true; + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(key), + ValidateIssuer = false, + ValidateAudience = false, + ValidateLifetime = true, + ClockSkew = TimeSpan.FromSeconds(60) + }; + }); + } + + /// + /// м + /// + private static void ConfigureMiddleware(WebApplication app, bool isDevelopment) + { + // Ӧѹ + app.UseResponseCompression(); + + // SwaggerUI + if (isDevelopment) + { + app.UseCustomSwaggerUI(options => options.Title = SwaggerDocTitle); + } + + // · + app.UseRouting(); + + // ֤Ȩ + app.UseAuthentication(); + app.UseAuthorization(); + + // ļϴ· + //ConfigureUploadPath(app, isDevelopment); + + // API·ӳ + app.MapControllers(); + + // SPA + if (!isDevelopment) + { + app.UseSpaStaticFiles(); + app.UseSpa(spa => spa.Options.SourcePath = SpaSourcePath); + } + } + + /// + /// ϴ· + /// + private static void ConfigureUploadPath(WebApplication app, bool isDevelopment) + { + var uploadPath = isDevelopment + ? Md5Util.UPLOAD_PATH_DEV + : Md5Util.UPLOAD_PATH_PRO; + + if (!Directory.Exists(uploadPath)) + { + Directory.CreateDirectory(uploadPath); + } + + // ļϴʿȡע + // app.UseStaticFiles(new StaticFileOptions + // { + // FileProvider = new PhysicalFileProvider(uploadPath), + // RequestPath = "/upload" + // }); + } + + /// + /// ʼӦ÷ + /// + private static void InitApplicationServices(WebApplication app) + { + using var scope = app.Services.CreateScope(); + var services = scope.ServiceProvider; + + try + { + // ʼû + var userService = services.GetRequiredService(); + userService.InitUser(new LoginUserInfo + { + UserName = "douyin", + Password = "douyin2025", + CreateTime = DateTime.Now + }); + + // ʼCookie + var cookieService = services.GetRequiredService(); + cookieService.Init(new DyUserCookies + { + UserName = "douyin", + Cookies = "--", + Id = "2026", + SavePath = "/app/collect", + Status = 0, + SecUserId = "--", + FavSavePath = "/app/favorite" + }); + + // ʼ + var commonService = services.GetRequiredService(); + var config = commonService.InitConfig(new AppConfig + { + Id = IdGener.GetLong().ToString(), + Cron = "30", + BatchCount = 10 + }); + + // ղƵ--ϰ汾-ԭľûֶ + commonService.UpdateCollectViedoType(); + + // ʱ + var quartzJobService = services.GetRequiredService(); + quartzJobService.StartJob(config?.Cron ?? "30"); + } + catch (Exception ex) + { + var logger = services.GetRequiredService>(); + logger.LogError(ex, "Failed to initialize services on startup"); + } + } + + /// + /// SQLiteݿַ + /// + private static string CreateSqliteDBConn() + { + var dbFolder = Path.Combine(Environment.CurrentDirectory, "db"); + Directory.CreateDirectory(dbFolder); // 򴴽ж + + var dbPath = Path.Combine(dbFolder, "dy.sqlite"); + if (!File.Exists(dbPath)) + { + using (File.Create(dbPath)) { } // ʹusingȷļر + } + + return $"DataSource={dbPath}"; + } + + /// + /// ʼݿ + /// + private static ISqlSugarClient InitDataBase(DbType dbType, string connString) + { + // SQLiteַ + if (dbType == DbType.Sqlite) + { + connString = CreateSqliteDBConn(); + } + + if (string.IsNullOrEmpty(connString)) + { + return null; + } + + return new SqlSugarClient(new ConnectionConfig + { + ConnectionString = connString, + InitKeyType = InitKeyType.Attribute, + DbType = dbType, + IsAutoCloseConnection = true + }, db => + { + // ־ + db.Aop.OnLogExecuting = (sql, pars) => Serilog.Log.Debug(sql); + db.Aop.OnError = e => + { + Serilog.Log.Error(e.Message); + Serilog.Log.Error(e.Sql); + }; + + // ݿͱ + db.DbMaintenance.CreateDatabase(); + var modelTypes = Assembly.GetExecutingAssembly() + .GetTypes() + .Where(t => t.Namespace?.StartsWith("dy.net.model") ?? false) + .ToArray(); + db.CodeFirst.InitTables(modelTypes); + }); + } + } +} \ No newline at end of file diff --git a/Properties/PublishProfiles/FolderProfile.pubxml b/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..3ed83c2 --- /dev/null +++ b/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,21 @@ + + + + + true + false + true + Release + Any CPU + FileSystem + bin\Release\net6.0\publish\ + FileSystem + <_TargetId>Folder + + net6.0 + 680660ef-acae-43a9-ab6c-b75532e758ad + false + + \ No newline at end of file diff --git a/Properties/PublishProfiles/FolderProfile.pubxml.user b/Properties/PublishProfiles/FolderProfile.pubxml.user new file mode 100644 index 0000000..e997050 --- /dev/null +++ b/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -0,0 +1,11 @@ + + + + + <_PublishTargetUrl>F:\work\code\me\dy-sync\bin\Release\net6.0\publish\ + True|2025-09-30T05:29:42.2354235Z||;True|2025-09-25T11:44:52.6858389+08:00||;True|2025-09-25T11:08:27.8810109+08:00||;True|2025-09-25T09:28:50.2563374+08:00||;True|2025-09-24T16:14:02.3072184+08:00||;True|2025-09-23T22:38:52.4414757+08:00||;True|2025-09-23T22:19:07.1006356+08:00||;True|2025-09-23T22:18:01.5945225+08:00||;True|2025-09-23T22:06:15.6293613+08:00||;True|2025-09-23T21:53:14.2977444+08:00||;True|2025-09-23T21:46:55.2322411+08:00||;False|2025-09-23T21:45:23.7858854+08:00||;False|2025-09-23T21:03:51.8325689+08:00||;True|2025-09-23T10:03:32.2251920+08:00||;False|2025-09-23T09:38:08.2372201+08:00||;False|2025-09-23T09:37:49.9390545+08:00||;True|2024-03-11T21:31:45.8102398+08:00||;True|2024-03-11T07:26:24.7660541+08:00||;True|2024-03-08T22:08:40.0154831+08:00||;True|2024-03-03T10:14:36.8109114+08:00||;True|2024-03-02T18:44:57.3288537+08:00||;True|2024-01-24T17:51:37.9164415+08:00||;True|2024-01-24T16:36:50.5612157+08:00||;True|2024-01-24T15:51:35.7556653+08:00||;True|2024-01-17T23:40:40.7526618+08:00||;True|2024-01-17T23:36:10.3692844+08:00||;True|2024-01-17T23:22:03.2378834+08:00||;True|2024-01-03T11:35:44.7118292+08:00||;True|2024-01-03T11:11:23.4270453+08:00||;True|2024-01-03T11:04:35.2081526+08:00||;True|2024-01-03T10:57:03.7053107+08:00||;True|2024-01-03T10:51:50.7463989+08:00||;False|2024-01-03T10:50:24.9775312+08:00||;True|2024-01-03T10:47:30.1128183+08:00||;True|2024-01-03T10:42:55.8640657+08:00||;True|2024-01-03T09:24:24.3436056+08:00||;True|2024-01-02T23:40:38.2001198+08:00||;True|2024-01-02T23:08:36.7230444+08:00||;True|2024-01-02T22:53:43.9658255+08:00||;True|2024-01-02T22:25:38.5545279+08:00||;False|2024-01-02T22:24:42.6577609+08:00||;True|2024-01-02T22:04:33.4708889+08:00||;True|2024-01-02T21:49:57.9249898+08:00||;True|2023-12-28T22:42:58.5976180+08:00||;True|2023-12-28T22:24:09.2051205+08:00||;True|2023-12-28T22:05:48.4865497+08:00||;True|2023-12-28T21:50:57.4549336+08:00||;True|2023-12-28T21:45:30.4557939+08:00||;True|2023-12-28T21:19:59.3614594+08:00||;False|2023-12-28T21:17:04.3069097+08:00||;False|2023-12-28T21:15:56.7788810+08:00||;False|2023-12-28T21:14:57.3617402+08:00||;False|2023-12-28T21:10:45.4382469+08:00||;True|2023-12-28T19:45:33.1431914+08:00||;True|2023-12-26T11:30:36.6418716+08:00||;True|2023-12-26T11:17:40.6433651+08:00||;True|2023-12-26T09:13:56.0741559+08:00||;True|2023-12-26T09:10:55.5358737+08:00||;True|2023-12-25T23:15:34.6534359+08:00||;True|2023-12-25T23:09:47.1566176+08:00||;False|2023-12-25T23:07:32.1118803+08:00||;True|2023-12-25T22:59:50.4643459+08:00||;True|2023-12-25T22:50:14.3584798+08:00||;False|2023-12-25T22:49:20.0279513+08:00||;True|2023-12-25T22:44:07.4183973+08:00||;True|2023-12-25T22:35:27.3847085+08:00||;True|2023-12-25T22:23:21.3542658+08:00||;True|2023-12-25T22:12:00.5219522+08:00||;True|2023-12-25T16:52:12.5089621+08:00||;True|2023-12-25T16:43:30.8348193+08:00||;True|2023-12-25T16:35:08.2421925+08:00||;True|2023-12-25T16:25:21.3233455+08:00||;False|2023-12-25T16:24:39.1703901+08:00||;True|2023-12-25T16:24:01.4340091+08:00||;True|2023-12-25T16:10:06.5213850+08:00||;True|2023-12-25T15:42:17.1376331+08:00||;True|2023-12-25T15:29:47.8537015+08:00||;True|2023-12-25T14:04:54.3750643+08:00||;False|2023-12-25T14:04:07.9330700+08:00||;True|2023-12-25T13:51:58.1949269+08:00||;True|2023-12-25T13:41:42.4832670+08:00||;True|2023-12-25T13:00:25.3861450+08:00||;True|2023-12-25T12:48:45.3851245+08:00||;True|2023-12-25T12:46:54.1266013+08:00||;True|2023-12-25T12:37:03.2615780+08:00||;False|2023-12-25T12:36:06.2657224+08:00||;True|2023-12-25T12:31:59.6032354+08:00||;True|2023-12-25T12:26:50.2316015+08:00||;True|2023-12-25T12:18:27.4149004+08:00||;True|2023-12-25T11:59:46.1381276+08:00||;True|2023-12-25T00:36:00.0643971+08:00||;True|2023-12-25T00:28:55.0051504+08:00||;False|2023-12-25T00:21:35.4266163+08:00||;True|2023-12-25T00:18:47.0638530+08:00||;True|2023-12-25T00:12:09.6195055+08:00||;True|2023-12-25T00:01:34.9698196+08:00||;False|2023-12-24T23:50:48.6479274+08:00||;True|2023-12-22T09:54:04.1399592+08:00||;True|2023-12-22T08:59:53.2795721+08:00||;False|2023-12-18T23:40:16.8523325+08:00||; + + + \ No newline at end of file diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json new file mode 100644 index 0000000..a492985 --- /dev/null +++ b/Properties/launchSettings.json @@ -0,0 +1,37 @@ +{ + "profiles": { + "dy.net": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5193" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "weatherforecast", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Docker": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/weatherforecast", + "publishAllPorts": true + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:35772", + "sslPort": 0 + } + } +} \ No newline at end of file diff --git a/SecUserId.png b/SecUserId.png deleted file mode 100644 index 27d86b13c2a80de7ac1a205b51ecfc0fa7b9b765..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25308 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 diff --git a/app/.babelrc b/app/.babelrc new file mode 100644 index 0000000..c13c5f6 --- /dev/null +++ b/app/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015"] +} diff --git a/app/.env b/app/.env new file mode 100644 index 0000000..adce5e5 --- /dev/null +++ b/app/.env @@ -0,0 +1,2 @@ +VITE_BASE_URL=/ +VITE_API_URL=http://localhost diff --git a/app/.env.development b/app/.env.development new file mode 100644 index 0000000..c4d5c01 --- /dev/null +++ b/app/.env.development @@ -0,0 +1,2 @@ +VITE_BASE_URL=/ +VITE_API_URL=http://localhost:10101 \ No newline at end of file diff --git a/app/.env.github b/app/.env.github new file mode 100644 index 0000000..b44d27e --- /dev/null +++ b/app/.env.github @@ -0,0 +1 @@ +VITE_BASE_URL=/ \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..a85a70d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,16 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local +.vscode +.history +.idea +*.log +*session.sql +package-lock.json +yarn.lock +stepin-template.session.sql +docs/.vitepress/cache +target +components.d.ts \ No newline at end of file diff --git a/app/.prettierrc.json b/app/.prettierrc.json new file mode 100644 index 0000000..8b1abb1 --- /dev/null +++ b/app/.prettierrc.json @@ -0,0 +1,22 @@ +{ + "arrowParens": "always", + "bracketSpacing": true, + "endOfLine": "lf", + "htmlWhitespaceSensitivity": "css", + "insertPragma": false, + "singleAttributePerLine": false, + "bracketSameLine": false, + "jsxBracketSameLine": false, + "bracketLine": false, + "jsxSingleQuote": true, + "printWidth": 120, + "proseWrap": "preserve", + "quoteProps": "as-needed", + "requirePragma": false, + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false, + "vueIndentScriptAndStyle": true +} diff --git a/app/LICENSE b/app/LICENSE new file mode 100644 index 0000000..1c9026b --- /dev/null +++ b/app/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 stepui + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/app/README-en_US.md b/app/README-en_US.md new file mode 100644 index 0000000..f01d0b6 --- /dev/null +++ b/app/README-en_US.md @@ -0,0 +1,83 @@ +

Stepin Template

+ +
+ +开箱即用的中后台前端/设计解决方案 +
+(原[ Vue Antd Admin](https://github.com/iczer/vue-antd-admin/) Vue3 版本) + +![GitHub package.json version (subfolder of monorepo)](https://img.shields.io/github/package-json/v/stepui/stepin-template) +![GitHub repo size](https://img.shields.io/github/repo-size/stepui/stepin-template) +![GitHub last commit](https://img.shields.io/github/last-commit/stepui/stepin-template) +![GitHub release (latest by date)](https://img.shields.io/github/v/release/stepui/stepin-template) +![Docs by iczer](https://img.shields.io/badge/docs%20by-iczer-green) + +![preview](./docs/images/preview.png) + +
+ +English | [简体中文](./README.md) + +- 预览地址: https://stepui.gitee.io/stepin-template +- 使用文档: http://stepui.gitee.io/stepin-template-docs/ +- 常见问题: http://stepui.gitee.io/stepin-template-docs/issue +- 国内镜像: https://gitee.com/stepui/stepin-template + +## 特性 + +- 强大的主题定制功能,实时动态切换 +- 多页签功能,助力后台管理高效开发 +- 内置权限控制,兼容 ABAC 和 RBAC 模型 +- 丰富的内置业务组件和常用页面模板 + +## 浏览器支持 +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| --- | --- | --- | --- | --- | +| last 2 versions | last 2 versions | last 2 versions | last 2 versions | last 2 versions | +## 环境要求 + +|git|node|yarn| +|---|----|----| +|`^2.15.0`|`^16.14.0`|`^1.21.1`| + +## 使用 + +### 拉取代码 + +```bash +git clone https://github.com/stepui/stepin-template.git +``` + +### 安装依赖 + +```bash +yarn install +``` + +### 启动 + +``` +yarn dev +``` + +### 预览 + +启动成功后,控制台会显示本地访问地址:http://127.0.0.1:5173,浏览器打开即可预览。 + +更新多信息请参考 [使用文档](http://stepui.gitee.io/stepin-template-docs/) + +## 参与贡献 + +我们非常欢迎你的贡献,你可以通过以下方式和我们一起共建 :star2:: + +- 在你的公司或个人项目中使用 Stepin Template。 +- 通过 [Issue](https://github.com/stepui/stepin-template/issues/new) 报告:bug:或进行咨询。 +- 提交 [Pull Request](https://github.com/stepui/stepin-template/pulls) 改进 Stepin Template 的代码。 +- 加入社群,与小伙伴们一同交流心得。QQ 群:441231578 + +## 打赏作者 +如果该项目对您有所帮助,可以请作者喝一杯咖啡。 +

+ + +

diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000..8ee0382 --- /dev/null +++ b/app/README.md @@ -0,0 +1,84 @@ +

Stepin Template

+ +
+ +开箱即用的中后台前端/设计解决方案 +
+(原[ Vue Antd Admin](https://github.com/iczer/vue-antd-admin/) Vue3 版本) + +![GitHub package.json version (subfolder of monorepo)](https://img.shields.io/github/package-json/v/stepui/stepin-template) +![GitHub repo size](https://img.shields.io/github/repo-size/stepui/stepin-template) +![GitHub last commit](https://img.shields.io/github/last-commit/stepui/stepin-template) +![GitHub release (latest by date)](https://img.shields.io/github/v/release/stepui/stepin-template) +![Docs by iczer](https://img.shields.io/badge/docs%20by-iczer-green) + +![preview](./docs/images/preview.png) + +
+ +简体中文 | [English](./README-en_US.md) + +- 预览地址: https://stepui.gitee.io/stepin-template +- 使用文档: http://stepui.gitee.io/stepin-template-docs/ +- 常见问题: http://stepui.gitee.io/stepin-template-docs/issue +- 国内镜像: https://gitee.com/stepui/stepin-template + +## 特性 + +- 强大的主题定制功能,实时动态切换 +- 多页签功能,助力后台管理高效开发 +- 内置权限控制,兼容 ABAC 和 RBAC 模型 +- 丰富的内置业务组件和常用页面模板 + +## 浏览器支持 +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| last 2 versions | last 2 versions | last 2 versions | last 2 versions | last 2 versions | +## 环境要求 + +| git | node | yarn | +| --------- | ---------- | --------- | +| `^2.15.0` | `^16.14.0` | `^1.21.1` | + +## 使用 + +### 拉取代码 + +```sh +git clone https://github.com/stepui/stepin-template.git +``` + +### 安装依赖 + +```sh +yarn install +``` + +### 启动 + +```sh +yarn dev +``` + +### 预览 + +启动成功后,控制台会显示本地访问地址:http://127.0.0.1:5173,浏览器打开即可预览。 + +更新多信息请参考 [使用文档](http://stepui.gitee.io/stepin-template-docs/) + +## 参与贡献 + +我们非常欢迎你的贡献,你可以通过以下方式和我们一起共建 :star2:: + +- 在你的公司或个人项目中使用 Stepin Template。 +- 通过 [Issue](https://github.com/stepui/stepin-template/issues/new) 报告:bug:或进行咨询。 +- 提交 [Pull Request](https://github.com/stepui/stepin-template/pulls) 改进 Stepin Template 的代码。 +- 加入社群,与小伙伴们一同交流心得。QQ 群:441231578 +- less报错 + yarn remove less && yarn add less@4.1.3 -D +## 打赏作者 +如果该项目对您有所帮助,可以请作者喝一杯咖啡。 +

+ + +

diff --git a/app/gulpfile.babel.js/index.js b/app/gulpfile.babel.js/index.js new file mode 100644 index 0000000..4a06b30 --- /dev/null +++ b/app/gulpfile.babel.js/index.js @@ -0,0 +1,86 @@ +import { series, src, dest } from 'gulp'; +import clean from 'gulp-clean'; +import replace from 'gulp-replace'; +import vueTsc from './vueTemplateTsc'; + +export { default as tsc } from './vueTemplateTsc'; + +function cleanAll() { + return src(['./target/*', '!./target/node_modules'], { allowEmpty: true }).pipe(clean({ force: true })); +} + +function copyIndex() { + return src(['./index.html']).pipe(replace('.ts', '.js')).pipe(replace(' + TS', '')).pipe(dest('./target')); +} + +function copyPublic() { + return src(['./public/**/*']).pipe(dest('./target/public')); +} + +function copyStyleAndJs() { + return src(['./src/**/*.{less,css,js}']).pipe(dest('./target/src')); +} + +function copyAssets() { + return src(['./src/assets/**/*']).pipe(dest('./target/src/assets')); +} + +function copyConfig() { + return src([ + './.env*', + './.gitignore', + '.babelrc', + './*.{json,cjs}', + './LICENSE', + '!./tsconfig.*', + '!./package*.json', + ]).pipe(dest('./target')); +} + +function copyReadme() { + return src(['./*.md']).pipe(replace('stepin-template.git', 'stepin-template-js.git')).pipe(dest('./target')); +} + +function copyPackageJson() { + return src(['./package.json']) + .pipe(replace(/,?[\r\n]+.*"(gulp[\-\w]*|vue-tsc|typescript)"[^,\r\n]*/g, '')) + .pipe(replace(/vue-tsc --noEmit && /g, '')) + .pipe(dest('./target')); +} +function cleanJsRepository() { + return src([ + '../stepin-template-js/*', + '!../stepin-template-js/node_modules', + '!../stepin-template-js/.git', + '!../stepin-template-js/.history', + '!../stepin-template-js/.vscode', + ]).pipe(clean({ force: true })); +} +export function copyToJsRepository() { + return src([ + './target/**/*', + './.env*', + './.gitignore', + '.babelrc', + '!./target/node_modules/**/*', + '!./target/node_modules', + ]).pipe(dest('../stepin-template-js')); +} + +export function copyDocs() { + return src(['./docs/**/*', '!./docs/.vitepress/**/*', '!./docs/.vitepress']).pipe(dest('../stepin-template-js/docs')); +} + +export const makeJs = series(cleanJsRepository, copyToJsRepository, copyDocs); + +export default series( + cleanAll, + vueTsc, + copyIndex, + copyPublic, + copyStyleAndJs, + copyConfig, + copyReadme, + copyAssets, + copyPackageJson +); diff --git a/app/gulpfile.babel.js/transform.js b/app/gulpfile.babel.js/transform.js new file mode 100644 index 0000000..4165e3f --- /dev/null +++ b/app/gulpfile.babel.js/transform.js @@ -0,0 +1,19 @@ +import { Transform } from 'stream'; + +export class BufferTransform extends Transform { + constructor(transform) { + super({ + objectMode: true, + transform(file, enc, callback) { + if (file.isBuffer()) { + file.contents = Buffer.from(transform(new String(file.contents))); + } + if (file.isStream()) { + console.log('stream file', file.path); + } + return callback(null, file); + }, + }); + return this; + } +} diff --git a/app/gulpfile.babel.js/vueTemplateTsc.js b/app/gulpfile.babel.js/vueTemplateTsc.js new file mode 100644 index 0000000..040d354 --- /dev/null +++ b/app/gulpfile.babel.js/vueTemplateTsc.js @@ -0,0 +1,152 @@ +import { src, dest, series } from 'gulp'; +import rename from 'gulp-rename'; +import replace from 'gulp-replace'; +import { BufferTransform } from './transform'; + +import ts from 'typescript'; +import prettier from 'prettier'; +import tsConfig from '../tsconfig.json'; + +tsConfig.compilerOptions.sourceMap = false; +tsConfig.compilerOptions.importsNotUsedAsValues = 'preserve'; + +/** + * vue 文件代码格式化 + * @param {*} code + * @returns + */ +const vueFormatter = () => + new BufferTransform((code) => + prettier.format(code, { + trailingComma: 'es5', + parser: 'vue', + vueIndentScriptAndStyle: true, + singleQuote: true, + }) + ); +/** + * ts 文件代码格式化 + * @param {*} code + * @returns + */ +const tsFormatter = () => + new BufferTransform((code) => + prettier.format(code, { + trailingComma: 'es5', + parser: 'typescript', + singleQuote: true, + }) + ); + +/** ts编译器 */ +const tsToJs = (tsStrCode) => { + const code = tsStrCode + .replace(/defineEmits<[\s\S]*>\(\);/g, (match) => + match.replace(/'?([\w:]*)'?:\s*\[.*\];/g, "'$1',").replace(/\(e:\s*(\'[^',]*\')[^;]*;/g, '$1,') + ) + .replace(/<{([^\{\}<>]*)}>\(\)/g, '([$1])'); + const result = ts.transpileModule(code, tsConfig); + const jsStrCode = result.outputText; + return jsStrCode; +}; + +/** + * SFC 文件 ts 代码编译 + * @param {*} tmpContent + * @returns + */ +const handleTmpContent = (tmpContent) => { + if (!tmpContent) { + return tmpContent; + } + return tmpContent + .replace(/(?<=((@|:|v-)[\w\-]*="))([^"]*)(?=")/g, function (match) { + if (/\s*{[\s\S]*}\s*/.test(match)) { + return tsToJs(`const patch = ${match}`).replace(/;\s*/g, '').replace('const patch = ', ''); + } + return `${tsToJs(match).replace(/;\s*/g, '')}`; + }) + .replace(/(?<=({{))([^{}]*)(?=}})/g, function (match) { + if (/\s*{[\s\S]*}\s*/.test(match)) { + return tsToJs(`const patch = ${match}`).replace(/;\s*/g, '').replace('const patch = ', ''); + } + return `${tsToJs(match).replace(/;\s*$/, '')}`; + }); +}; + +function transformVue(options) { + return new BufferTransform((content) => + content + .replace(/(?<=(\