├── .gitee ├── ISSUE_TEMPLATE.zh-CN.md └── PULL_REQUEST_TEMPLATE.zh-CN.md ├── .gitignore ├── LICENSE ├── README.en.md ├── README.md ├── admin-ui ├── .editorconfig ├── .env ├── .env.prod ├── .env.test ├── .gitattributes ├── .gitignore ├── .npmrc ├── .vscode │ ├── extensions.json │ ├── launch.json │ └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build │ ├── config │ │ ├── index.ts │ │ └── proxy.ts │ └── plugins │ │ ├── index.ts │ │ ├── router.ts │ │ ├── unocss.ts │ │ └── unplugin.ts ├── eslint.config.js ├── index.html ├── package.json ├── packages │ ├── axios │ │ ├── package.json │ │ ├── src │ │ │ ├── constant.ts │ │ │ ├── index.ts │ │ │ ├── options.ts │ │ │ ├── shared.ts │ │ │ └── type.ts │ │ └── tsconfig.json │ ├── color-palette │ │ ├── package.json │ │ ├── src │ │ │ ├── constant │ │ │ │ ├── index.ts │ │ │ │ ├── name.ts │ │ │ │ └── palette.ts │ │ │ ├── index.ts │ │ │ ├── palette │ │ │ │ └── index.ts │ │ │ ├── shared │ │ │ │ ├── colord.ts │ │ │ │ ├── index.ts │ │ │ │ └── name.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── hooks │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── use-boolean.ts │ │ │ ├── use-context.ts │ │ │ ├── use-count-down.ts │ │ │ ├── use-loading.ts │ │ │ ├── use-request.ts │ │ │ ├── use-signal.ts │ │ │ ├── use-svg-icon-render.ts │ │ │ └── use-table.ts │ │ └── tsconfig.json │ ├── materials │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── libs │ │ │ │ ├── admin-layout │ │ │ │ │ ├── index.module.css │ │ │ │ │ ├── index.module.css.d.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── index.vue │ │ │ │ │ └── shared.ts │ │ │ │ ├── page-tab │ │ │ │ │ ├── button-tab.vue │ │ │ │ │ ├── chrome-tab-bg.vue │ │ │ │ │ ├── chrome-tab.vue │ │ │ │ │ ├── index.module.css │ │ │ │ │ ├── index.module.css.d.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── index.vue │ │ │ │ │ ├── shared.ts │ │ │ │ │ └── svg-close.vue │ │ │ │ └── simple-scrollbar │ │ │ │ │ ├── index.ts │ │ │ │ │ └── index.vue │ │ │ └── types │ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── ofetch │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── scripts │ │ ├── bin.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── commands │ │ │ │ ├── changelog.ts │ │ │ │ ├── cleanup.ts │ │ │ │ ├── git-commit.ts │ │ │ │ ├── index.ts │ │ │ │ ├── release.ts │ │ │ │ ├── router.ts │ │ │ │ └── update-pkg.ts │ │ │ ├── config │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── shared │ │ │ │ └── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── uno-preset │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ └── tsconfig.json │ └── utils │ │ ├── package.json │ │ └── src │ │ ├── color.ts │ │ ├── crypto.ts │ │ ├── index.ts │ │ ├── nanoid.ts │ │ └── storage.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── public │ └── favicon.svg ├── src │ ├── App.vue │ ├── assets │ │ ├── imgs │ │ │ └── soybean.jpg │ │ └── svg-icon │ │ │ ├── activity.svg │ │ │ ├── at-sign.svg │ │ │ ├── avatar.svg │ │ │ ├── banner.svg │ │ │ ├── cast.svg │ │ │ ├── chrome.svg │ │ │ ├── copy.svg │ │ │ ├── custom-icon.svg │ │ │ ├── empty-data.svg │ │ │ ├── expectation.svg │ │ │ ├── heart.svg │ │ │ ├── logo.svg │ │ │ ├── network-error.svg │ │ │ ├── no-icon.svg │ │ │ ├── no-permission.svg │ │ │ ├── not-found.svg │ │ │ ├── service-error.svg │ │ │ └── wind.svg │ ├── components │ │ ├── advanced │ │ │ ├── table-column-setting.vue │ │ │ └── table-header-operation.vue │ │ ├── common │ │ │ ├── app-provider.vue │ │ │ ├── dark-mode-container.vue │ │ │ ├── exception-base.vue │ │ │ ├── full-screen.vue │ │ │ ├── lang-switch.vue │ │ │ ├── menu-toggler.vue │ │ │ ├── pin-toggler.vue │ │ │ ├── reload-button.vue │ │ │ ├── system-logo.vue │ │ │ └── theme-schema-switch.vue │ │ └── custom │ │ │ ├── better-scroll.vue │ │ │ ├── button-icon.vue │ │ │ ├── count-to.vue │ │ │ ├── look-forward.vue │ │ │ ├── soybean-avatar.vue │ │ │ ├── svg-icon.vue │ │ │ └── wave-bg.vue │ ├── config │ │ ├── index.ts │ │ ├── map-sdk.ts │ │ ├── regexp.ts │ │ └── service.ts │ ├── constants │ │ ├── app.ts │ │ ├── business.ts │ │ ├── common.ts │ │ └── reg.ts │ ├── enum │ │ └── index.ts │ ├── hooks │ │ ├── business │ │ │ ├── auth.ts │ │ │ ├── captcha.ts │ │ │ ├── index.ts │ │ │ ├── use-count-down.ts │ │ │ ├── use-hook-table.ts │ │ │ ├── use-image-verify.ts │ │ │ └── use-sms-code.ts │ │ ├── common │ │ │ ├── echarts.ts │ │ │ ├── form.ts │ │ │ ├── icon.ts │ │ │ ├── index.ts │ │ │ ├── router.ts │ │ │ ├── table.ts │ │ │ ├── use-boolean.ts │ │ │ ├── use-context.ts │ │ │ ├── use-loading-empty.ts │ │ │ ├── use-loading.ts │ │ │ └── use-reload.ts │ │ └── index.ts │ ├── layouts │ │ ├── base-layout │ │ │ └── index.vue │ │ ├── blank-layout │ │ │ └── index.vue │ │ ├── context │ │ │ └── index.ts │ │ └── modules │ │ │ ├── global-breadcrumb │ │ │ └── index.vue │ │ │ ├── global-content │ │ │ └── index.vue │ │ │ ├── global-footer │ │ │ └── index.vue │ │ │ ├── global-header │ │ │ ├── components │ │ │ │ ├── theme-button.vue │ │ │ │ └── user-avatar.vue │ │ │ └── index.vue │ │ │ ├── global-logo │ │ │ └── index.vue │ │ │ ├── global-menu │ │ │ ├── base-menu.vue │ │ │ ├── first-level-menu.vue │ │ │ ├── horizontal-mix-menu.vue │ │ │ └── vertical-mix-menu.vue │ │ │ ├── global-search │ │ │ ├── components │ │ │ │ ├── search-footer.vue │ │ │ │ ├── search-modal.vue │ │ │ │ └── search-result.vue │ │ │ └── index.vue │ │ │ ├── global-sider │ │ │ └── index.vue │ │ │ ├── global-tab │ │ │ ├── context-menu.vue │ │ │ └── index.vue │ │ │ └── theme-drawer │ │ │ ├── components │ │ │ ├── layout-mode-card.vue │ │ │ └── setting-item.vue │ │ │ ├── index.vue │ │ │ └── modules │ │ │ ├── config-operation.vue │ │ │ ├── dark-mode.vue │ │ │ ├── layout-mode.vue │ │ │ ├── page-fun.vue │ │ │ └── theme-color.vue │ ├── locales │ │ ├── dayjs.ts │ │ ├── index.ts │ │ ├── langs │ │ │ ├── en-us.ts │ │ │ └── zh-cn.ts │ │ ├── locale.ts │ │ └── naive.ts │ ├── main.ts │ ├── plugins │ │ ├── assets.ts │ │ ├── dayjs.ts │ │ ├── fast-crud │ │ │ ├── common.scss │ │ │ ├── index.tsx │ │ │ └── naive.ts │ │ ├── iconify.ts │ │ ├── index.ts │ │ ├── loading.ts │ │ └── nprogress.ts │ ├── router │ │ ├── elegant │ │ │ ├── imports.ts │ │ │ ├── routes.ts │ │ │ └── transform.ts │ │ ├── guard │ │ │ ├── index.ts │ │ │ ├── progress.ts │ │ │ ├── route.ts │ │ │ └── title.ts │ │ ├── index.ts │ │ └── routes │ │ │ ├── builtin.ts │ │ │ └── index.ts │ ├── service │ │ ├── api │ │ │ ├── auth.ts │ │ │ ├── department.ts │ │ │ ├── dynamic.ts │ │ │ ├── enum.ts │ │ │ ├── index.ts │ │ │ ├── menu.ts │ │ │ ├── post.ts │ │ │ ├── route.ts │ │ │ └── user.ts │ │ └── request │ │ │ ├── index.ts │ │ │ └── shared.ts │ ├── store │ │ ├── index.ts │ │ ├── modules │ │ │ ├── app │ │ │ │ └── index.ts │ │ │ ├── auth │ │ │ │ ├── index.ts │ │ │ │ └── shared.ts │ │ │ ├── route │ │ │ │ ├── index.ts │ │ │ │ └── shared.ts │ │ │ ├── tab │ │ │ │ ├── index.ts │ │ │ │ └── shared.ts │ │ │ └── theme │ │ │ │ ├── index.ts │ │ │ │ └── shared.ts │ │ └── plugins │ │ │ └── index.ts │ ├── styles │ │ ├── css │ │ │ ├── global.css │ │ │ ├── nprogress.css │ │ │ ├── reset.css │ │ │ └── transition.css │ │ └── scss │ │ │ ├── global.scss │ │ │ └── scrollbar.scss │ ├── theme │ │ ├── settings.ts │ │ └── vars.ts │ ├── typings │ │ ├── api.d.ts │ │ ├── app.d.ts │ │ ├── common.d.ts │ │ ├── components.d.ts │ │ ├── elegant-router.d.ts │ │ ├── env.d.ts │ │ ├── global.d.ts │ │ ├── naive-ui.d.ts │ │ ├── router.d.ts │ │ ├── storage.d.ts │ │ └── union-key.d.ts │ ├── utils │ │ ├── common.ts │ │ ├── crypto.ts │ │ ├── icon.ts │ │ ├── rule.ts │ │ ├── service.ts │ │ └── storage.ts │ └── views │ │ ├── _builtin │ │ ├── 403 │ │ │ └── index.vue │ │ ├── 404 │ │ │ └── index.vue │ │ ├── 500 │ │ │ └── index.vue │ │ ├── iframe-page │ │ │ └── [url].vue │ │ └── login │ │ │ ├── index.vue │ │ │ └── modules │ │ │ ├── bind-wechat.vue │ │ │ ├── code-login.vue │ │ │ ├── pwd-login.vue │ │ │ ├── register.vue │ │ │ └── reset-pwd.vue │ │ ├── about │ │ └── index.vue │ │ ├── dynamic │ │ ├── api │ │ │ └── index.vue │ │ └── database │ │ │ └── index.vue │ │ ├── function │ │ ├── hide-child │ │ │ ├── one │ │ │ │ └── index.vue │ │ │ ├── three │ │ │ │ └── index.vue │ │ │ └── two │ │ │ │ └── index.vue │ │ ├── multi-tab │ │ │ └── index.vue │ │ ├── request │ │ │ └── index.vue │ │ ├── super-page │ │ │ └── index.vue │ │ ├── tab │ │ │ └── index.vue │ │ └── toggle-auth │ │ │ └── index.vue │ │ ├── home │ │ ├── index.vue │ │ └── modules │ │ │ ├── card-data.vue │ │ │ ├── creativity-banner.vue │ │ │ ├── header-banner.vue │ │ │ ├── line-chart.vue │ │ │ ├── pie-chart.vue │ │ │ └── project-news.vue │ │ ├── manage │ │ ├── menu │ │ │ ├── crud.tsx │ │ │ └── index.vue │ │ └── user │ │ │ ├── crud.tsx │ │ │ └── index.vue │ │ ├── multi-menu │ │ ├── first_child │ │ │ └── index.vue │ │ └── second_child_home │ │ │ └── index.vue │ │ └── user-center │ │ └── index.vue ├── tsconfig.json ├── uno.config.ts └── vite.config.ts ├── doc ├── 1.png ├── 3.png ├── 4.png ├── 555.png ├── qun.png └── zanshang.jpg └── services ├── .dockerignore ├── .idea └── .idea.SuperApi │ └── .idea │ ├── .gitignore │ ├── .name │ ├── indexLayout.xml │ └── vcs.xml ├── SuperApi.sln └── SuperApi ├── Cache └── CacheProvider.cs ├── Config └── ConfigProvider.cs ├── Configuration ├── App.json ├── Cache.json ├── Database.json ├── JWT.json ├── Limit.json ├── Logging.json ├── Upload.json └── Wechat.json ├── Dockerfile ├── Dto ├── Auth │ ├── LoginInput.cs │ ├── LoginOutput.cs │ └── UserInfoOutPut.cs ├── DyDto.cs ├── Enum │ ├── EnumEntity.cs │ ├── EnumInput.cs │ └── EnumOutput.cs ├── FileInput.cs ├── Page.cs ├── Route │ ├── RouteMenuOutput.cs │ └── RouteOutput.cs └── UniResult.cs ├── Enum ├── AccountSourceEnum.cs ├── AccountTypeEnum.cs ├── AppPageEnum.cs ├── ComputeModeEnum.cs ├── CryptogramEnum.cs ├── DataScopeEnum.cs ├── ErrorCodeEnum.cs ├── GenderEnum.cs ├── IntegralSourceEnum.cs ├── MenuTypeEnum.cs ├── NoticeTypeEnum.cs ├── OpTypeEnum.cs ├── OrderStateEnum.cs ├── OrderTypeEnum.cs ├── PlatformTypeEnum.cs ├── StatusEnum.cs ├── WalletSourceEnum.cs └── YesNoEnum.cs ├── Filter ├── ExceptionFilter.cs ├── LoggerFilter.cs └── UniResultFilter.cs ├── Job └── TestJob.cs ├── Model ├── Base.cs ├── Config.cs ├── Department.cs ├── DictData.cs ├── DictType.cs ├── Field.cs ├── Files.cs ├── Job.cs ├── Menu.cs ├── OpLog.cs ├── Post.cs ├── Role.cs ├── RoleMenu.cs ├── Table.cs ├── User.cs ├── UserDepartment.cs └── UserRole.cs ├── Program.cs ├── Properties └── launchSettings.json ├── Service ├── AuthService.cs ├── BaseService.cs ├── ConfigService.cs ├── DepartmentService.cs ├── DictDataService.cs ├── DictTypeService.cs ├── DiyNodeDataService.cs ├── DiyNodeService.cs ├── DynamicService.cs ├── EnumService.cs ├── FieldService.cs ├── FileService.cs ├── HomeService.cs ├── JobService.cs ├── MenuService.cs ├── OpLogService.cs ├── PostService.cs ├── RoleService.cs ├── TableService.cs └── UserService.cs ├── SqlSugar ├── Repository.cs ├── Seed │ ├── DepartmentSeed.cs │ ├── MenuSeed.cs │ ├── PostSeed.cs │ └── UserSeed.cs └── SqlsugarSetup.cs ├── SuperApi.csproj ├── SuperApi.http ├── Utils ├── CacheManageUtil.cs ├── CommonUtil.cs ├── ComputerUtil.cs ├── CryptogramUtil.cs ├── DateTimeUtil.cs ├── EnumUtil.cs ├── FileContentTypeUtil.cs ├── GM │ ├── GM.cs │ └── GMUtil.cs ├── JWTEncryptionUtil.cs ├── JwtManageUtil.cs ├── LoggerUtil.cs ├── LongToStringConverterUtil.cs ├── ObjectUtil.cs ├── RegularValidate.cs ├── SqlSugarUtil.cs └── TripleDES.cs ├── appsettings.Development.json ├── appsettings.json ├── nlog.config └── wwwroot ├── Upload ├── 1790278317430149121.png ├── 1790288730997788673.png ├── 1790301428166823937.png ├── 1790301476749447169.png ├── 1790563542529871873.png └── 1790586568491274241.jpg ├── assets ├── DescriptionsItem-BM8MmuEo.js ├── Space-CUMox7Fx.js ├── _commonjsHelpers-2f131a27-flC_zxlv.js ├── _url_-MePe-juJ.js ├── dynamic-gU_5PGvA.js ├── exception-base.vue_vue_type_script_setup_true_lang-Dd_RLJG2.js ├── fs-copyable-cdb97d41-BYzBau_g.js ├── fs-cropper-cb557eb1-B-8z5C98.js ├── fs-cropper-uploader-58d3df0b-BOJGbyXq.js ├── fs-file-uploader-802104d0-C4VyeiZD.js ├── fs-files-format-0f269a06-C3wkYVEw.js ├── fs-json-editor-ace10bde-Dq3GVP66.js ├── fs-time-humanize-b4edebe6-CM_DnplP.js ├── fs-uploader-0f406a2a-DKgNpGPZ.js ├── index-2YcrU8FE.js ├── index-6fc7242a-BkA8-ixq.js ├── index-8Zat4c5B.js ├── index-8dab55cb-bLhCoU--.js ├── index-99487c8e-Dq8H8oge.js ├── index-B6x3Gimk.js ├── index-BXdYPuBb.js ├── index-BZUOWCTQ.js ├── index-BnRYhHXP.js ├── index-C5CtqXlC.js ├── index-CBqg4KaE.js ├── index-CGRBzWb_.css ├── index-CSL-_yYS.js ├── index-CVQ0VXAU.js ├── index-CXvDrQgj.js ├── index-D0Yj8Qx6.js ├── index-D9iJFfHJ.js ├── index-DLfsA-ZK.js ├── index-DRlGMnxp.js ├── index-DVuM67FR.js ├── index-Dcu9BgNx.js ├── index-DnZhkf2e.js ├── index-DrmDjbUF.js ├── index-DxTPa1BL.js ├── index-eUYUfgxG.js ├── index-o00djbCc.js ├── look-forward.vue_vue_type_script_setup_true_lang-qO66lTGI.js ├── soybean-JC38yUrs.jpg ├── uploader-alioss-2ed0a0c2-BXpkt4v3.js ├── uploader-cos-7edd9efa-DjUGPAFl.js ├── uploader-form-b18e19b1-DSwjLPjC.js ├── uploader-qiniu-ae5fc328-Bplj3_GM.js └── uploader-s3-c30a8609-CNUfA2dF.js ├── favicon.svg └── index.html /.gitee/ISSUE_TEMPLATE.zh-CN.md: -------------------------------------------------------------------------------- 1 | ### 该问题是怎么引起的? 2 | 3 | 4 | 5 | ### 重现步骤 6 | 7 | 8 | 9 | ### 报错信息 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md: -------------------------------------------------------------------------------- 1 | ### 一、内容说明(相关的Issue) 2 | 3 | 4 | 5 | ### 二、建议测试周期和提测地址 6 | 建议测试完成时间:xxxx.xx.xx 7 | 投产上线时间:xxxx.xx.xx 8 | 提测地址:CI环境/压测环境 9 | 测试账号: 10 | 11 | ### 三、变更内容 12 | * 3.1 关联PR列表 13 | 14 | * 3.2 数据库和部署说明 15 | 1. 常规更新 16 | 2. 重启unicorn 17 | 3. 重启sidekiq 18 | 4. 迁移任务:是否有迁移任务,没有写 "无" 19 | 5. rake脚本:`bundle exec xxx RAILS_ENV = production`;没有写 "无" 20 | 21 | * 3.4 其他技术优化内容(做了什么,变更了什么) 22 | - 重构了 xxxx 代码 23 | - xxxx 算法优化 24 | 25 | 26 | * 3.5 废弃通知(什么字段、方法弃用?) 27 | 28 | 29 | 30 | * 3.6 后向不兼容变更(是否有无法向后兼容的变更?) 31 | 32 | 33 | 34 | ### 四、研发自测点(自测哪些?冒烟用例全部自测?) 35 | 自测测试结论: 36 | 37 | 38 | ### 五、测试关注点(需要提醒QA重点关注的、可能会忽略的地方) 39 | 检查点: 40 | 41 | | 需求名称 | 是否影响xx公共模块 | 是否需要xx功能 | 需求升级是否依赖其他子产品 | 42 | |------|------------|----------|---------------| 43 | | xxx | 否 | 需要 | 不需要 | 44 | | | | | | 45 | 46 | 接口测试: 47 | 48 | 性能测试: 49 | 50 | 并发测试: 51 | 52 | 其他: 53 | 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 倔强嘴角留下一抹殇 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /admin-ui/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /admin-ui/.env.prod: -------------------------------------------------------------------------------- 1 | VITE_BASE_URL=/ 2 | # backend service base url, prod environment 3 | VITE_SERVICE_BASE_URL=http://localhost:3000/api 4 | 5 | # other backend service base url, prod environment 6 | VITE_OTHER_SERVICE_BASE_URL= `{ 7 | "demo": "http://localhost:9529" 8 | }` 9 | -------------------------------------------------------------------------------- /admin-ui/.env.test: -------------------------------------------------------------------------------- 1 | ### 2 | # @Author: 490912587@qq.com 3 | # @Date: 2024-04-30 15:08:20 4 | # @LastEditors: 490912587@qq.com 5 | # @LastEditTime: 2024-04-30 15:38:15 6 | # @FilePath: \admin-ui\.env.test 7 | # @Description: 8 | ### 9 | # backend service base url, test environment 10 | VITE_SERVICE_BASE_URL=https://mock.apifox.com/m1/3109515-0-default 11 | # other backend service base url, test environment 12 | VITE_OTHER_SERVICE_BASE_URL= `{ 13 | "demo": "http://localhost:9528" 14 | }` 15 | -------------------------------------------------------------------------------- /admin-ui/.gitattributes: -------------------------------------------------------------------------------- 1 | "*.vue" eol=lf 2 | "*.js" eol=lf 3 | "*.ts" eol=lf 4 | "*.jsx" eol=lf 5 | "*.tsx" eol=lf 6 | "*.mjs" eol=lf 7 | "*.json" eol=lf 8 | "*.html" eol=lf 9 | "*.css" eol=lf 10 | "*.scss" eol=lf 11 | "*.md" eol=lf 12 | "*.yaml" eol=lf 13 | "*.yml" eol=lf 14 | -------------------------------------------------------------------------------- /admin-ui/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | !.vscode/settings.json 24 | !.vscode/launch.json 25 | .idea 26 | *.suo 27 | *.ntvs* 28 | *.njsproj 29 | *.sln 30 | *.sw? 31 | 32 | package-lock.json 33 | yarn.lock 34 | 35 | .VSCodeCounter 36 | -------------------------------------------------------------------------------- /admin-ui/.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmmirror.com/ 2 | shamefully-hoist=true 3 | ignore-workspace-root-check=true 4 | link-workspace-packages=true 5 | -------------------------------------------------------------------------------- /admin-ui/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "afzalsayed96.icones", 4 | "antfu.iconify", 5 | "antfu.unocss", 6 | "dbaeumer.vscode-eslint", 7 | "editorconfig.editorconfig", 8 | "esbenp.prettier-vscode", 9 | "formulahendry.auto-close-tag", 10 | "formulahendry.auto-complete-tag", 11 | "formulahendry.auto-rename-tag", 12 | "lokalise.i18n-ally", 13 | "mhutchie.git-graph", 14 | "mikestead.dotenv", 15 | "naumovs.color-highlight", 16 | "pkief.material-icon-theme", 17 | "sdras.vue-vscode-snippets", 18 | "vue.volar", 19 | "whtouche.vscode-js-console-utils", 20 | "zhuangtongfa.material-theme" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /admin-ui/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "pnpm run dev", 6 | "name": "Run", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | }, 10 | { 11 | "type": "chrome", 12 | "request": "launch", 13 | "name": "Vue Debugger", 14 | "url": "http://localhost:9527", 15 | "webRoot": "${workspaceFolder}" 16 | }, 17 | { 18 | "type": "node", 19 | "request": "launch", 20 | "name": "TS Debugger", 21 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/tsx", 22 | "skipFiles": [ 23 | "/**", 24 | "${workspaceFolder}/node_modules/**" 25 | ], 26 | "program": "${file}" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /admin-ui/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": "explicit", 4 | "source.organizeImports": "never" 5 | }, 6 | "eslint.experimental.useFlatConfig": true, 7 | "editor.formatOnSave": false, 8 | "eslint.validate": ["html", "css", "scss", "json", "jsonc"], 9 | "i18n-ally.displayLanguage": "zh-cn", 10 | "i18n-ally.enabledParsers": ["ts"], 11 | "i18n-ally.enabledFrameworks": ["vue"], 12 | "i18n-ally.editor.preferEditor": true, 13 | "i18n-ally.keystyle": "nested", 14 | "i18n-ally.localesPaths": ["src/locales/langs"], 15 | "prettier.enable": false, 16 | "unocss.root": ["./"], 17 | "typescript.tsdk": "node_modules/typescript/lib", 18 | "vue.server.hybridMode": true 19 | } 20 | -------------------------------------------------------------------------------- /admin-ui/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Soybean 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /admin-ui/build/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './proxy'; 2 | -------------------------------------------------------------------------------- /admin-ui/build/config/proxy.ts: -------------------------------------------------------------------------------- 1 | import type { ProxyOptions } from 'vite'; 2 | import { createServiceConfig } from '../../src/utils/service'; 3 | 4 | /** 5 | * Set http proxy 6 | * 7 | * @param env - The current env 8 | * @param isDev - Is development environment 9 | */ 10 | export function createViteProxy(env: Env.ImportMeta, isDev: boolean) { 11 | const isEnableHttpProxy = isDev && env.VITE_HTTP_PROXY === 'Y'; 12 | 13 | if (!isEnableHttpProxy) return undefined; 14 | 15 | const { baseURL, proxyPattern, other } = createServiceConfig(env); 16 | 17 | const proxy: Record = createProxyItem({ baseURL, proxyPattern }); 18 | 19 | other.forEach(item => { 20 | Object.assign(proxy, createProxyItem(item)); 21 | }); 22 | 23 | return proxy; 24 | } 25 | 26 | function createProxyItem(item: App.Service.ServiceConfigItem) { 27 | const proxy: Record = {}; 28 | 29 | proxy[item.proxyPattern] = { 30 | target: item.baseURL, 31 | changeOrigin: true, 32 | rewrite: path => path.replace(new RegExp(`^${item.proxyPattern}`), '') 33 | }; 34 | 35 | return proxy; 36 | } 37 | -------------------------------------------------------------------------------- /admin-ui/build/plugins/index.ts: -------------------------------------------------------------------------------- 1 | import type { PluginOption } from 'vite'; 2 | import vue from '@vitejs/plugin-vue'; 3 | import vueJsx from '@vitejs/plugin-vue-jsx'; 4 | import VueDevtools from 'vite-plugin-vue-devtools'; 5 | import progress from 'vite-plugin-progress'; 6 | import { setupElegantRouter } from './router'; 7 | import { setupUnocss } from './unocss'; 8 | import { setupUnplugin } from './unplugin'; 9 | 10 | export function setupVitePlugins(viteEnv: Env.ImportMeta) { 11 | const plugins: PluginOption = [ 12 | vue({ 13 | script: { 14 | defineModel: true 15 | } 16 | }), 17 | vueJsx(), 18 | VueDevtools(), 19 | setupElegantRouter(), 20 | setupUnocss(viteEnv), 21 | ...setupUnplugin(viteEnv), 22 | progress() 23 | ]; 24 | 25 | return plugins; 26 | } 27 | -------------------------------------------------------------------------------- /admin-ui/build/plugins/unocss.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import path from 'node:path'; 3 | import unocss from '@unocss/vite'; 4 | import presetIcons from '@unocss/preset-icons'; 5 | import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders'; 6 | 7 | export function setupUnocss(viteEnv: Env.ImportMeta) { 8 | const { VITE_ICON_PREFIX, VITE_ICON_LOCAL_PREFIX } = viteEnv; 9 | 10 | const localIconPath = path.join(process.cwd(), 'src/assets/svg-icon'); 11 | 12 | /** The name of the local icon collection */ 13 | const collectionName = VITE_ICON_LOCAL_PREFIX.replace(`${VITE_ICON_PREFIX}-`, ''); 14 | 15 | return unocss({ 16 | presets: [ 17 | presetIcons({ 18 | prefix: `${VITE_ICON_PREFIX}-`, 19 | scale: 1, 20 | extraProperties: { 21 | display: 'inline-block' 22 | }, 23 | collections: { 24 | [collectionName]: FileSystemIconLoader(localIconPath, svg => 25 | svg.replace(/^ 2 | 3 | 4 | 5 | 6 | 7 | %VITE_APP_TITLE% 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /admin-ui/packages/axios/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/axios", 3 | "version": "1.0.8", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "@sa/utils": "workspace:*", 14 | "axios": "1.6.8", 15 | "axios-retry": "4.1.0", 16 | "qs": "6.12.1" 17 | }, 18 | "devDependencies": { 19 | "@types/qs": "6.9.15" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /admin-ui/packages/axios/src/constant.ts: -------------------------------------------------------------------------------- 1 | /** request id key */ 2 | export const REQUEST_ID_KEY = 'X-Request-Id'; 3 | 4 | /** the backend error code key */ 5 | export const BACKEND_ERROR_CODE = 'BACKEND_ERROR'; 6 | -------------------------------------------------------------------------------- /admin-ui/packages/axios/src/options.ts: -------------------------------------------------------------------------------- 1 | import type { CreateAxiosDefaults } from 'axios'; 2 | import type { IAxiosRetryConfig } from 'axios-retry'; 3 | import { stringify } from 'qs'; 4 | import { isHttpSuccess } from './shared'; 5 | import type { RequestOption } from './type'; 6 | 7 | export function createDefaultOptions(options?: Partial>) { 8 | const opts: RequestOption = { 9 | onRequest: async config => config, 10 | isBackendSuccess: _response => true, 11 | onBackendFail: async () => {}, 12 | transformBackendResponse: async response => response.data, 13 | onError: async () => {} 14 | }; 15 | 16 | Object.assign(opts, options); 17 | 18 | return opts; 19 | } 20 | 21 | export function createRetryOptions(config?: Partial) { 22 | const retryConfig: IAxiosRetryConfig = { 23 | retries: 3 24 | }; 25 | 26 | Object.assign(retryConfig, config); 27 | 28 | return retryConfig; 29 | } 30 | 31 | export function createAxiosConfig(config?: Partial) { 32 | const TEN_SECONDS = 10 * 1000; 33 | 34 | const axiosConfig: CreateAxiosDefaults = { 35 | timeout: TEN_SECONDS, 36 | headers: { 37 | 'Content-Type': 'application/json' 38 | }, 39 | validateStatus: isHttpSuccess, 40 | paramsSerializer: params => { 41 | return stringify(params); 42 | } 43 | }; 44 | 45 | Object.assign(axiosConfig, config); 46 | 47 | return axiosConfig; 48 | } 49 | -------------------------------------------------------------------------------- /admin-ui/packages/axios/src/shared.ts: -------------------------------------------------------------------------------- 1 | import type { AxiosHeaderValue, AxiosResponse, InternalAxiosRequestConfig } from 'axios'; 2 | 3 | export function getContentType(config: InternalAxiosRequestConfig) { 4 | const contentType: AxiosHeaderValue = config.headers?.['Content-Type'] || 'application/json'; 5 | 6 | return contentType; 7 | } 8 | 9 | /** 10 | * check if http status is success 11 | * 12 | * @param status 13 | */ 14 | export function isHttpSuccess(status: number) { 15 | const isSuccessCode = status >= 200 && status < 300; 16 | return isSuccessCode || status === 304; 17 | } 18 | 19 | /** 20 | * is response json 21 | * 22 | * @param response axios response 23 | */ 24 | export function isResponseJson(response: AxiosResponse) { 25 | const { responseType } = response.config; 26 | 27 | return responseType === 'json' || responseType === undefined; 28 | } 29 | -------------------------------------------------------------------------------- /admin-ui/packages/axios/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /admin-ui/packages/color-palette/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/color-palette", 3 | "version": "1.0.8", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "colord": "2.9.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /admin-ui/packages/color-palette/src/constant/index.ts: -------------------------------------------------------------------------------- 1 | export * from './name'; 2 | export * from './palette'; 3 | -------------------------------------------------------------------------------- /admin-ui/packages/color-palette/src/index.ts: -------------------------------------------------------------------------------- 1 | import { colorPalettes } from './constant'; 2 | import { getColorName, getHex, getHsl, getRgb } from './shared'; 3 | 4 | export * from './palette'; 5 | export { getColorName, getHex, getHsl, getRgb, colorPalettes }; 6 | export * from './types'; 7 | -------------------------------------------------------------------------------- /admin-ui/packages/color-palette/src/shared/colord.ts: -------------------------------------------------------------------------------- 1 | import { colord, extend } from 'colord'; 2 | import type { HslColor } from 'colord'; 3 | import labPlugin from 'colord/plugins/lab'; 4 | 5 | extend([labPlugin]); 6 | 7 | export function isValidColor(color: string) { 8 | return colord(color).isValid(); 9 | } 10 | 11 | export function getHex(color: string) { 12 | return colord(color).toHex(); 13 | } 14 | 15 | export function getRgb(color: string) { 16 | return colord(color).toRgb(); 17 | } 18 | 19 | export function getHsl(color: string) { 20 | return colord(color).toHsl(); 21 | } 22 | 23 | export function getDeltaE(color1: string, color2: string) { 24 | return colord(color1).delta(color2); 25 | } 26 | 27 | export function transformHslToHex(color: HslColor) { 28 | return colord(color).toHex(); 29 | } 30 | -------------------------------------------------------------------------------- /admin-ui/packages/color-palette/src/shared/index.ts: -------------------------------------------------------------------------------- 1 | export * from './colord'; 2 | export * from './name'; 3 | -------------------------------------------------------------------------------- /admin-ui/packages/color-palette/src/shared/name.ts: -------------------------------------------------------------------------------- 1 | import { colorNames } from '../constant'; 2 | import { getHex, getHsl, getRgb } from './colord'; 3 | 4 | /** 5 | * Get color name 6 | * 7 | * @param color 8 | */ 9 | export function getColorName(color: string) { 10 | const hex = getHex(color); 11 | const rgb = getRgb(color); 12 | const hsl = getHsl(color); 13 | 14 | let ndf = 0; 15 | let ndf1 = 0; 16 | let ndf2 = 0; 17 | let cl = -1; 18 | let df = -1; 19 | 20 | let name = ''; 21 | 22 | colorNames.some((item, index) => { 23 | const [hexValue, colorName] = item; 24 | 25 | const match = hex === hexValue; 26 | 27 | if (match) { 28 | name = colorName; 29 | } else { 30 | const { r, g, b } = getRgb(hexValue); 31 | const { h, s, l } = getHsl(hexValue); 32 | 33 | ndf1 = (rgb.r - r) ** 2 + (rgb.g - g) ** 2 + (rgb.b - b) ** 2; 34 | ndf2 = (hsl.h - h) ** 2 + (hsl.s - s) ** 2 + (hsl.l - l) ** 2; 35 | 36 | ndf = ndf1 + ndf2 * 2; 37 | if (df < 0 || df > ndf) { 38 | df = ndf; 39 | cl = index; 40 | } 41 | } 42 | 43 | return match; 44 | }); 45 | 46 | name = colorNames[cl][1]; 47 | 48 | return name; 49 | } 50 | -------------------------------------------------------------------------------- /admin-ui/packages/color-palette/src/types/index.ts: -------------------------------------------------------------------------------- 1 | /** the color palette number */ 2 | export type ColorPaletteNumber = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950; 3 | 4 | /** the color palette */ 5 | export type ColorPalette = { 6 | /** the color hex value */ 7 | hex: string; 8 | /** 9 | * the color number 10 | * 11 | * - 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950 12 | */ 13 | number: ColorPaletteNumber; 14 | }; 15 | 16 | /** the color palette family */ 17 | export type ColorPaletteFamily = { 18 | /** the color palette family name */ 19 | name: string; 20 | /** the color palettes */ 21 | palettes: ColorPalette[]; 22 | }; 23 | 24 | /** the color palette with delta */ 25 | export type ColorPaletteWithDelta = ColorPalette & { 26 | delta: number; 27 | }; 28 | 29 | /** the color palette family with nearest palette */ 30 | export type ColorPaletteFamilyWithNearestPalette = ColorPaletteFamily & { 31 | nearestPalette: ColorPaletteWithDelta; 32 | nearestLightnessPalette: ColorPaletteWithDelta; 33 | }; 34 | 35 | /** the color palette match */ 36 | export type ColorPaletteMatch = ColorPaletteFamily & { 37 | /** the color map of the palette */ 38 | colorMap: Map; 39 | /** 40 | * the main color of the palette 41 | * 42 | * which number is 500 43 | */ 44 | main: ColorPalette; 45 | /** the match color of the palette */ 46 | match: ColorPalette; 47 | }; 48 | -------------------------------------------------------------------------------- /admin-ui/packages/color-palette/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /admin-ui/packages/hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/hooks", 3 | "version": "1.0.8", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "@sa/axios": "workspace:*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /admin-ui/packages/hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | import useBoolean from './use-boolean'; 2 | import useLoading from './use-loading'; 3 | import useCountDown from './use-count-down'; 4 | import useContext from './use-context'; 5 | import useSvgIconRender from './use-svg-icon-render'; 6 | import useHookTable from './use-table'; 7 | 8 | export { useBoolean, useLoading, useCountDown, useContext, useSvgIconRender, useHookTable }; 9 | 10 | export * from './use-signal'; 11 | export * from './use-table'; 12 | -------------------------------------------------------------------------------- /admin-ui/packages/hooks/src/use-boolean.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | /** 4 | * Boolean 5 | * 6 | * @param initValue Init value 7 | */ 8 | export default function useBoolean(initValue = false) { 9 | const bool = ref(initValue); 10 | 11 | function setBool(value: boolean) { 12 | bool.value = value; 13 | } 14 | function setTrue() { 15 | setBool(true); 16 | } 17 | function setFalse() { 18 | setBool(false); 19 | } 20 | function toggle() { 21 | setBool(!bool.value); 22 | } 23 | 24 | return { 25 | bool, 26 | setBool, 27 | setTrue, 28 | setFalse, 29 | toggle 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /admin-ui/packages/hooks/src/use-count-down.ts: -------------------------------------------------------------------------------- 1 | import { computed, onScopeDispose, ref } from 'vue'; 2 | import { useRafFn } from '@vueuse/core'; 3 | 4 | /** 5 | * count down 6 | * 7 | * @param seconds - count down seconds 8 | */ 9 | export default function useCountDown(seconds: number) { 10 | const FPS_PER_SECOND = 60; 11 | 12 | const fps = ref(0); 13 | 14 | const count = computed(() => Math.ceil(fps.value / FPS_PER_SECOND)); 15 | 16 | const isCounting = computed(() => fps.value > 0); 17 | 18 | const { pause, resume } = useRafFn( 19 | () => { 20 | if (fps.value > 0) { 21 | fps.value -= 1; 22 | } else { 23 | pause(); 24 | } 25 | }, 26 | { immediate: false } 27 | ); 28 | 29 | function start(updateSeconds: number = seconds) { 30 | fps.value = FPS_PER_SECOND * updateSeconds; 31 | resume(); 32 | } 33 | 34 | function stop() { 35 | fps.value = 0; 36 | pause(); 37 | } 38 | 39 | onScopeDispose(() => { 40 | pause(); 41 | }); 42 | 43 | return { 44 | count, 45 | isCounting, 46 | start, 47 | stop 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /admin-ui/packages/hooks/src/use-loading.ts: -------------------------------------------------------------------------------- 1 | import useBoolean from './use-boolean'; 2 | 3 | /** 4 | * Loading 5 | * 6 | * @param initValue Init value 7 | */ 8 | export default function useLoading(initValue = false) { 9 | const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(initValue); 10 | 11 | return { 12 | loading, 13 | startLoading, 14 | endLoading 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /admin-ui/packages/hooks/src/use-svg-icon-render.ts: -------------------------------------------------------------------------------- 1 | import { h } from 'vue'; 2 | import type { Component } from 'vue'; 3 | 4 | /** 5 | * Svg icon render hook 6 | * 7 | * @param SvgIcon Svg icon component 8 | */ 9 | export default function useSvgIconRender(SvgIcon: Component) { 10 | interface IconConfig { 11 | /** Iconify icon name */ 12 | icon?: string; 13 | /** Local icon name */ 14 | localIcon?: string; 15 | /** Icon color */ 16 | color?: string; 17 | /** Icon size */ 18 | fontSize?: number; 19 | } 20 | 21 | type IconStyle = Partial>; 22 | 23 | /** 24 | * Svg icon VNode 25 | * 26 | * @param config 27 | */ 28 | const SvgIconVNode = (config: IconConfig) => { 29 | const { color, fontSize, icon, localIcon } = config; 30 | 31 | const style: IconStyle = {}; 32 | 33 | if (color) { 34 | style.color = color; 35 | } 36 | if (fontSize) { 37 | style.fontSize = `${fontSize}px`; 38 | } 39 | 40 | if (!icon && !localIcon) { 41 | return undefined; 42 | } 43 | 44 | return () => h(SvgIcon, { icon, localIcon, style }); 45 | }; 46 | 47 | return { 48 | SvgIconVNode 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /admin-ui/packages/hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/materials", 3 | "version": "1.0.8", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "@sa/utils": "workspace:*", 14 | "simplebar-vue": "2.3.3" 15 | }, 16 | "devDependencies": { 17 | "typed-css-modules": "0.9.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/index.ts: -------------------------------------------------------------------------------- 1 | import AdminLayout, { LAYOUT_MAX_Z_INDEX, LAYOUT_SCROLL_EL_ID } from './libs/admin-layout'; 2 | import PageTab from './libs/page-tab'; 3 | import SimpleScrollbar from './libs/simple-scrollbar'; 4 | 5 | export { AdminLayout, LAYOUT_SCROLL_EL_ID, LAYOUT_MAX_Z_INDEX, PageTab, SimpleScrollbar }; 6 | export * from './types'; 7 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/admin-layout/index.module.css: -------------------------------------------------------------------------------- 1 | /* @type */ 2 | 3 | .layout-header, 4 | .layout-header-placement { 5 | height: var(--soy-header-height); 6 | } 7 | 8 | .layout-header { 9 | z-index: var(--soy-header-z-index); 10 | } 11 | 12 | .layout-tab { 13 | top: var(--soy-header-height); 14 | height: var(--soy-tab-height); 15 | z-index: var(--soy-tab-z-index); 16 | } 17 | 18 | .layout-tab-placement { 19 | height: var(--soy-tab-height); 20 | } 21 | 22 | .layout-sider { 23 | width: var(--soy-sider-width); 24 | z-index: var(--soy-sider-z-index); 25 | } 26 | 27 | .layout-mobile-sider { 28 | z-index: var(--soy-sider-z-index); 29 | } 30 | 31 | .layout-mobile-sider-mask { 32 | z-index: var(--soy-mobile-sider-z-index); 33 | } 34 | 35 | .layout-sider_collapsed { 36 | width: var(--soy-sider-collapsed-width); 37 | z-index: var(--soy-sider-z-index); 38 | } 39 | 40 | .layout-footer, 41 | .layout-footer-placement { 42 | height: var(--soy-footer-height); 43 | } 44 | 45 | .layout-footer { 46 | z-index: var(--soy-footer-z-index); 47 | } 48 | 49 | .left-gap { 50 | padding-left: var(--soy-sider-width); 51 | } 52 | 53 | .left-gap_collapsed { 54 | padding-left: var(--soy-sider-collapsed-width); 55 | } 56 | 57 | .sider-padding-top { 58 | padding-top: var(--soy-header-height); 59 | } 60 | 61 | .sider-padding-bottom { 62 | padding-bottom: var(--soy-footer-height); 63 | } 64 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/admin-layout/index.module.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly 'layout-header': string; 3 | readonly 'layout-header-placement': string; 4 | readonly 'layout-tab': string; 5 | readonly 'layout-tab-placement': string; 6 | readonly 'layout-sider': string; 7 | readonly 'layout-mobile-sider': string; 8 | readonly 'layout-mobile-sider-mask': string; 9 | readonly 'layout-sider_collapsed': string; 10 | readonly 'layout-footer': string; 11 | readonly 'layout-footer-placement': string; 12 | readonly 'left-gap': string; 13 | readonly 'left-gap_collapsed': string; 14 | readonly 'sider-padding-top': string; 15 | readonly 'sider-padding-bottom': string; 16 | }; 17 | 18 | export default styles; 19 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/admin-layout/index.ts: -------------------------------------------------------------------------------- 1 | import AdminLayout from './index.vue'; 2 | import { LAYOUT_MAX_Z_INDEX, LAYOUT_SCROLL_EL_ID } from './shared'; 3 | 4 | export default AdminLayout; 5 | export { LAYOUT_SCROLL_EL_ID, LAYOUT_MAX_Z_INDEX }; 6 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/page-tab/button-tab.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/page-tab/chrome-tab-bg.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/page-tab/index.module.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly 'button-tab': string; 3 | readonly 'button-tab_dark': string; 4 | readonly 'button-tab_active': string; 5 | readonly 'button-tab_active_dark': string; 6 | readonly 'chrome-tab': string; 7 | readonly 'chrome-tab_active': string; 8 | readonly 'chrome-tab__bg': string; 9 | readonly 'chrome-tab_active_dark': string; 10 | readonly 'chrome-tab_dark': string; 11 | readonly 'chrome-tab-divider': string; 12 | readonly 'svg-close': string; 13 | }; 14 | 15 | export default styles; 16 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/page-tab/index.ts: -------------------------------------------------------------------------------- 1 | import PageTab from './index.vue'; 2 | 3 | export default PageTab; 4 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/page-tab/shared.ts: -------------------------------------------------------------------------------- 1 | import { addColorAlpha, transformColorWithOpacity } from '@sa/utils'; 2 | import type { PageTabCssVars, PageTabCssVarsProps } from '../../types'; 3 | 4 | /** The active color of the tab */ 5 | export const ACTIVE_COLOR = '#1890ff'; 6 | 7 | function createCssVars(props: PageTabCssVarsProps) { 8 | const cssVars: PageTabCssVars = { 9 | '--soy-primary-color': props.primaryColor, 10 | '--soy-primary-color1': props.primaryColor1, 11 | '--soy-primary-color2': props.primaryColor2, 12 | '--soy-primary-color-opacity1': props.primaryColorOpacity1, 13 | '--soy-primary-color-opacity2': props.primaryColorOpacity2, 14 | '--soy-primary-color-opacity3': props.primaryColorOpacity3 15 | }; 16 | 17 | return cssVars; 18 | } 19 | 20 | export function createTabCssVars(primaryColor: string) { 21 | const cssProps: PageTabCssVarsProps = { 22 | primaryColor, 23 | primaryColor1: transformColorWithOpacity(primaryColor, 0.1, '#ffffff'), 24 | primaryColor2: transformColorWithOpacity(primaryColor, 0.3, '#000000'), 25 | primaryColorOpacity1: addColorAlpha(primaryColor, 0.1), 26 | primaryColorOpacity2: addColorAlpha(primaryColor, 0.15), 27 | primaryColorOpacity3: addColorAlpha(primaryColor, 0.3) 28 | }; 29 | 30 | return createCssVars(cssProps); 31 | } 32 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/page-tab/svg-close.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/simple-scrollbar/index.ts: -------------------------------------------------------------------------------- 1 | import SimpleScrollbar from './index.vue'; 2 | 3 | export default SimpleScrollbar; 4 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/src/libs/simple-scrollbar/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /admin-ui/packages/materials/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /admin-ui/packages/ofetch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/fetch", 3 | "version": "1.0.8", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "ofetch": "1.3.4" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /admin-ui/packages/ofetch/src/index.ts: -------------------------------------------------------------------------------- 1 | import { ofetch } from 'ofetch'; 2 | import type { FetchOptions } from 'ofetch'; 3 | 4 | export function createRequest(options: FetchOptions) { 5 | const request = ofetch.create(options); 6 | 7 | return request; 8 | } 9 | 10 | export default createRequest; 11 | -------------------------------------------------------------------------------- /admin-ui/packages/ofetch/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /admin-ui/packages/scripts/bin.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tsx 2 | 3 | import './src/index.ts'; 4 | -------------------------------------------------------------------------------- /admin-ui/packages/scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/scripts", 3 | "version": "1.0.8", 4 | "bin": { 5 | "sa": "./bin.ts" 6 | }, 7 | "exports": { 8 | ".": "./src/index.ts" 9 | }, 10 | "typesVersions": { 11 | "*": { 12 | "*": ["./src/*"] 13 | } 14 | }, 15 | "devDependencies": { 16 | "@soybeanjs/changelog": "0.3.23", 17 | "bumpp": "9.4.0", 18 | "c12": "1.10.0", 19 | "cac": "6.7.14", 20 | "consola": "3.2.3", 21 | "enquirer": "2.4.1", 22 | "execa": "8.0.1", 23 | "kolorist": "1.8.0", 24 | "npm-check-updates": "16.14.20", 25 | "rimraf": "5.0.5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /admin-ui/packages/scripts/src/commands/changelog.ts: -------------------------------------------------------------------------------- 1 | import { generateChangelog, generateTotalChangelog } from '@soybeanjs/changelog'; 2 | import type { ChangelogOption } from '@soybeanjs/changelog'; 3 | 4 | export async function genChangelog(options?: Partial, total = false) { 5 | if (total) { 6 | await generateTotalChangelog(options); 7 | } else { 8 | await generateChangelog(options); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /admin-ui/packages/scripts/src/commands/cleanup.ts: -------------------------------------------------------------------------------- 1 | import { rimraf } from 'rimraf'; 2 | 3 | export async function cleanup(paths: string[]) { 4 | await rimraf(paths, { glob: true }); 5 | } 6 | -------------------------------------------------------------------------------- /admin-ui/packages/scripts/src/commands/index.ts: -------------------------------------------------------------------------------- 1 | export * from './git-commit'; 2 | export * from './cleanup'; 3 | export * from './update-pkg'; 4 | export * from './changelog'; 5 | export * from './release'; 6 | export * from './router'; 7 | -------------------------------------------------------------------------------- /admin-ui/packages/scripts/src/commands/release.ts: -------------------------------------------------------------------------------- 1 | import { versionBump } from 'bumpp'; 2 | 3 | export async function release(execute = 'pnpm sa changelog', push = true) { 4 | await versionBump({ 5 | files: ['**/package.json', '!**/node_modules'], 6 | execute, 7 | all: true, 8 | tag: true, 9 | commit: 'chore(projects): release v%s', 10 | push 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /admin-ui/packages/scripts/src/commands/update-pkg.ts: -------------------------------------------------------------------------------- 1 | import { execCommand } from '../shared'; 2 | 3 | export async function updatePkg(args: string[] = ['--deep', '-u']) { 4 | execCommand('npx', ['ncu', ...args], { stdio: 'inherit' }); 5 | } 6 | -------------------------------------------------------------------------------- /admin-ui/packages/scripts/src/shared/index.ts: -------------------------------------------------------------------------------- 1 | import type { Options } from 'execa'; 2 | 3 | export async function execCommand(cmd: string, args: string[], options?: Options) { 4 | const { execa } = await import('execa'); 5 | const res = await execa(cmd, args, options); 6 | return res?.stdout?.trim() || ''; 7 | } 8 | -------------------------------------------------------------------------------- /admin-ui/packages/scripts/src/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { ChangelogOption } from '@soybeanjs/changelog'; 2 | 3 | export interface CliOption { 4 | /** The project root directory */ 5 | cwd: string; 6 | /** 7 | * Cleanup dirs 8 | * 9 | * Glob pattern syntax {@link https://github.com/isaacs/minimatch} 10 | * 11 | * @default 12 | * ```json 13 | * ["** /dist", "** /pnpm-lock.yaml", "** /node_modules", "!node_modules/**"] 14 | * ``` 15 | */ 16 | cleanupDirs: string[]; 17 | /** Git commit types */ 18 | gitCommitTypes: [string, string][]; 19 | /** Git commit scopes */ 20 | gitCommitScopes: [string, string][]; 21 | /** 22 | * Npm-check-updates command args 23 | * 24 | * @default ['--deep', '-u'] 25 | */ 26 | ncuCommandArgs: string[]; 27 | /** 28 | * Options of generate changelog 29 | * 30 | * @link https://github.com/soybeanjs/changelog 31 | */ 32 | changelogOptions: Partial; 33 | } 34 | -------------------------------------------------------------------------------- /admin-ui/packages/scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*", "typings/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /admin-ui/packages/uno-preset/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/uno-preset", 3 | "version": "1.0.8", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /admin-ui/packages/uno-preset/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /admin-ui/packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/utils", 3 | "version": "1.0.8", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "colord": "2.9.3", 14 | "crypto-js": "4.2.0", 15 | "localforage": "1.10.0", 16 | "nanoid": "5.0.7" 17 | }, 18 | "devDependencies": { 19 | "@types/crypto-js": "4.2.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /admin-ui/packages/utils/src/crypto.ts: -------------------------------------------------------------------------------- 1 | import CryptoJS from 'crypto-js'; 2 | 3 | export class Crypto { 4 | /** Secret */ 5 | secret: string; 6 | 7 | constructor(secret: string) { 8 | this.secret = secret; 9 | } 10 | 11 | encrypt(data: T): string { 12 | const dataString = JSON.stringify(data); 13 | const encrypted = CryptoJS.AES.encrypt(dataString, this.secret); 14 | return encrypted.toString(); 15 | } 16 | 17 | decrypt(encrypted: string) { 18 | const decrypted = CryptoJS.AES.decrypt(encrypted, this.secret); 19 | const dataString = decrypted.toString(CryptoJS.enc.Utf8); 20 | try { 21 | return JSON.parse(dataString) as T; 22 | } catch { 23 | // avoid parse error 24 | return null; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /admin-ui/packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './color'; 2 | export * from './crypto'; 3 | export * from './storage'; 4 | export * from './nanoid'; 5 | -------------------------------------------------------------------------------- /admin-ui/packages/utils/src/nanoid.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from 'nanoid'; 2 | 3 | export { nanoid }; 4 | -------------------------------------------------------------------------------- /admin-ui/pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/*" 3 | -------------------------------------------------------------------------------- /admin-ui/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin-ui/src/App.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /admin-ui/src/assets/imgs/soybean.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/admin-ui/src/assets/imgs/soybean.jpg -------------------------------------------------------------------------------- /admin-ui/src/assets/svg-icon/activity.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin-ui/src/assets/svg-icon/at-sign.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin-ui/src/assets/svg-icon/cast.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin-ui/src/assets/svg-icon/chrome.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin-ui/src/assets/svg-icon/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin-ui/src/assets/svg-icon/custom-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin-ui/src/assets/svg-icon/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin-ui/src/assets/svg-icon/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin-ui/src/assets/svg-icon/wind.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin-ui/src/components/advanced/table-column-setting.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /admin-ui/src/components/common/app-provider.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /admin-ui/src/components/common/dark-mode-container.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /admin-ui/src/components/common/exception-base.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /admin-ui/src/components/common/full-screen.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /admin-ui/src/components/common/lang-switch.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /admin-ui/src/components/common/menu-toggler.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /admin-ui/src/components/common/pin-toggler.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /admin-ui/src/components/common/reload-button.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /admin-ui/src/components/common/system-logo.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /admin-ui/src/components/common/theme-schema-switch.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /admin-ui/src/components/custom/look-forward.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /admin-ui/src/components/custom/soybean-avatar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /admin-ui/src/components/custom/svg-icon.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /admin-ui/src/config/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 490912587@qq.com 3 | * @Date: 2024-05-14 14:05:35 4 | * @LastEditors: 490912587@qq.com 5 | * @LastEditTime: 2024-05-15 09:55:38 6 | * @FilePath: \admin-ui\src\config\index.ts 7 | * @Description: 8 | */ 9 | export * from './service'; 10 | export * from './regexp'; 11 | export * from './map-sdk'; -------------------------------------------------------------------------------- /admin-ui/src/config/map-sdk.ts: -------------------------------------------------------------------------------- 1 | /** 百度地图sdk地址 */ 2 | export const BAIDU_MAP_SDK_URL = `https://api.map.baidu.com/getscript?v=3.0&ak=KSezYymXPth1DIGILRX3oYN9PxbOQQmU&services=&t=20210201100830&s=1`; 3 | 4 | /** 高德地图sdk地址 */ 5 | export const AMAP_SDK_URL = 'https://webapi.amap.com/maps?v=2.0&key=e7bd02bd504062087e6563daf4d6721d'; 6 | 7 | /** 腾讯地图sdk地址 */ 8 | export const TENCENT_MAP_SDK_URL = 'https://map.qq.com/api/gljs?v=1.exp&key=A6DBZ-KXPLW-JKSRY-ONZF4-CPHY3-K6BL7'; 9 | -------------------------------------------------------------------------------- /admin-ui/src/config/regexp.ts: -------------------------------------------------------------------------------- 1 | /** 手机号码正则 */ 2 | export const REGEXP_PHONE = 3 | /^[1](([3][0-9])|([4][01456789])|([5][012356789])|([6][2567])|([7][0-8])|([8][0-9])|([9][012356789]))[0-9]{8}$/; 4 | 5 | /** 邮箱正则 */ 6 | export const REGEXP_EMAIL = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; 7 | 8 | /** 密码正则(密码为6-18位数字/字符/符号的组合) */ 9 | export const REGEXP_PWD = 10 | /^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){5,18}$/; 11 | 12 | /** 6位数字验证码正则 */ 13 | export const REGEXP_CODE_SIX = /^\d{6}$/; 14 | 15 | /** 4位数字验证码正则 */ 16 | export const REGEXP_CODE_FOUR = /^\d{4}$/; 17 | 18 | /** url链接正则 */ 19 | export const REGEXP_URL = 20 | /(((^https?:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)$/; 21 | -------------------------------------------------------------------------------- /admin-ui/src/config/service.ts: -------------------------------------------------------------------------------- 1 | /** 请求超时时间 */ 2 | export const REQUEST_TIMEOUT = 60 * 1000; 3 | 4 | /** 错误信息的显示时间 */ 5 | export const ERROR_MSG_DURATION = 3 * 1000; 6 | 7 | /** 默认的请求错误code */ 8 | export const DEFAULT_REQUEST_ERROR_CODE = 'DEFAULT'; 9 | 10 | /** 默认的请求错误文本 */ 11 | export const DEFAULT_REQUEST_ERROR_MSG = '请求错误~'; 12 | 13 | /** 请求超时的错误code(为固定值:ECONNABORTED) */ 14 | export const REQUEST_TIMEOUT_CODE = 'ECONNABORTED'; 15 | 16 | /** 请求超时的错误文本 */ 17 | export const REQUEST_TIMEOUT_MSG = '请求超时~'; 18 | 19 | /** 网络不可用的code */ 20 | export const NETWORK_ERROR_CODE = 'NETWORK_ERROR'; 21 | 22 | /** 网络不可用的错误文本 */ 23 | export const NETWORK_ERROR_MSG = '网络不可用~'; 24 | 25 | /** 请求不成功各种状态的错误 */ 26 | export const ERROR_STATUS = { 27 | 400: '400: 请求出现语法错误~', 28 | 401: '401: 用户未授权~', 29 | 403: '403: 服务器拒绝访问~', 30 | 404: '404: 请求的资源不存在~', 31 | 405: '405: 请求方法未允许~', 32 | 408: '408: 网络请求超时~', 33 | 500: '500: 服务器内部错误~', 34 | 501: '501: 服务器未实现请求功能~', 35 | 502: '502: 错误网关~', 36 | 503: '503: 服务不可用~', 37 | 504: '504: 网关超时~', 38 | 505: '505: http版本不支持该请求~', 39 | [DEFAULT_REQUEST_ERROR_CODE]: DEFAULT_REQUEST_ERROR_MSG 40 | }; 41 | 42 | /** 不弹出错误信息的code */ 43 | export const NO_ERROR_MSG_CODE: (string | number)[] = []; 44 | 45 | /** token失效需要刷新token的code(这里的401只是个例子,需要将后端表示token过期的code填进来) */ 46 | export const REFRESH_TOKEN_CODE: (string | number)[] = [401]; 47 | -------------------------------------------------------------------------------- /admin-ui/src/constants/business.ts: -------------------------------------------------------------------------------- 1 | import { transformRecordToOption } from '@/utils/common'; 2 | 3 | export const enableStatusRecord: Record = { 4 | '1': 'page.manage.common.status.enable', 5 | '2': 'page.manage.common.status.disable' 6 | }; 7 | 8 | export const enableStatusOptions = transformRecordToOption(enableStatusRecord); 9 | 10 | export const userGenderRecord: Record = { 11 | '1': 'page.manage.user.gender.male', 12 | '2': 'page.manage.user.gender.female' 13 | }; 14 | 15 | export const userGenderOptions = transformRecordToOption(userGenderRecord); 16 | 17 | export const menuTypeRecord: Record = { 18 | '1': 'page.manage.menu.type.directory', 19 | '2': 'page.manage.menu.type.menu' 20 | }; 21 | 22 | export const menuTypeOptions = transformRecordToOption(menuTypeRecord); 23 | 24 | export const menuIconTypeRecord: Record = { 25 | '1': 'page.manage.menu.iconType.iconify', 26 | '2': 'page.manage.menu.iconType.local' 27 | }; 28 | 29 | export const menuIconTypeOptions = transformRecordToOption(menuIconTypeRecord); 30 | -------------------------------------------------------------------------------- /admin-ui/src/constants/common.ts: -------------------------------------------------------------------------------- 1 | import { transformRecordToOption } from '@/utils/common'; 2 | 3 | export const yesOrNoRecord: Record = { 4 | Y: 'common.yesOrNo.yes', 5 | N: 'common.yesOrNo.no' 6 | }; 7 | 8 | export const yesOrNoOptions = transformRecordToOption(yesOrNoRecord); 9 | -------------------------------------------------------------------------------- /admin-ui/src/constants/reg.ts: -------------------------------------------------------------------------------- 1 | export const REG_USER_NAME = /^[\u4E00-\u9FA5a-zA-Z0-9_-]{4,16}$/; 2 | 3 | /** Phone reg */ 4 | export const REG_PHONE = 5 | /^[1](([3][0-9])|([4][01456789])|([5][012356789])|([6][2567])|([7][0-8])|([8][0-9])|([9][012356789]))[0-9]{8}$/; 6 | 7 | /** 8 | * Password reg 9 | * 10 | * 6-18 characters, including letters, numbers, and underscores 11 | */ 12 | export const REG_PWD = /^\w{6,18}$/; 13 | 14 | /** Email reg */ 15 | export const REG_EMAIL = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; 16 | 17 | /** Six digit code reg */ 18 | export const REG_CODE_SIX = /^\d{6}$/; 19 | 20 | /** Four digit code reg */ 21 | export const REG_CODE_FOUR = /^\d{4}$/; 22 | 23 | /** Url reg */ 24 | export const REG_URL = 25 | /(((^https?:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)$/; 26 | -------------------------------------------------------------------------------- /admin-ui/src/enum/index.ts: -------------------------------------------------------------------------------- 1 | export enum SetupStoreId { 2 | App = 'app-store', 3 | Theme = 'theme-store', 4 | Auth = 'auth-store', 5 | Route = 'route-store', 6 | Tab = 'tab-store' 7 | } 8 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/business/auth.ts: -------------------------------------------------------------------------------- 1 | import { useAuthStore } from '@/store/modules/auth'; 2 | 3 | export function useAuth() { 4 | const authStore = useAuthStore(); 5 | 6 | function hasAuth(codes: string | string[]) { 7 | if (!authStore.isLogin) { 8 | return false; 9 | } 10 | 11 | if (typeof codes === 'string') { 12 | return authStore.userInfo.buttons.includes(codes); 13 | } 14 | 15 | return codes.some(code => authStore.userInfo.buttons.includes(code)); 16 | } 17 | 18 | return { 19 | hasAuth 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/business/index.ts: -------------------------------------------------------------------------------- 1 | import useCountDown from './use-count-down'; 2 | import useSmsCode from './use-sms-code'; 3 | import useImageVerify from './use-image-verify'; 4 | 5 | export { useCountDown, useSmsCode, useImageVerify }; 6 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/business/use-count-down.ts: -------------------------------------------------------------------------------- 1 | import { computed, onScopeDispose, ref } from 'vue'; 2 | import { useBoolean } from '../common'; 3 | 4 | /** 5 | * 倒计时 6 | * @param second - 倒计时的时间(s) 7 | */ 8 | export default function useCountDown(second: number) { 9 | if (second <= 0 && second % 1 !== 0) { 10 | throw new Error('倒计时的时间应该为一个正整数!'); 11 | } 12 | const { bool: isComplete, setTrue, setFalse } = useBoolean(false); 13 | 14 | const counts = ref(0); 15 | const isCounting = computed(() => Boolean(counts.value)); 16 | 17 | let intervalId: any; 18 | 19 | /** 20 | * 开始计时 21 | * @param updateSecond - 更改初时传入的倒计时时间 22 | */ 23 | function start(updateSecond: number = second) { 24 | if (!counts.value) { 25 | setFalse(); 26 | counts.value = updateSecond; 27 | intervalId = setInterval(() => { 28 | counts.value -= 1; 29 | if (counts.value <= 0) { 30 | clearInterval(intervalId); 31 | setTrue(); 32 | } 33 | }, 1000); 34 | } 35 | } 36 | 37 | /** 38 | * 停止计时 39 | */ 40 | function stop() { 41 | intervalId = clearInterval(intervalId); 42 | counts.value = 0; 43 | } 44 | 45 | onScopeDispose(stop); 46 | 47 | return { 48 | counts, 49 | isCounting, 50 | start, 51 | stop, 52 | isComplete 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/common/icon.ts: -------------------------------------------------------------------------------- 1 | import { useSvgIconRender } from '@sa/hooks'; 2 | import SvgIcon from '@/components/custom/svg-icon.vue'; 3 | 4 | export function useSvgIcon() { 5 | const { SvgIconVNode } = useSvgIconRender(SvgIcon); 6 | 7 | return { 8 | SvgIconVNode 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/common/index.ts: -------------------------------------------------------------------------------- 1 | import useContext from './use-context'; 2 | import useBoolean from './use-boolean'; 3 | import useLoading from './use-loading'; 4 | import useLoadingEmpty from './use-loading-empty'; 5 | import useReload from './use-reload'; 6 | 7 | export { useContext, useBoolean, useLoading, useLoadingEmpty, useReload }; 8 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/common/use-boolean.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | /** 4 | * boolean组合式函数 5 | * @param initValue 初始值 6 | */ 7 | export default function useBoolean(initValue = false) { 8 | const bool = ref(initValue); 9 | 10 | function setBool(value: boolean) { 11 | bool.value = value; 12 | } 13 | function setTrue() { 14 | setBool(true); 15 | } 16 | function setFalse() { 17 | setBool(false); 18 | } 19 | function toggle() { 20 | setBool(!bool.value); 21 | } 22 | 23 | return { 24 | bool, 25 | setBool, 26 | setTrue, 27 | setFalse, 28 | toggle 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/common/use-context.ts: -------------------------------------------------------------------------------- 1 | import { inject, provide } from 'vue'; 2 | import type { InjectionKey } from 'vue'; 3 | 4 | /** 创建共享上下文状态 */ 5 | export default function useContext(contextName = 'context') { 6 | const injectKey: InjectionKey = Symbol(contextName); 7 | 8 | function useProvide(context: T) { 9 | provide(injectKey, context); 10 | return context; 11 | } 12 | 13 | function useInject() { 14 | return inject(injectKey) as T; 15 | } 16 | 17 | return { 18 | useProvide, 19 | useInject 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/common/use-loading-empty.ts: -------------------------------------------------------------------------------- 1 | import useBoolean from './use-boolean'; 2 | 3 | export default function useLoadingEmpty(initLoading = false, initEmpty = false) { 4 | const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(initLoading); 5 | const { bool: empty, setBool: setEmpty } = useBoolean(initEmpty); 6 | 7 | return { 8 | loading, 9 | startLoading, 10 | endLoading, 11 | empty, 12 | setEmpty 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/common/use-loading.ts: -------------------------------------------------------------------------------- 1 | import useBoolean from './use-boolean'; 2 | 3 | export default function useLoading(initValue = false) { 4 | const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(initValue); 5 | 6 | return { 7 | loading, 8 | startLoading, 9 | endLoading 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/common/use-reload.ts: -------------------------------------------------------------------------------- 1 | import { nextTick } from 'vue'; 2 | import useBoolean from './use-boolean'; 3 | 4 | /** 重载 */ 5 | export default function useReload() { 6 | // 重载的标志 7 | const { bool: reloadFlag, setTrue, setFalse } = useBoolean(true); 8 | 9 | /** 10 | * 触发重载 11 | * @param duration - 延迟时间(ms) 12 | */ 13 | async function handleReload(duration = 0) { 14 | setFalse(); 15 | await nextTick(); 16 | 17 | if (duration > 0) { 18 | setTimeout(() => { 19 | setTrue(); 20 | }, duration); 21 | } 22 | } 23 | 24 | return { 25 | reloadFlag, 26 | handleReload 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /admin-ui/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; 2 | export * from './business'; 3 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/blank-layout/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/context/index.ts: -------------------------------------------------------------------------------- 1 | import { computed, ref, watch } from 'vue'; 2 | import { useRoute } from 'vue-router'; 3 | import { useContext } from '@sa/hooks'; 4 | import { useRouteStore } from '@/store/modules/route'; 5 | 6 | export const { setupStore: setupMixMenuContext, useStore: useMixMenuContext } = useContext('mix-menu', useMixMenu); 7 | 8 | function useMixMenu() { 9 | const route = useRoute(); 10 | const routeStore = useRouteStore(); 11 | 12 | const activeFirstLevelMenuKey = ref(''); 13 | 14 | function setActiveFirstLevelMenuKey(key: string) { 15 | activeFirstLevelMenuKey.value = key; 16 | } 17 | 18 | function getActiveFirstLevelMenuKey() { 19 | const { hideInMenu, activeMenu } = route.meta; 20 | const name = route.name as string; 21 | 22 | const routeName = (hideInMenu ? activeMenu : name) || name; 23 | 24 | const [firstLevelRouteName] = routeName.split('_'); 25 | 26 | setActiveFirstLevelMenuKey(firstLevelRouteName); 27 | } 28 | 29 | const menus = computed( 30 | () => routeStore.menus.find(menu => menu.key === activeFirstLevelMenuKey.value)?.children || [] 31 | ); 32 | 33 | watch( 34 | () => route.name, 35 | () => { 36 | getActiveFirstLevelMenuKey(); 37 | }, 38 | { immediate: true } 39 | ); 40 | 41 | return { 42 | activeFirstLevelMenuKey, 43 | setActiveFirstLevelMenuKey, 44 | getActiveFirstLevelMenuKey, 45 | menus 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/modules/global-content/index.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/modules/global-footer/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 14 | 15 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/modules/global-header/components/theme-button.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/modules/global-logo/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/modules/global-menu/horizontal-mix-menu.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/modules/global-search/components/search-footer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | 25 | 37 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/modules/global-search/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/modules/theme-drawer/components/setting-item.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /admin-ui/src/layouts/modules/theme-drawer/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /admin-ui/src/locales/dayjs.ts: -------------------------------------------------------------------------------- 1 | import { locale } from 'dayjs'; 2 | import 'dayjs/locale/zh-cn'; 3 | import 'dayjs/locale/en'; 4 | import { localStg } from '@/utils/storage'; 5 | 6 | /** 7 | * Set dayjs locale 8 | * 9 | * @param lang 10 | */ 11 | export function setDayjsLocale(lang: App.I18n.LangType = 'zh-CN') { 12 | const localMap = { 13 | 'zh-CN': 'zh-cn', 14 | 'en-US': 'en' 15 | } satisfies Record; 16 | 17 | const l = lang || localStg.get('lang') || 'zh-CN'; 18 | 19 | locale(localMap[l]); 20 | } 21 | -------------------------------------------------------------------------------- /admin-ui/src/locales/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue'; 2 | import { createI18n } from 'vue-i18n'; 3 | import { localStg } from '@/utils/storage'; 4 | import messages from './locale'; 5 | 6 | const i18n = createI18n({ 7 | locale: localStg.get('lang') || 'zh-CN', 8 | fallbackLocale: 'en', 9 | messages, 10 | legacy: false 11 | }); 12 | 13 | /** 14 | * Setup plugin i18n 15 | * 16 | * @param app 17 | */ 18 | export function setupI18n(app: App) { 19 | app.use(i18n); 20 | } 21 | 22 | export const $t = i18n.global.t as App.I18n.$T; 23 | 24 | export function setLocale(locale: App.I18n.LangType) { 25 | i18n.global.locale.value = locale; 26 | } 27 | -------------------------------------------------------------------------------- /admin-ui/src/locales/locale.ts: -------------------------------------------------------------------------------- 1 | import zhCN from './langs/zh-cn'; 2 | import enUS from './langs/en-us'; 3 | 4 | const locales: Record = { 5 | 'zh-CN': zhCN, 6 | 'en-US': enUS 7 | }; 8 | 9 | export default locales; 10 | -------------------------------------------------------------------------------- /admin-ui/src/locales/naive.ts: -------------------------------------------------------------------------------- 1 | import { dateEnUS, dateZhCN, enUS, zhCN } from 'naive-ui'; 2 | import type { NDateLocale, NLocale } from 'naive-ui'; 3 | 4 | export const naiveLocales: Record = { 5 | 'zh-CN': zhCN, 6 | 'en-US': enUS 7 | }; 8 | 9 | export const naiveDateLocales: Record = { 10 | 'zh-CN': dateZhCN, 11 | 'en-US': dateEnUS 12 | }; 13 | -------------------------------------------------------------------------------- /admin-ui/src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 490912587@qq.com 3 | * @Date: 2024-04-30 15:08:20 4 | * @LastEditors: 490912587@qq.com 5 | * @LastEditTime: 2024-05-09 16:46:29 6 | * @FilePath: \admin-ui\src\main.ts 7 | * @Description: 8 | */ 9 | import { createApp } from 'vue'; 10 | import './plugins/assets'; 11 | import { setupDayjs, setupIconifyOffline, setupLoading, setupNProgress } from './plugins'; 12 | import { setupStore } from './store'; 13 | import { setupRouter } from './router'; 14 | import { setupI18n } from './locales'; 15 | import { setupFastCrud } from './plugins/fast-crud'; 16 | import App from './App.vue'; 17 | 18 | async function setupApp() { 19 | setupLoading(); 20 | 21 | setupNProgress(); 22 | 23 | setupIconifyOffline(); 24 | 25 | setupDayjs(); 26 | 27 | const app = createApp(App); 28 | 29 | setupStore(app); 30 | 31 | await setupRouter(app); 32 | 33 | setupI18n(app); 34 | 35 | setupFastCrud(app); 36 | 37 | app.mount('#app'); 38 | } 39 | 40 | setupApp(); 41 | -------------------------------------------------------------------------------- /admin-ui/src/plugins/assets.ts: -------------------------------------------------------------------------------- 1 | import 'virtual:svg-icons-register'; 2 | import 'uno.css'; 3 | import '../styles/css/global.css'; 4 | -------------------------------------------------------------------------------- /admin-ui/src/plugins/dayjs.ts: -------------------------------------------------------------------------------- 1 | import { extend } from 'dayjs'; 2 | import localeData from 'dayjs/plugin/localeData'; 3 | import { setDayjsLocale } from '../locales/dayjs'; 4 | 5 | export function setupDayjs() { 6 | extend(localeData); 7 | 8 | setDayjsLocale(); 9 | } 10 | -------------------------------------------------------------------------------- /admin-ui/src/plugins/fast-crud/common.scss: -------------------------------------------------------------------------------- 1 | html:root { 2 | --baseColor: #fff; 3 | } 4 | /* 深色模式 */ 5 | html.dark:root { 6 | --baseColor: #000; 7 | } 8 | 9 | .fs-container { 10 | background-color: var(--baseColor); 11 | } 12 | -------------------------------------------------------------------------------- /admin-ui/src/plugins/fast-crud/naive.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue'; 2 | import * as NaiveUI from 'naive-ui'; 3 | 4 | const naive = NaiveUI.create({ 5 | components: [ 6 | NaiveUI.NInput, 7 | NaiveUI.NButton, 8 | NaiveUI.NForm, 9 | NaiveUI.NFormItem, 10 | NaiveUI.NCheckboxGroup, 11 | NaiveUI.NCheckbox, 12 | NaiveUI.NIcon, 13 | NaiveUI.NDropdown, 14 | NaiveUI.NTooltip, 15 | NaiveUI.NTabs, 16 | NaiveUI.NTabPane, 17 | NaiveUI.NCard, 18 | NaiveUI.NRow, 19 | NaiveUI.NCol, 20 | NaiveUI.NDrawer, 21 | NaiveUI.NDrawerContent, 22 | NaiveUI.NDivider, 23 | NaiveUI.NSwitch, 24 | NaiveUI.NBadge, 25 | NaiveUI.NAlert, 26 | NaiveUI.NTag, 27 | NaiveUI.NProgress, 28 | NaiveUI.NDatePicker, 29 | NaiveUI.NGrid, 30 | NaiveUI.NGridItem, 31 | NaiveUI.NDataTable, 32 | NaiveUI.NPagination, 33 | NaiveUI.NSelect, 34 | NaiveUI.NRadioGroup, 35 | NaiveUI.NRadio, 36 | NaiveUI.NInputGroup, 37 | NaiveUI.NTable, 38 | NaiveUI.NInputNumber, 39 | NaiveUI.NLoadingBarProvider, 40 | NaiveUI.NModal, 41 | NaiveUI.NUpload, 42 | NaiveUI.NTree, 43 | NaiveUI.NSpin, 44 | NaiveUI.NTimePicker, 45 | 46 | // add by fs 47 | NaiveUI.NCascader, 48 | NaiveUI.NRadioButton, 49 | NaiveUI.NTreeSelect, 50 | NaiveUI.NImageGroup, 51 | NaiveUI.NImage, 52 | NaiveUI.NCollapse, 53 | NaiveUI.NCollapseItem 54 | ] 55 | }); 56 | 57 | export function setupNaive(app: App) { 58 | app.use(naive); 59 | } 60 | -------------------------------------------------------------------------------- /admin-ui/src/plugins/iconify.ts: -------------------------------------------------------------------------------- 1 | import { addAPIProvider, disableCache } from '@iconify/vue'; 2 | 3 | /** Setup the iconify offline */ 4 | export function setupIconifyOffline() { 5 | const { VITE_ICONIFY_URL } = import.meta.env; 6 | 7 | if (VITE_ICONIFY_URL) { 8 | addAPIProvider('', { resources: [VITE_ICONIFY_URL] }); 9 | 10 | disableCache('all'); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /admin-ui/src/plugins/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | export * from './nprogress'; 3 | export * from './iconify'; 4 | export * from './dayjs'; 5 | -------------------------------------------------------------------------------- /admin-ui/src/plugins/loading.ts: -------------------------------------------------------------------------------- 1 | // @unocss-include 2 | import { getRgbOfColor } from '@sa/utils'; 3 | import { $t } from '@/locales'; 4 | import { localStg } from '@/utils/storage'; 5 | import systemLogo from '@/assets/svg-icon/logo.svg?raw'; 6 | 7 | export function setupLoading() { 8 | const themeColor = localStg.get('themeColor') || '#646cff'; 9 | 10 | const { r, g, b } = getRgbOfColor(themeColor); 11 | 12 | const primaryColor = `--primary-color: ${r} ${g} ${b}`; 13 | 14 | const loadingClasses = [ 15 | 'left-0 top-0', 16 | 'left-0 bottom-0 animate-delay-500', 17 | 'right-0 top-0 animate-delay-1000', 18 | 'right-0 bottom-0 animate-delay-1500' 19 | ]; 20 | 21 | const logoWithClass = systemLogo.replace(' { 25 | return `
`; 26 | }) 27 | .join('\n'); 28 | 29 | const loading = ` 30 |
31 | ${logoWithClass} 32 |
33 |
34 | ${dot} 35 |
36 |
37 |

${$t('system.title')}

38 |
`; 39 | 40 | const app = document.getElementById('app'); 41 | 42 | if (app) { 43 | app.innerHTML = loading; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /admin-ui/src/plugins/nprogress.ts: -------------------------------------------------------------------------------- 1 | import NProgress from 'nprogress'; 2 | 3 | /** Setup plugin NProgress */ 4 | export function setupNProgress() { 5 | NProgress.configure({ easing: 'ease', speed: 500 }); 6 | 7 | // mount on window 8 | window.NProgress = NProgress; 9 | } 10 | -------------------------------------------------------------------------------- /admin-ui/src/router/guard/index.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from 'vue-router'; 2 | import { createRouteGuard } from './route'; 3 | import { createProgressGuard } from './progress'; 4 | import { createDocumentTitleGuard } from './title'; 5 | 6 | /** 7 | * Router guard 8 | * 9 | * @param router - Router instance 10 | */ 11 | export function createRouterGuard(router: Router) { 12 | createProgressGuard(router); 13 | createRouteGuard(router); 14 | createDocumentTitleGuard(router); 15 | } 16 | -------------------------------------------------------------------------------- /admin-ui/src/router/guard/progress.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from 'vue-router'; 2 | 3 | export function createProgressGuard(router: Router) { 4 | router.beforeEach((_to, _from, next) => { 5 | window.NProgress?.start?.(); 6 | next(); 7 | }); 8 | router.afterEach(_to => { 9 | window.NProgress?.done?.(); 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /admin-ui/src/router/guard/title.ts: -------------------------------------------------------------------------------- 1 | import { useTitle } from '@vueuse/core'; 2 | import type { Router } from 'vue-router'; 3 | import { $t } from '@/locales'; 4 | 5 | export function createDocumentTitleGuard(router: Router) { 6 | router.afterEach(to => { 7 | const { i18nKey, title } = to.meta; 8 | 9 | const documentTitle = i18nKey ? $t(i18nKey) : title; 10 | 11 | useTitle(documentTitle); 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /admin-ui/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue'; 2 | import { 3 | type RouterHistory, 4 | createMemoryHistory, 5 | createRouter, 6 | createWebHashHistory, 7 | createWebHistory 8 | } from 'vue-router'; 9 | import { createBuiltinVueRoutes } from './routes/builtin'; 10 | import { createRouterGuard } from './guard'; 11 | 12 | const { VITE_ROUTER_HISTORY_MODE = 'history', VITE_BASE_URL } = import.meta.env; 13 | 14 | const historyCreatorMap: Record RouterHistory> = { 15 | hash: createWebHashHistory, 16 | history: createWebHistory, 17 | memory: createMemoryHistory 18 | }; 19 | 20 | export const router = createRouter({ 21 | history: historyCreatorMap[VITE_ROUTER_HISTORY_MODE](VITE_BASE_URL), 22 | routes: createBuiltinVueRoutes() 23 | }); 24 | 25 | /** Setup Vue Router */ 26 | export async function setupRouter(app: App) { 27 | app.use(router); 28 | createRouterGuard(router); 29 | await router.isReady(); 30 | } 31 | -------------------------------------------------------------------------------- /admin-ui/src/router/routes/builtin.ts: -------------------------------------------------------------------------------- 1 | import type { CustomRoute } from '@elegant-router/types'; 2 | import { layouts, views } from '../elegant/imports'; 3 | import { getRoutePath, transformElegantRoutesToVueRoutes } from '../elegant/transform'; 4 | 5 | export const ROOT_ROUTE: CustomRoute = { 6 | name: 'root', 7 | path: '/', 8 | redirect: getRoutePath(import.meta.env.VITE_ROUTE_HOME) || '/home', 9 | meta: { 10 | title: 'root', 11 | constant: true 12 | } 13 | }; 14 | 15 | const NOT_FOUND_ROUTE: CustomRoute = { 16 | name: 'not-found', 17 | path: '/:pathMatch(.*)*', 18 | component: 'layout.blank$view.404', 19 | meta: { 20 | title: 'not-found', 21 | constant: true 22 | } 23 | }; 24 | 25 | /** builtin routes, it must be constant and setup in vue-router */ 26 | const builtinRoutes: CustomRoute[] = [ROOT_ROUTE, NOT_FOUND_ROUTE]; 27 | 28 | /** create builtin vue routes */ 29 | export function createBuiltinVueRoutes() { 30 | return transformElegantRoutesToVueRoutes(builtinRoutes, layouts, views); 31 | } 32 | -------------------------------------------------------------------------------- /admin-ui/src/service/api/auth.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 490912587@qq.com 3 | * @Date: 2024-04-30 15:08:20 4 | * @LastEditors: 490912587@qq.com 5 | * @LastEditTime: 2024-05-14 13:33:52 6 | * @FilePath: \admin-ui\src\service\api\auth.ts 7 | * @Description: 8 | */ 9 | import { request } from '../request'; 10 | 11 | /** 12 | * Login 13 | * 14 | * @param account User name 15 | * @param password Password 16 | */ 17 | export function fetchLogin(account: string, password: string) { 18 | return request({ 19 | url: '/default/Auth/PwdLogin', 20 | method: 'post', 21 | data: { 22 | account, 23 | password 24 | } 25 | }); 26 | } 27 | 28 | /** Get user info */ 29 | export function fetchGetUserInfo() { 30 | return request({ url: '/default/Auth/UserInfo' }); 31 | } 32 | 33 | /** 34 | * Refresh token 35 | * 36 | * @param refreshToken Refresh token 37 | */ 38 | export function fetchRefreshToken(refreshToken: string) { 39 | return request({ 40 | url: '/auth/refreshToken', 41 | method: 'post', 42 | data: { 43 | refreshToken 44 | } 45 | }); 46 | } 47 | 48 | /** 49 | * return custom backend error 50 | * 51 | * @param code error code 52 | * @param msg error message 53 | */ 54 | export function fetchCustomBackendError(code: string, msg: string) { 55 | return request({ url: '/auth/error', params: { code, msg } }); 56 | } 57 | -------------------------------------------------------------------------------- /admin-ui/src/service/api/department.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 490912587@qq.com 3 | * @Date: 2024-04-30 15:08:20 4 | * @LastEditors: 490912587@qq.com 5 | * @LastEditTime: 2024-05-15 13:56:15 6 | * @FilePath: \admin-ui\src\service\api\department.ts 7 | * @Description: 8 | */ 9 | import { request } from '../request'; 10 | import qs from 'qs'; 11 | export function getDepartment(params: object) { 12 | return request({ url: '/default/Department/Tree?' + qs.stringify(params) }); 13 | } 14 | export function getDepartmentPage(params: object) { 15 | return request({ url: '/default/Department/Page?' + qs.stringify(params) }); 16 | } 17 | export function addDepartment(data: object) { 18 | return request({ 19 | url: '/default/Department', 20 | method: 'post', 21 | data 22 | }); 23 | } 24 | export function editDepartment(data: object) { 25 | return request({ 26 | url: '/default/Department/Edit', 27 | method: 'post', 28 | data 29 | }); 30 | } 31 | export function delDepartment(data: object) { 32 | return request({ 33 | url: '/default/Department/Del', 34 | method: 'post', 35 | data 36 | }); 37 | } 38 | export function delBatchDepartment(data: object) { 39 | return request({ 40 | url: '/default/Department/DelBatch', 41 | method: 'post', 42 | data 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /admin-ui/src/service/api/enum.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 490912587@qq.com 3 | * @Date: 2024-01-10 16:24:10 4 | * @LastEditors: 490912587@qq.com 5 | * @LastEditTime: 2024-05-14 15:46:49 6 | * @FilePath: \admin-ui\src\service\api\enum.ts 7 | * @Description: 8 | */ 9 | import { request } from '../request'; 10 | // 获取所有枚举类型 11 | export const getEnumTypeList = async () => { 12 | const result = await request({ url: '/default/Enum/EnumTypeList' }); 13 | return result; 14 | }; 15 | // 通过枚举类型名称获取枚举值 16 | export const getEnumDataByTypeName = async (typeName: string) => { 17 | const result = await request({ url: '/default/Enum/EnumDataList', params: { EnumName: typeName } }); 18 | return result; 19 | }; -------------------------------------------------------------------------------- /admin-ui/src/service/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth'; 2 | export * from './route'; 3 | export * from './user'; 4 | export * from './menu'; 5 | export * from './enum'; 6 | export * from './department'; 7 | export * from './post'; -------------------------------------------------------------------------------- /admin-ui/src/service/api/menu.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 490912587@qq.com 3 | * @Date: 2024-05-09 17:30:09 4 | * @LastEditors: 490912587@qq.com 5 | * @LastEditTime: 2024-05-16 11:01:57 6 | * @FilePath: \admin-ui\src\service\api\menu.ts 7 | * @Description: 8 | */ 9 | import { request } from '../request'; 10 | import qs from 'qs'; 11 | export function getMenuTree(params: object) { 12 | return request({ url: '/default/Menu/MenuTreeList?' + qs.stringify(params) }); 13 | } 14 | export function addMenu(data: object) { 15 | return request({ 16 | url: '/default/Menu', 17 | method: 'post', 18 | data 19 | }); 20 | } 21 | export function editMenu(data: object) { 22 | return request({ 23 | url: '/default/Menu/Edit', 24 | method: 'post', 25 | data 26 | }); 27 | } 28 | export function delMenu(data: object) { 29 | return request({ 30 | url: '/default/Menu/Del', 31 | method: 'post', 32 | data 33 | }); 34 | } 35 | export function delBatchMenu(data: object) { 36 | return request({ 37 | url: '/default/Menu/DelBatch', 38 | method: 'post', 39 | data 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /admin-ui/src/service/api/post.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 490912587@qq.com 3 | * @Date: 2024-04-30 15:08:20 4 | * @LastEditors: 490912587@qq.com 5 | * @LastEditTime: 2024-05-15 13:56:21 6 | * @FilePath: \admin-ui\src\service\api\post.ts 7 | * @Description: 8 | */ 9 | import { request } from '../request'; 10 | import qs from 'qs'; 11 | export function getPost(params: object) { 12 | return request({ url: '/default/Post/List?' + qs.stringify(params) }); 13 | } 14 | export function getPostPage(params: object) { 15 | return request({ url: '/default/Post/Page?' + qs.stringify(params) }); 16 | } 17 | export function addPost(data: object) { 18 | return request({ 19 | url: '/default/Post', 20 | method: 'post', 21 | data 22 | }); 23 | } 24 | export function editPost(data: object) { 25 | return request({ 26 | url: '/default/Post/Edit', 27 | method: 'post', 28 | data 29 | }); 30 | } 31 | export function delPost(data: object) { 32 | return request({ 33 | url: '/default/Post/Del', 34 | method: 'post', 35 | data 36 | }); 37 | } 38 | export function delBatchPost(data: object) { 39 | return request({ 40 | url: '/default/Post/DelBatch', 41 | method: 'post', 42 | data 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /admin-ui/src/service/api/route.ts: -------------------------------------------------------------------------------- 1 | import { request } from '../request'; 2 | 3 | /** get constant routes */ 4 | /** 基础路由,不依赖布局的页面路由放到此处 */ 5 | export function fetchGetConstantRoutes() { 6 | return request({ url: '/default/Menu/ConstRoutes' }); 7 | } 8 | 9 | /** get user routes */ 10 | export function fetchGetUserRoutes() { 11 | return request({ url: '/default/Menu/UserRoutes' }); 12 | } 13 | 14 | /** 15 | * whether the route is exist 16 | * 17 | * @param routeName route name 18 | */ 19 | export function fetchIsRouteExist(routeName: string) { 20 | return request({ url: '/route/isRouteExist', params: { routeName } }); 21 | } 22 | -------------------------------------------------------------------------------- /admin-ui/src/service/api/user.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 490912587@qq.com 3 | * @Date: 2024-04-30 15:08:20 4 | * @LastEditors: 490912587@qq.com 5 | * @LastEditTime: 2024-05-15 10:04:10 6 | * @FilePath: \admin-ui\src\service\api\user.ts 7 | * @Description: 8 | */ 9 | import { request } from '../request'; 10 | import qs from 'qs'; 11 | export function getUserPage(params: object) { 12 | return request({ url: '/default/User/Page?' + qs.stringify(params) }); 13 | } 14 | export function addUser(data: object) { 15 | return request({ 16 | url: '/default/User/PcUser', 17 | method: 'post', 18 | data 19 | }); 20 | } 21 | export function editUser(data: object) { 22 | return request({ 23 | url: '/default/User/Edit', 24 | method: 'post', 25 | data 26 | }); 27 | } 28 | export function delUser(data: object) { 29 | return request({ 30 | url: '/default/User/Del', 31 | method: 'post', 32 | data 33 | }); 34 | } 35 | export function delBatchUser(data: object) { 36 | return request({ 37 | url: '/default/User/DelBatch', 38 | method: 'post', 39 | data 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /admin-ui/src/service/request/shared.ts: -------------------------------------------------------------------------------- 1 | import type { AxiosRequestConfig } from 'axios'; 2 | import { useAuthStore } from '@/store/modules/auth'; 3 | import { localStg } from '@/utils/storage'; 4 | import { fetchRefreshToken } from '../api'; 5 | 6 | /** 7 | * refresh token 8 | * 9 | * @param axiosConfig - request config when the token is expired 10 | */ 11 | export async function handleRefreshToken(axiosConfig: AxiosRequestConfig) { 12 | const { resetStore } = useAuthStore(); 13 | 14 | const refreshToken = localStg.get('refreshToken') || ''; 15 | const { error, data } = await fetchRefreshToken(refreshToken); 16 | if (!error) { 17 | localStg.set('token', data.token); 18 | localStg.set('refreshToken', data.refreshToken); 19 | 20 | const config = { ...axiosConfig }; 21 | if (config.headers) { 22 | config.headers.Authorization = data.token; 23 | } 24 | 25 | return config; 26 | } 27 | 28 | resetStore(); 29 | 30 | return null; 31 | } 32 | -------------------------------------------------------------------------------- /admin-ui/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue'; 2 | import { createPinia } from 'pinia'; 3 | import { resetSetupStore } from './plugins'; 4 | 5 | /** Setup Vue store plugin pinia */ 6 | export function setupStore(app: App) { 7 | const store = createPinia(); 8 | 9 | store.use(resetSetupStore); 10 | 11 | app.use(store); 12 | } 13 | -------------------------------------------------------------------------------- /admin-ui/src/store/modules/auth/shared.ts: -------------------------------------------------------------------------------- 1 | import { localStg } from '@/utils/storage'; 2 | 3 | /** Get token */ 4 | export function getToken() { 5 | return localStg.get('token') || ''; 6 | } 7 | 8 | /** Get user info */ 9 | export function getUserInfo() { 10 | const emptyInfo: Api.Auth.UserInfo = { 11 | userId: '', 12 | account: '', 13 | roles: [], 14 | buttons: [] 15 | }; 16 | const userInfo = localStg.get('userInfo') || emptyInfo; 17 | 18 | // fix new property: buttons, this will be removed in the next version `1.1.0` 19 | if (!userInfo.buttons) { 20 | userInfo.buttons = []; 21 | } 22 | 23 | return userInfo; 24 | } 25 | 26 | /** Clear auth storage */ 27 | export function clearAuthStorage() { 28 | localStg.remove('token'); 29 | localStg.remove('refreshToken'); 30 | localStg.remove('userInfo'); 31 | } 32 | -------------------------------------------------------------------------------- /admin-ui/src/store/plugins/index.ts: -------------------------------------------------------------------------------- 1 | import type { PiniaPluginContext } from 'pinia'; 2 | import { cloneDeep } from 'lodash-es'; 3 | import { SetupStoreId } from '@/enum'; 4 | 5 | /** 6 | * The plugin reset the state of the store which is written by setup syntax 7 | * 8 | * @param context 9 | */ 10 | export function resetSetupStore(context: PiniaPluginContext) { 11 | const setupSyntaxIds = Object.values(SetupStoreId) as string[]; 12 | 13 | if (setupSyntaxIds.includes(context.store.$id)) { 14 | const { $state } = context.store; 15 | 16 | const defaultStore = cloneDeep($state); 17 | 18 | context.store.$reset = () => { 19 | context.store.$patch(defaultStore); 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /admin-ui/src/styles/css/global.css: -------------------------------------------------------------------------------- 1 | @import './reset.css'; 2 | @import './nprogress.css'; 3 | @import './transition.css'; 4 | 5 | html, 6 | body, 7 | #app { 8 | height: 100%; 9 | } 10 | 11 | html { 12 | overflow-x: hidden; 13 | } 14 | -------------------------------------------------------------------------------- /admin-ui/src/styles/scss/global.scss: -------------------------------------------------------------------------------- 1 | @import './scrollbar.scss'; 2 | -------------------------------------------------------------------------------- /admin-ui/src/styles/scss/scrollbar.scss: -------------------------------------------------------------------------------- 1 | @mixin scrollbar($size: 7px, $color: rgba(0, 0, 0, 0.5)) { 2 | scrollbar-width: thin; 3 | scrollbar-color: $color transparent; 4 | 5 | &::-webkit-scrollbar-thumb { 6 | background-color: $color; 7 | border-radius: $size; 8 | } 9 | &::-webkit-scrollbar-thumb:hover { 10 | background-color: $color; 11 | border-radius: $size; 12 | } 13 | &::-webkit-scrollbar { 14 | width: $size; 15 | height: $size; 16 | } 17 | &::-webkit-scrollbar-track-piece { 18 | background-color: rgba(0, 0, 0, 0); 19 | border-radius: 0; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /admin-ui/src/theme/settings.ts: -------------------------------------------------------------------------------- 1 | /** Default theme settings */ 2 | export const themeSettings: App.Theme.ThemeSetting = { 3 | themeScheme: 'light', 4 | themeColor: '#646cff', 5 | otherColor: { 6 | info: '#2080f0', 7 | success: '#52c41a', 8 | warning: '#faad14', 9 | error: '#f5222d' 10 | }, 11 | isInfoFollowPrimary: true, 12 | layout: { 13 | mode: 'vertical', 14 | scrollMode: 'content' 15 | }, 16 | page: { 17 | animate: true, 18 | animateMode: 'fade-slide' 19 | }, 20 | header: { 21 | height: 56, 22 | breadcrumb: { 23 | visible: true, 24 | showIcon: true 25 | } 26 | }, 27 | tab: { 28 | visible: true, 29 | cache: true, 30 | height: 44, 31 | mode: 'chrome' 32 | }, 33 | fixedHeaderAndTab: true, 34 | sider: { 35 | inverted: false, 36 | width: 220, 37 | collapsedWidth: 64, 38 | mixWidth: 90, 39 | mixCollapsedWidth: 64, 40 | mixChildMenuWidth: 200 41 | }, 42 | footer: { 43 | visible: true, 44 | fixed: false, 45 | height: 48, 46 | right: true 47 | } 48 | }; 49 | 50 | /** 51 | * Override theme settings 52 | * 53 | * If publish new version, use `overrideThemeSettings` to override certain theme settings 54 | */ 55 | export const overrideThemeSettings: Partial = {}; 56 | -------------------------------------------------------------------------------- /admin-ui/src/theme/vars.ts: -------------------------------------------------------------------------------- 1 | /** Create color palette vars */ 2 | function createColorPaletteVars() { 3 | const colors: App.Theme.ThemeColorKey[] = ['primary', 'info', 'success', 'warning', 'error']; 4 | const colorPaletteNumbers: App.Theme.ColorPaletteNumber[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]; 5 | 6 | const colorPaletteVar = {} as App.Theme.ThemePaletteColor; 7 | 8 | colors.forEach(color => { 9 | colorPaletteVar[color] = `rgb(var(--${color}-color))`; 10 | colorPaletteNumbers.forEach(number => { 11 | colorPaletteVar[`${color}-${number}`] = `rgb(var(--${color}-${number}-color))`; 12 | }); 13 | }); 14 | 15 | return colorPaletteVar; 16 | } 17 | 18 | const colorPaletteVars = createColorPaletteVars(); 19 | 20 | /** Theme vars */ 21 | export const themeVars: App.Theme.ThemeToken = { 22 | colors: { 23 | ...colorPaletteVars, 24 | nprogress: 'rgb(var(--nprogress-color))', 25 | container: 'rgb(var(--container-bg-color))', 26 | layout: 'rgb(var(--layout-bg-color))', 27 | inverted: 'rgb(var(--inverted-bg-color))', 28 | base_text: 'rgb(var(--base-text-color))' 29 | }, 30 | boxShadow: { 31 | header: 'var(--header-box-shadow)', 32 | sider: 'var(--sider-box-shadow)', 33 | tab: 'var(--tab-box-shadow)' 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /admin-ui/src/typings/common.d.ts: -------------------------------------------------------------------------------- 1 | /** The common type namespace */ 2 | declare namespace CommonType { 3 | /** The strategic pattern */ 4 | interface StrategicPattern { 5 | /** The condition */ 6 | condition: boolean; 7 | /** If the condition is true, then call the action function */ 8 | callback: () => void; 9 | } 10 | 11 | /** 12 | * The option type 13 | * 14 | * @property value: The option value 15 | * @property label: The option label 16 | */ 17 | type Option = { value: K; label: string }; 18 | 19 | type YesOrNo = 'Y' | 'N'; 20 | 21 | /** add null to all properties */ 22 | type RecordNullable = { 23 | [K in keyof T]?: T[K] | null; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /admin-ui/src/typings/global.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | /** NProgress instance */ 3 | NProgress?: import('nprogress').NProgress; 4 | /** Loading bar instance */ 5 | $loadingBar?: import('naive-ui').LoadingBarProviderInst; 6 | /** Dialog instance */ 7 | $dialog?: import('naive-ui').DialogProviderInst; 8 | /** Message instance */ 9 | $message?: import('naive-ui').MessageProviderInst; 10 | /** Notification instance */ 11 | $notification?: import('naive-ui').NotificationProviderInst; 12 | } 13 | 14 | interface ViewTransition { 15 | ready: Promise; 16 | } 17 | 18 | interface Document { 19 | startViewTransition?: (callback: () => Promise | void) => ViewTransition; 20 | } 21 | 22 | interface ImportMeta { 23 | readonly env: Env.ImportMeta; 24 | } 25 | 26 | /** Build time of the project */ 27 | declare const BUILD_TIME: string; 28 | -------------------------------------------------------------------------------- /admin-ui/src/typings/storage.d.ts: -------------------------------------------------------------------------------- 1 | /** The storage namespace */ 2 | declare namespace StorageType { 3 | interface Session { 4 | /** The theme color */ 5 | themeColor: string; 6 | // /** 7 | // * the theme settings 8 | // */ 9 | // themeSettings: App.Theme.ThemeSetting; 10 | } 11 | 12 | interface Local { 13 | /** The i18n language */ 14 | lang: App.I18n.LangType; 15 | /** The token */ 16 | token: string; 17 | /** Fixed sider with mix-menu */ 18 | mixSiderFixed: CommonType.YesOrNo; 19 | /** The refresh token */ 20 | refreshToken: string; 21 | /** The user info */ 22 | userInfo: Api.Auth.UserInfo; 23 | /** The theme color */ 24 | themeColor: string; 25 | /** The theme settings */ 26 | themeSettings: App.Theme.ThemeSetting; 27 | /** 28 | * The override theme flags 29 | * 30 | * The value is the build time of the project 31 | */ 32 | overrideThemeFlag: string; 33 | /** The global tabs */ 34 | globalTabs: App.Global.Tab[]; 35 | /** The backup theme setting before is mobile */ 36 | backupThemeSettingBeforeIsMobile: { 37 | layout: UnionKey.ThemeLayoutMode; 38 | siderCollapse: boolean; 39 | }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /admin-ui/src/utils/common.ts: -------------------------------------------------------------------------------- 1 | import { $t } from '@/locales'; 2 | 3 | /** 4 | * Transform record to option 5 | * 6 | * @example 7 | * ```ts 8 | * const record = { 9 | * key1: 'label1', 10 | * key2: 'label2' 11 | * }; 12 | * const options = transformRecordToOption(record); 13 | * // [ 14 | * // { value: 'key1', label: 'label1' }, 15 | * // { value: 'key2', label: 'label2' } 16 | * // ] 17 | * ```; 18 | * 19 | * @param record 20 | */ 21 | export function transformRecordToOption>(record: T) { 22 | return Object.entries(record).map(([value, label]) => ({ 23 | value, 24 | label 25 | })) as CommonType.Option[]; 26 | } 27 | 28 | /** 29 | * Translate options 30 | * 31 | * @param options 32 | */ 33 | export function translateOptions(options: CommonType.Option[]) { 34 | return options.map(option => ({ 35 | ...option, 36 | label: $t(option.label as App.I18n.I18nKey) 37 | })); 38 | } 39 | -------------------------------------------------------------------------------- /admin-ui/src/utils/crypto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 490912587@qq.com 3 | * @Date: 2024-01-05 15:31:29 4 | * @LastEditors: 490912587@qq.com 5 | * @LastEditTime: 2024-05-06 15:29:25 6 | * @FilePath: \admin-ui\src\utils\crypto.ts 7 | * @Description: 8 | */ 9 | import CryptoJS from 'crypto-js'; 10 | 11 | const CryptoSecret = '__CryptoJS_Secret__'; 12 | //加密公钥 13 | export const publicKey = `0484C7466D950E120E5ECE5DD85D0C90EAA85081A3A2BD7C57AE6DC822EFCCBD66620C67B0103FC8DD280E36C3B282977B722AAEC3C56518EDCEBAFB72C5A05312`; 14 | /** 15 | * 加密数据 16 | * @param data - 数据 17 | */ 18 | export function encrypt(data: any) { 19 | const newData = JSON.stringify(data); 20 | return CryptoJS.AES.encrypt(newData, CryptoSecret).toString(); 21 | } 22 | 23 | /** 24 | * 解密数据 25 | * @param cipherText - 密文 26 | */ 27 | export function decrypt(cipherText: string) { 28 | const bytes = CryptoJS.AES.decrypt(cipherText, CryptoSecret); 29 | const originalText = bytes.toString(CryptoJS.enc.Utf8); 30 | if (originalText) { 31 | return JSON.parse(originalText); 32 | } 33 | return null; 34 | } 35 | -------------------------------------------------------------------------------- /admin-ui/src/utils/icon.ts: -------------------------------------------------------------------------------- 1 | export function getLocalIcons() { 2 | const svgIcons = import.meta.glob('/src/assets/svg-icon/*.svg'); 3 | 4 | const keys = Object.keys(svgIcons) 5 | .map(item => item.split('/').at(-1)?.replace('.svg', '') || '') 6 | .filter(Boolean); 7 | 8 | return keys; 9 | } 10 | -------------------------------------------------------------------------------- /admin-ui/src/utils/storage.ts: -------------------------------------------------------------------------------- 1 | import { createLocalforage, createStorage } from '@sa/utils'; 2 | 3 | export const localStg = createStorage('local'); 4 | 5 | export const sessionStg = createStorage('session'); 6 | 7 | export const localforage = createLocalforage('local'); 8 | -------------------------------------------------------------------------------- /admin-ui/src/views/_builtin/403/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/src/views/_builtin/404/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/src/views/_builtin/500/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/src/views/_builtin/iframe-page/[url].vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /admin-ui/src/views/_builtin/login/modules/bind-wechat.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /admin-ui/src/views/function/hide-child/one/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/src/views/function/hide-child/three/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/src/views/function/hide-child/two/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/src/views/function/multi-tab/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /admin-ui/src/views/function/request/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /admin-ui/src/views/function/super-page/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/src/views/home/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /admin-ui/src/views/home/modules/creativity-banner.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /admin-ui/src/views/home/modules/project-news.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /admin-ui/src/views/multi-menu/first_child/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/src/views/multi-menu/second_child_home/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/src/views/user-center/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "jsxImportSource": "vue", 6 | "lib": ["DOM", "ESNext"], 7 | "baseUrl": ".", 8 | "module": "ESNext", 9 | "moduleResolution": "node", 10 | "paths": { 11 | "@/*": ["./src/*"], 12 | "~/*": ["./*"] 13 | }, 14 | "resolveJsonModule": true, 15 | "types": ["vite/client", "node", "unplugin-icons/types/vue", "naive-ui/volar"], 16 | "strict": true, 17 | "strictNullChecks": true, 18 | "noUnusedLocals": false, 19 | "allowSyntheticDefaultImports": true, 20 | "esModuleInterop": true, 21 | "forceConsistentCasingInFileNames": true, 22 | "isolatedModules": true 23 | }, 24 | "include": ["./**/*.ts", "./**/*.tsx", "./**/*.vue"], 25 | "exclude": ["node_modules", "dist"] 26 | } 27 | -------------------------------------------------------------------------------- /admin-ui/uno.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@unocss/vite'; 2 | import transformerDirectives from '@unocss/transformer-directives'; 3 | import transformerVariantGroup from '@unocss/transformer-variant-group'; 4 | import presetUno from '@unocss/preset-uno'; 5 | import type { Theme } from '@unocss/preset-uno'; 6 | import { presetSoybeanAdmin } from '@sa/uno-preset'; 7 | import { themeVars } from './src/theme/vars'; 8 | 9 | export default defineConfig({ 10 | content: { 11 | pipeline: { 12 | exclude: ['node_modules', 'dist'] 13 | } 14 | }, 15 | theme: { 16 | ...themeVars, 17 | fontSize: { 18 | 'icon-xs': '0.875rem', 19 | 'icon-small': '1rem', 20 | icon: '1.125rem', 21 | 'icon-large': '1.5rem', 22 | 'icon-xl': '2rem' 23 | } 24 | }, 25 | shortcuts: { 26 | 'card-wrapper': 'rd-8px shadow-sm' 27 | }, 28 | transformers: [transformerDirectives(), transformerVariantGroup()], 29 | presets: [presetUno({ dark: 'class' }), presetSoybeanAdmin()] 30 | }); 31 | -------------------------------------------------------------------------------- /admin-ui/vite.config.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import { URL, fileURLToPath } from 'node:url'; 3 | import { defineConfig, loadEnv } from 'vite'; 4 | import dayjs from 'dayjs'; 5 | import { setupVitePlugins } from './build/plugins'; 6 | import { createViteProxy } from './build/config'; 7 | 8 | export default defineConfig(configEnv => { 9 | const viteEnv = loadEnv(configEnv.mode, process.cwd()) as unknown as Env.ImportMeta; 10 | 11 | const buildTime = dayjs().format('YYYY-MM-DD HH:mm:ss'); 12 | 13 | return { 14 | base: viteEnv.VITE_BASE_URL, 15 | resolve: { 16 | alias: { 17 | '~': fileURLToPath(new URL('./', import.meta.url)), 18 | '@': fileURLToPath(new URL('./src', import.meta.url)) 19 | } 20 | }, 21 | css: { 22 | preprocessorOptions: { 23 | scss: { 24 | additionalData: `@use "./src/styles/scss/global.scss" as *;` 25 | } 26 | } 27 | }, 28 | plugins: setupVitePlugins(viteEnv), 29 | define: { 30 | BUILD_TIME: JSON.stringify(buildTime) 31 | }, 32 | server: { 33 | host: '0.0.0.0', 34 | port: 9527, 35 | open: true, 36 | proxy: createViteProxy(viteEnv, configEnv.command === 'serve'), 37 | fs: { 38 | cachedChecks: false 39 | } 40 | }, 41 | preview: { 42 | port: 9725 43 | }, 44 | build: { 45 | reportCompressedSize: false, 46 | sourcemap: viteEnv.VITE_SOURCE_MAP === 'Y', 47 | commonjsOptions: { 48 | ignoreTryCatch: false 49 | } 50 | } 51 | }; 52 | }); 53 | -------------------------------------------------------------------------------- /doc/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/doc/1.png -------------------------------------------------------------------------------- /doc/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/doc/3.png -------------------------------------------------------------------------------- /doc/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/doc/4.png -------------------------------------------------------------------------------- /doc/555.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/doc/555.png -------------------------------------------------------------------------------- /doc/qun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/doc/qun.png -------------------------------------------------------------------------------- /doc/zanshang.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/doc/zanshang.jpg -------------------------------------------------------------------------------- /services/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.dockerignore 2 | **/.env 3 | **/.git 4 | **/.gitignore 5 | **/.project 6 | **/.settings 7 | **/.toolstarget 8 | **/.vs 9 | **/.vscode 10 | **/.idea 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /services/.idea/.idea.SuperApi/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /modules.xml 6 | /projectSettingsUpdater.xml 7 | /contentModel.xml 8 | /.idea.SuperApi.iml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /services/.idea/.idea.SuperApi/.idea/.name: -------------------------------------------------------------------------------- 1 | SuperApi -------------------------------------------------------------------------------- /services/.idea/.idea.SuperApi/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /services/.idea/.idea.SuperApi/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /services/SuperApi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperApi", "SuperApi\SuperApi.csproj", "{E18CFF40-BAA5-4EEA-B94D-A60699022C24}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {E18CFF40-BAA5-4EEA-B94D-A60699022C24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {E18CFF40-BAA5-4EEA-B94D-A60699022C24}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {E18CFF40-BAA5-4EEA-B94D-A60699022C24}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {E18CFF40-BAA5-4EEA-B94D-A60699022C24}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /services/SuperApi/Cache/CacheProvider.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Caching; 2 | using SuperApi.Config; 3 | namespace SuperApi.Cache; 4 | 5 | /// 6 | /// 缓存服务提供者 7 | /// 8 | public static class CacheProvider 9 | { 10 | public static ICache? Instance { get; set; } 11 | 12 | /// 13 | /// 缓存注册(新生命Redis组件) 14 | /// 15 | /// 16 | public static void AddCache(this IServiceCollection services) 17 | { 18 | ICache cache = NewLife.Caching.Cache.Default; 19 | var prefix = ConfigProvider.Config["Cache:Prefix"]!; 20 | var configuration = ConfigProvider.Config["Cache:Redis:Configuration"]!; 21 | var cacheType = ConfigProvider.Config["Cache:CacheType"]!; 22 | if (cacheType == "Redis") 23 | { 24 | cache = new FullRedis(new RedisOptions 25 | { 26 | Configuration = configuration, 27 | Prefix = prefix 28 | }); 29 | if (Convert.ToInt32(ConfigProvider.Config["Cache:Redis:MaxMessageSize"]) > 0) 30 | ((FullRedis)cache).MaxMessageSize = 31 | Convert.ToInt32(ConfigProvider.Config["Cache:Redis:MaxMessageSize"]); 32 | } 33 | 34 | Instance = cache; 35 | services.AddSingleton(cache); 36 | } 37 | } -------------------------------------------------------------------------------- /services/SuperApi/Config/ConfigProvider.cs: -------------------------------------------------------------------------------- 1 | namespace SuperApi.Config; 2 | 3 | public static class ConfigProvider 4 | { 5 | /// 6 | /// 配置 7 | /// 8 | public static IConfiguration Config=new ConfigurationManager(); 9 | /// 10 | /// 上下文关联 11 | /// 12 | /// 13 | public static void Initialize(IConfiguration configuration) 14 | { 15 | Config = configuration; 16 | } 17 | } -------------------------------------------------------------------------------- /services/SuperApi/Configuration/Cache.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "", 3 | 4 | "Cache": { 5 | "Prefix": "timServe_", // 全局缓存前缀 6 | "CacheType": "Memory", // Memory、Redis 7 | "Redis": { 8 | "Configuration": "server=127.0.0.1:6379;ssl=false;password=;db=0;", // Redis连接字符串 9 | "MaxMessageSize": "1048576" // 最大消息大小 默认1024 * 1024 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /services/SuperApi/Configuration/Database.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "", 3 | "DbConnection": { 4 | "ConfigId":"Master", 5 | // "DbType": "MySql", // MySql、SqlServer、Sqlite、Oracle、PostgreSQL、Dm、Kdbndp、Oscar、MySqlConnector、Access、OpenGauss、QuestDB、HG、ClickHouse、GBase、Odbc、Custom 6 | // "ConnectionString": "server=127.0.0.1;Database=super_api;Uid=root;Pwd=123456" 7 | "DbType": "Sqlite", 8 | "ConnectionString": "DataSource=./SuperApi.db" 9 | } 10 | } -------------------------------------------------------------------------------- /services/SuperApi/Configuration/JWT.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "", 3 | 4 | "JWTSettings": { 5 | "ExpiredTime": 600,//jwt accessToken过期时间,单位(秒) 默认为10分钟 6 | "RefreshExpiredTime":86400, //jwt refreshToken过期时间,单位(秒)默认为24小时 7 | "ValidateIssuerSigningKey": true, // 是否验证密钥,bool 类型,默认true 8 | "IssuerSigningKey": "3c1cbc3f546eda35168c3aa3cb91780fbe703f0996c6d123ea96dc85c70bbc0a", // 密钥,string 类型,必须是复杂密钥,长度大于16 9 | "ValidIssuer": "Unify", // 签发方,string 类型 10 | "ValidAudience": "Unify", // 签收方,string 类型 11 | "ClockSkew": 0, // 过期时间容错值,long 类型,单位秒,默认5秒 12 | "Algorithm": "HS256" // 加密算法,string 类型,默认 HS256 13 | } 14 | } -------------------------------------------------------------------------------- /services/SuperApi/Configuration/Logging.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "", 3 | 4 | "Logging": { 5 | "LogLevel": { 6 | "Default": "Information", 7 | "Microsoft": "Information", 8 | "Microsoft.Hosting.Lifetime": "Information", 9 | "Microsoft.AspNetCore": "Information" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /services/SuperApi/Configuration/Upload.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "", 3 | "Upload": { 4 | "Path": "Upload/{yyyy}/{MM}/{dd}", 5 | // 文件上传目录 6 | "MaxSize": 20480, 7 | // 文件最大限制KB:1024*20 8 | "EnableMd5": true 9 | // 启用文件MDF5验证-防止重复上传 10 | }, 11 | "OSSProvider": { 12 | "IsEnable": false, 13 | "Provider": "Aliyun", 14 | // OSS提供者 Invalid/Minio/Aliyun/QCloud/Qiniu/HuaweiCloud 15 | "Endpoint": "", 16 | // 节点 在腾讯云OSS中表示AppId 17 | "Region": "", 18 | // 地域 19 | "AccessKey": "", 20 | "SecretKey": "", 21 | "IsEnableHttps": true, 22 | // 是否启用HTTPS 23 | "IsEnableCache": true, 24 | // 是否启用缓存 25 | "Bucket": "" 26 | } 27 | } -------------------------------------------------------------------------------- /services/SuperApi/Configuration/Wechat.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "", 3 | 4 | "Wechat": { 5 | // 公众号 6 | "WechatAppId": "", 7 | "WechatAppSecret": "", 8 | // 小程序 9 | "WxOpenAppId": "", 10 | "WxOpenAppSecret": "" 11 | }, 12 | // 微信支付 13 | "WechatPay": { 14 | "AppId": "", // 微信公众平台AppId、开放平台AppId、小程序AppId、企业微信CorpId 15 | "MerchantId": "", // 商户平台的商户号 16 | "MerchantV3Secret": "", // 商户平台的APIv3密钥 17 | "MerchantCertificateSerialNumber": "", // 商户平台的证书序列号 18 | "MerchantCertificatePrivateKey": "\\WxPayCert\\apiclient_key.pem" // 商户平台的API证书私钥(apiclient_key.pem文件内容) 19 | }, 20 | // 支付回调 21 | "PayCallBack": { 22 | "WechatPayUrl": "https://xxx/api/sysWechatPay/payCallBack", // 微信支付回调 23 | "WechatRefundUrl": "", // 微信退款回调 24 | "AlipayUrl": "", // 支付宝支付回调 25 | "AlipayRefundUrl": "" // 支付宝退款回调 26 | } 27 | } -------------------------------------------------------------------------------- /services/SuperApi/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 2 | WORKDIR /app 3 | EXPOSE 80 4 | EXPOSE 443 5 | 6 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 7 | WORKDIR /src 8 | COPY ["SuperApi/SuperApi.csproj", "SuperApi/"] 9 | RUN dotnet restore "SuperApi/SuperApi.csproj" 10 | COPY . . 11 | WORKDIR "/src/SuperApi" 12 | RUN dotnet build "SuperApi.csproj" -c Release -o /app/build 13 | 14 | FROM build AS publish 15 | RUN dotnet publish "SuperApi.csproj" -c Release -o /app/publish /p:UseAppHost=false 16 | 17 | FROM base AS final 18 | WORKDIR /app 19 | COPY --from=publish /app/publish . 20 | ENTRYPOINT ["dotnet", "SuperApi.dll"] 21 | -------------------------------------------------------------------------------- /services/SuperApi/Dto/Auth/LoginInput.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace SuperApi.Dto.Auth; 5 | 6 | /// 7 | /// 用户登录参数 8 | /// 9 | public class LoginInput 10 | { 11 | /// 12 | /// 账号 13 | /// 14 | /// admin 15 | [Required(ErrorMessage = "账号不能为空"), MinLength(2, ErrorMessage = "账号不能少于2个字符")] 16 | public string Account { get; set; }= ""; 17 | 18 | /// 19 | /// 加密密码 20 | /// 21 | /// 123456 22 | [Required(ErrorMessage = "密码不能为空"), MinLength(16, ErrorMessage = "密码不能少于16个字符")] 23 | public string Password { get; set; } = ""; 24 | 25 | /// 26 | /// 验证码Id 27 | /// 28 | public long CodeId { get; set; } 29 | 30 | /// 31 | /// 验证码 32 | /// 33 | public string Code { get; set; }= ""; 34 | } -------------------------------------------------------------------------------- /services/SuperApi/Dto/Auth/LoginOutput.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace SuperApi.Dto.Auth; 3 | 4 | /// 5 | /// 用户登录结果 6 | /// 7 | public class LoginOutput 8 | { 9 | /// 10 | /// 令牌Token 11 | /// 12 | public string AccessToken { get; set; }= ""; 13 | 14 | /// 15 | /// 刷新Token 16 | /// 17 | public string RefreshToken { get; set; }= ""; 18 | } -------------------------------------------------------------------------------- /services/SuperApi/Dto/Auth/UserInfoOutPut.cs: -------------------------------------------------------------------------------- 1 | namespace SuperApi.Dto.Auth; 2 | /// 3 | /// 用户登录返回用户信息结果 4 | /// 5 | public class UserInfoOutPut 6 | { 7 | /// 8 | /// 登录用户ID 9 | /// 10 | public long UserId { get; set; } = 0; 11 | 12 | /// 13 | /// 登录账号 14 | /// 15 | public string Account { get; set; } = ""; 16 | 17 | /// 18 | /// 授权角色列表 19 | /// 20 | public List Roles { get; set; } = new List(); 21 | 22 | /// 23 | /// 授权按钮标识列表 24 | /// 25 | public List Buttons { get; set; } = new List(); 26 | } -------------------------------------------------------------------------------- /services/SuperApi/Dto/DyDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace SuperApi.Dto; 4 | 5 | /// 6 | /// 动态模块Dto 7 | /// 8 | public class DyDto 9 | { 10 | /// 11 | /// 表ID 12 | /// 13 | [Required(ErrorMessage = "TableId不能为空")] 14 | public long TableId { get; set; } = 0; 15 | 16 | /// 17 | /// 参数 18 | /// 19 | [Required(ErrorMessage = "参数不能为空")] 20 | public Dictionary Param { get; set; } = new Dictionary(); 21 | 22 | /// 23 | /// 页码 24 | /// 25 | public int PageNum { get; set; } 26 | 27 | /// 28 | /// 每页数量 29 | /// 30 | public int PageSize { get; set; } 31 | } -------------------------------------------------------------------------------- /services/SuperApi/Dto/Enum/EnumEntity.cs: -------------------------------------------------------------------------------- 1 | namespace SuperApi.Dto; 2 | 3 | /// 4 | /// 枚举实体 5 | /// 6 | public class EnumEntity 7 | { 8 | /// 9 | /// 枚举的描述 10 | /// 11 | public string Describe { set; get; } = ""; 12 | 13 | /// 14 | /// 枚举名称 15 | /// 16 | public string Name { set; get; } = ""; 17 | 18 | /// 19 | /// 枚举对象的值 20 | /// 21 | public int Value { set; get; } 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Dto/Enum/EnumInput.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace SuperApi.Dto; 4 | /// 5 | /// 枚举输入参数 6 | /// 7 | public class EnumInput 8 | { 9 | /// 10 | /// 枚举类型名称 11 | /// 12 | /// AccountTypeEnum 13 | [Required(ErrorMessage = "枚举类型不能为空")] 14 | public string EnumName { get; set; }= ""; 15 | } 16 | 17 | public class QueryEnumDataInput 18 | { 19 | /// 20 | /// 实体名称 21 | /// 22 | /// SysUser 23 | [Required(ErrorMessage = "实体名称不能为空")] 24 | public string EntityName { get; set; }= ""; 25 | 26 | /// 27 | /// 字段名称 28 | /// 29 | /// AccountType 30 | [Required(ErrorMessage = "字段名称不能为空")] 31 | public string FieldName { get; set; }= ""; 32 | } -------------------------------------------------------------------------------- /services/SuperApi/Dto/Enum/EnumOutput.cs: -------------------------------------------------------------------------------- 1 | namespace SuperApi.Dto; 2 | 3 | /// 4 | /// 枚举类型输出参数 5 | /// 6 | public class EnumTypeOutput 7 | { 8 | /// 9 | /// 枚举类型描述 10 | /// 11 | public string TypeDescribe { get; set; }= ""; 12 | 13 | /// 14 | /// 枚举类型名称 15 | /// 16 | public string TypeName { get; set; }= ""; 17 | 18 | /// 19 | /// 枚举类型备注 20 | /// 21 | public string TypeRemark { get; set; }= ""; 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Dto/FileInput.cs: -------------------------------------------------------------------------------- 1 | namespace SuperApi.Dto; 2 | 3 | /// 4 | /// 文件输入 5 | /// 6 | public class FileInput 7 | { 8 | /// 9 | /// 文件名称 10 | /// 11 | public string FileName { get; set; } 12 | 13 | /// 14 | /// 文件Url 15 | /// 16 | public string? Url { get; set; } 17 | } -------------------------------------------------------------------------------- /services/SuperApi/Dto/Page.cs: -------------------------------------------------------------------------------- 1 | namespace SuperApi.Dto; 2 | 3 | /// 4 | /// 统一分页返回数据格式 5 | /// 6 | public class Page 7 | { 8 | /// 9 | /// 分页数据列表 10 | /// 11 | public object? List { get; set; } 12 | 13 | /// 14 | /// 总页数 15 | /// 16 | public int TotalPage { get; set; } 17 | 18 | /// 19 | /// 当前页 20 | /// 21 | public int CurrentPage { get; set; } 22 | 23 | /// 24 | /// 每页数量 25 | /// 26 | public int PageSize { get; set; } 27 | } -------------------------------------------------------------------------------- /services/SuperApi/Dto/Route/RouteMenuOutput.cs: -------------------------------------------------------------------------------- 1 | namespace SuperApi.Dto.Route; 2 | /// 3 | /// 前端路由输出 4 | /// 5 | public class RouteMenuOutput 6 | { 7 | /// 8 | /// 主路由名称 9 | /// 10 | /// home 11 | public string Home { get; set; }= "home"; 12 | /// 13 | /// 14 | /// 15 | public List Routes { get; set; }= new List(); 16 | } -------------------------------------------------------------------------------- /services/SuperApi/Dto/UniResult.cs: -------------------------------------------------------------------------------- 1 | namespace SuperApi.Dto; 2 | /// 3 | /// 全局返回结果 4 | /// 5 | public class UniResult 6 | { 7 | /// 8 | /// 状态码 9 | /// 10 | public int Code { get; set; } 11 | 12 | /// 13 | /// 类型success、warning、error 14 | /// 15 | public string? Type { get; set; } 16 | 17 | /// 18 | /// 错误信息 19 | /// 20 | public string? Message { get; set; } 21 | 22 | /// 23 | /// 数据 24 | /// 25 | public object? Result { get; set; } 26 | 27 | /// 28 | /// 附加数据 29 | /// 30 | public object? Extras { get; set; } 31 | 32 | /// 33 | /// 时间 34 | /// 35 | public string? Time { get; set; } 36 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/AccountSourceEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | /// 6 | /// 账号来源枚举 7 | /// 8 | [Description("账号来源枚举")] 9 | public enum AccountSourceEnum 10 | { 11 | /// 12 | /// PC 13 | /// 14 | [Description("Pc")] Pc = 999, 15 | 16 | /// 17 | /// APP 18 | /// 19 | [Description("App")] App = 888, 20 | 21 | /// 22 | /// H5 23 | /// 24 | [Description("H5")] H5 = 777, 25 | 26 | /// 27 | /// 微信小程序 28 | /// 29 | [Description("微信小程序")] 微信小程序 = 666, 30 | 31 | /// 32 | /// 抖音小程序 33 | /// 34 | [Description("抖音小程序")] 抖音小程序 = 555, 35 | 36 | /// 37 | /// 其他小程序 38 | /// 39 | [Description("其他小程序")] 其他小程序 = 444, 40 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/AccountTypeEnum.cs: -------------------------------------------------------------------------------- 1 | 2 | using System.ComponentModel; 3 | 4 | namespace SuperApi.Enum; 5 | 6 | /// 7 | /// 账号类型枚举 8 | /// 9 | [Description("账号类型枚举")] 10 | public enum AccountTypeEnum 11 | { 12 | /// 13 | /// 超级管理员 14 | /// 15 | [Description("超级管理员")] 16 | 超级管理员 = 999, 17 | 18 | /// 19 | /// 系统管理员 20 | /// 21 | [Description("系统管理员")] 22 | 系统管理员 = 888, 23 | 24 | /// 25 | /// 普通账号 26 | /// 27 | [Description("普通账号")] 28 | 普通账号 = 777, 29 | 30 | /// 31 | /// 会员 32 | /// 33 | [Description("会员")] 34 | 会员 = 666, 35 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/AppPageEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | [Description("AppMenu显示位置")] 6 | public enum AppPageEnum 7 | { 8 | /// 9 | /// 首页 10 | /// 11 | [Description("首页")] 首页 = 0, 12 | /// 13 | /// 首页底部 14 | /// 15 | [Description("首页底部")] 首页底部 = 1, 16 | /// 17 | /// 用户中心页 18 | /// 19 | /// 20 | [Description("用户中心")] 用户中心 =2, 21 | /// 22 | /// AI乐园页 23 | /// 24 | /// 25 | [Description("AI乐园")] AI乐园 = 3, 26 | /// 27 | /// 板块分类页 28 | /// 29 | /// 30 | [Description("板块分类")] 板块分类 =4, 31 | /// 32 | /// 发布页 33 | /// 34 | /// 35 | [Description("发布")] 发布 =5, 36 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/ComputeModeEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | [Description("计算方式")] 5 | public enum ComputeModeEnum 6 | { 7 | /// 8 | /// 增加 9 | /// 10 | [Description("增加")] 增加=0, 11 | /// 12 | /// 扣除 13 | /// 14 | [Description("扣除")] 扣除=1, 15 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/CryptogramEnum.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.ComponentModel; 3 | 4 | namespace SuperApi.Enum; 5 | 6 | /// 7 | /// 密码加密枚举 8 | /// 9 | [Description("密码加密枚举")] 10 | public enum CryptogramEnum 11 | { 12 | /// 13 | /// MD5 14 | /// 15 | [Description("MD5")] 16 | MD5 = 0, 17 | 18 | /// 19 | /// SM2(国密) 20 | /// 21 | [Description("SM2")] 22 | SM2 = 1, 23 | 24 | /// 25 | /// SM4(国密) 26 | /// 27 | [Description("SM4")] 28 | SM4 = 2 29 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/DataScopeEnum.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.ComponentModel; 3 | 4 | namespace SuperApi.Enum; 5 | 6 | /// 7 | /// 角色数据范围枚举 8 | /// 9 | [Description("角色数据范围枚举")] 10 | public enum DataScopeEnum 11 | { 12 | /// 13 | /// 全部数据 14 | /// 15 | [Description("全部数据")] 16 | 全部数据 = 1, 17 | 18 | /// 19 | /// 本部门及以下数据 20 | /// 21 | [Description("本部门及以下数据")] 22 | 本部门及以下数据 = 2, 23 | 24 | /// 25 | /// 本部门数据 26 | /// 27 | [Description("本部门数据")] 28 | 本部门数据 = 3, 29 | 30 | /// 31 | /// 仅本人数据 32 | /// 33 | [Description("仅本人数据")] 34 | 仅本人数据 = 4, 35 | 36 | /// 37 | /// 自定义数据 38 | /// 39 | [Description("自定义数据")] 40 | 自定义数据 = 5 41 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/GenderEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | /// 6 | /// 性别枚举 7 | /// 8 | [Description("性别枚举")] 9 | public enum GenderEnum 10 | { 11 | /// 12 | /// 男 13 | /// 14 | [Description("男")] 男 = 1, 15 | 16 | /// 17 | /// 女 18 | /// 19 | [Description("女")] 女 = 2, 20 | 21 | /// 22 | /// 其他 23 | /// 24 | [Description("其他")] 其他 = 3 25 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/IntegralSourceEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | /// 6 | /// 积分来源枚举 7 | /// 8 | [Description("积分来源枚举")] 9 | public enum IntegralSourceEnum 10 | { 11 | /// 12 | /// 签到 13 | /// 14 | [Description("签到")] 签到 = 1, 15 | 16 | /// 17 | /// 消费 18 | /// 19 | [Description("消费")] 消费 = 3, 20 | 21 | /// 22 | /// 赠送 23 | /// 24 | [Description("赠送")] 赠送 = 4, 25 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/MenuTypeEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | /// 6 | /// 系统菜单类型枚举 7 | /// 8 | [Description("系统菜单类型枚举")] 9 | public enum MenuTypeEnum 10 | { 11 | /// 12 | /// 目录 13 | /// 14 | [Description("目录")] 15 | 目录 = 1, 16 | 17 | /// 18 | /// 菜单 19 | /// 20 | [Description("菜单")] 21 | 菜单 = 2, 22 | 23 | /// 24 | /// 按钮 25 | /// 26 | [Description("按钮")] 27 | 按钮 = 3 28 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/NoticeTypeEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | /// 6 | /// 通知公告状类型枚举 7 | /// 8 | [Description("通知公告状类型枚举")] 9 | public enum NoticeTypeEnum 10 | { 11 | /// 12 | /// 通知 13 | /// 14 | [Description("通知")] 15 | 通知 = 1, 16 | 17 | /// 18 | /// 公告 19 | /// 20 | [Description("公告")] 21 | 公告 = 2, 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/OpTypeEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | /// 6 | /// 操作日志类型枚举 7 | /// 8 | [Description("操作日志类型枚举")] 9 | public enum OpLogTypeEnum 10 | { 11 | /// 12 | /// 默认日志 13 | /// 14 | [Description("默认日志")] 默认日志 = 1, 15 | /// 16 | /// 登录日志 17 | /// 18 | [Description("登录日志")] 登录日志 = 2 19 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/OrderStateEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | /// 5 | /// 订单状态枚举 6 | /// 7 | [Description("订单状态枚举")] 8 | public enum OrderStateEnum 9 | { 10 | /// 11 | /// 待付款 12 | /// 13 | [Description("待付款")] 待付款 = 0, 14 | 15 | /// 16 | /// 已付款 17 | /// 18 | [Description("已付款")] 已付款 = 0, 19 | 20 | /// 21 | /// 已完成 22 | /// 23 | [Description("已完成")] 已完成 = 0, 24 | 25 | /// 26 | /// 已取消 27 | /// 28 | [Description("已取消")] 已取消 = 0, 29 | 30 | /// 31 | /// 退款申请 32 | /// 33 | [Description("退款申请")] 退款申请 = 0, 34 | 35 | /// 36 | /// 退款中 37 | /// 38 | [Description("退款中")] 退款中 = 0, 39 | 40 | /// 41 | /// 退款完成 42 | /// 43 | [Description("退款完成")] 退款完成 = 0, 44 | 45 | /// 46 | /// 待发货 47 | /// 48 | [Description("待发货")] 待发货 = 0, 49 | 50 | /// 51 | /// 运输中 52 | /// 53 | [Description("运输中")] 运输中 = 0, 54 | 55 | /// 56 | /// 已送达 57 | /// 58 | [Description("已送达")] 已送达 = 0, 59 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/OrderTypeEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | /// 5 | /// 订单类型枚举 6 | /// 7 | [Description("订单类型枚举")] 8 | public enum OrderTypeEnum 9 | { 10 | /// 11 | /// 充值订单 12 | /// 13 | [Description("充值订单")] 充值订单 = 0, 14 | 15 | /// 16 | /// 普通订单 17 | /// 18 | [Description("普通订单")] 普通订单 = 1, 19 | 20 | /// 21 | /// 服务订单 22 | /// 23 | [Description("服务订单")] 服务订单 = 2, 24 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/PlatformTypeEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | /// 6 | /// 平台类型枚举 7 | /// 8 | [Description("平台类型枚举")] 9 | public enum PlatformTypeEnum 10 | { 11 | /// 12 | /// 微信公众号 13 | /// 14 | [Description("微信公众号")] 15 | 微信公众号 = 1, 16 | 17 | /// 18 | /// 微信小程序 19 | /// 20 | [Description("微信小程序")] 21 | 微信小程序 = 2, 22 | 23 | /// 24 | /// QQ 25 | /// 26 | [Description("QQ")] 27 | QQ = 3, 28 | 29 | /// 30 | /// 支付宝 31 | /// 32 | [Description("支付宝")] 33 | 支付宝 = 4, 34 | 35 | /// 36 | /// Gitee 37 | /// 38 | [Description("Gitee")] 39 | Gitee = 5, 40 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/StatusEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | /// 6 | /// 通用状态枚举 7 | /// 8 | [Description("通用状态枚举")] 9 | public enum StatusEnum 10 | { 11 | /// 12 | /// 启用 13 | /// 14 | [Description("启用")] 启用 = 1, 15 | 16 | /// 17 | /// 停用 18 | /// 19 | [Description("停用")] 停用 = 2, 20 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/WalletSourceEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | /// 6 | /// 钱包余额来源枚举 7 | /// 8 | [Description("钱包余额来源枚举")] 9 | public enum WalletSourceEnum 10 | { 11 | /// 12 | /// 赞赏 13 | /// 14 | [Description("赞赏")] 赞赏 = 1, 15 | 16 | /// 17 | /// 积分兑换 18 | /// 19 | [Description("积分兑换")] 积分兑换 = 2, 20 | 21 | /// 22 | /// 充值 23 | /// 24 | [Description("充值")] 充值 = 3, 25 | 26 | /// 27 | /// 消费 28 | /// 29 | [Description("消费")] 消费 = 3, 30 | } -------------------------------------------------------------------------------- /services/SuperApi/Enum/YesNoEnum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SuperApi.Enum; 4 | 5 | /// 6 | /// 是否枚举 7 | /// 8 | [Description("是否枚举")] 9 | public enum YesNoEnum 10 | { 11 | /// 12 | /// 是 13 | /// 14 | [Description("是")] 15 | 是 = 1, 16 | 17 | /// 18 | /// 否 19 | /// 20 | [Description("否")] 21 | 否 = 2 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Filter/UniResultFilter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.Filters; 4 | using SuperApi.Dto; 5 | 6 | namespace SuperApi.Filter; 7 | 8 | /// 9 | /// 统一返回过滤器 10 | /// 11 | public class UniResultFilter : ActionFilterAttribute 12 | { 13 | /// 14 | /// 返回值执行时触发 15 | /// 16 | /// 17 | public override void OnResultExecuting(ResultExecutingContext context) 18 | { 19 | if (context.Result is ObjectResult objRst) 20 | { 21 | var result = new UniResult 22 | { 23 | Code = StatusCodes.Status200OK, 24 | Type = "success", 25 | Message = "操作成功!", 26 | Result = objRst.Value, 27 | Extras = null, 28 | Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") 29 | }; 30 | if (objRst.Value!.GetType().Equals(typeof(bool))&&!(bool)objRst.Value) 31 | { 32 | result = new UniResult 33 | { 34 | Code = StatusCodes.Status400BadRequest, 35 | Type = "fail", 36 | Message = "操作失败!", 37 | Result = objRst.Value, 38 | }; 39 | } 40 | context.Result = new ObjectResult(result); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /services/SuperApi/Job/TestJob.cs: -------------------------------------------------------------------------------- 1 | using Quartz; 2 | namespace SuperApi.Job; 3 | /// 4 | /// 测试任务 5 | /// 6 | public class TestJob : IJob 7 | { 8 | /// 9 | /// 任务执行 10 | /// 11 | /// 12 | public async Task Execute(IJobExecutionContext context) 13 | { 14 | await Console.Out.WriteLineAsync($"{DateTime.Now}:Hello!"); 15 | } 16 | } -------------------------------------------------------------------------------- /services/SuperApi/Model/Base.cs: -------------------------------------------------------------------------------- 1 | using SqlSugar; 2 | 3 | namespace SuperApi.Model; 4 | 5 | /// 6 | /// 框架实体基类 7 | /// 8 | public class Base 9 | { 10 | /// 11 | /// 主键Id 12 | /// 13 | [SugarColumn(ColumnName = "Id", ColumnDescription = "主键Id", IsPrimaryKey = true, IsIdentity = false)] 14 | public long Id { get; set; } = SnowFlakeSingle.Instance.NextId(); 15 | 16 | /// 17 | /// 创建时间 18 | /// 19 | [SugarColumn(ColumnDescription = "创建时间", IsOnlyIgnoreUpdate = true)] 20 | public DateTime? CreateTime { get; set; } 21 | 22 | /// 23 | /// 更新时间 24 | /// 25 | [SugarColumn(ColumnDescription = "更新时间", IsOnlyIgnoreInsert = true)] 26 | public DateTime? UpdateTime { get; set; } 27 | 28 | /// 29 | /// 创建者Id 30 | /// 31 | [SugarColumn(ColumnDescription = "创建者Id", IsOnlyIgnoreUpdate = true)] 32 | public long? CreateUserId { get; set; } 33 | 34 | /// 35 | /// 修改者Id 36 | /// 37 | [SugarColumn(ColumnDescription = "修改者Id", IsOnlyIgnoreInsert = true)] 38 | public long? UpdateUserId { get; set; } 39 | 40 | /// 41 | /// 软删除 42 | /// 43 | [SugarColumn(ColumnDescription = "软删除")] 44 | public bool IsDelete { get; set; } = false; 45 | } -------------------------------------------------------------------------------- /services/SuperApi/Model/DictType.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using SqlSugar; 3 | using SuperApi.Enum; 4 | 5 | namespace SuperApi.Model; 6 | /// 7 | /// 字典类型表 8 | /// 9 | [SugarTable(null, "字典类型表")] 10 | [SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)] 11 | [SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)] 12 | public class DictType:Base 13 | { 14 | /// 15 | /// 名称 16 | /// 17 | [SugarColumn(ColumnDescription = "名称", Length = 64)] 18 | [Required, MaxLength(64)] 19 | public string Name { get; set; } = ""; 20 | 21 | /// 22 | /// 编码 23 | /// 24 | [SugarColumn(ColumnDescription = "编码", Length = 64)] 25 | [Required, MaxLength(64)] 26 | public string Code { get; set; }= ""; 27 | 28 | /// 29 | /// 排序 30 | /// 31 | [SugarColumn(ColumnDescription = "排序")] 32 | public int OrderNo { get; set; } = 100; 33 | 34 | /// 35 | /// 备注 36 | /// 37 | [SugarColumn(ColumnDescription = "备注", Length = 256)] 38 | [MaxLength(256)] 39 | public string? Remark { get; set; } 40 | 41 | /// 42 | /// 状态 43 | /// 44 | [SugarColumn(ColumnDescription = "状态")] 45 | public StatusEnum Status { get; set; } = StatusEnum.启用; 46 | 47 | /// 48 | /// 字典值集合 49 | /// 50 | [Navigate(NavigateType.OneToMany, nameof(DictData.DictTypeId))] 51 | public List Children { get; set; } = new List(); 52 | } -------------------------------------------------------------------------------- /services/SuperApi/Model/Field.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using SqlSugar; 3 | 4 | namespace SuperApi.Model; 5 | 6 | /// 7 | /// 数据表的字段 8 | /// 9 | [SugarTable(null, "Table字段表")] 10 | [SugarIndex("index_{table}_N", nameof(FieldName), OrderByType.Asc)] 11 | [SugarIndex("index_{table}_C", nameof(FieldType), OrderByType.Asc)] 12 | public class Field : Base 13 | { 14 | /// 15 | /// 关联表ID 16 | /// 17 | [SugarColumn(ColumnDescription = "关联表ID")] 18 | public long TableId { get; set; } = 0; 19 | 20 | /// 21 | /// 字段名称 22 | /// 23 | [SugarColumn(ColumnDescription = "字段名称", Length = 32)] 24 | [Required, MaxLength(32)] 25 | public string FieldName { get; set; } = ""; 26 | /// 27 | /// 字段类型 28 | /// 29 | [SugarColumn(ColumnDescription = "字段类型", Length = 32)] 30 | [Required, MaxLength(32)] 31 | public string FieldType { get; set; } = ""; 32 | 33 | /// 34 | /// 字段注释 35 | /// 36 | [SugarColumn(ColumnDescription = "字段注释", Length = 32)] 37 | [Required, MaxLength(32)] 38 | public string FieldComment { get; set; } = ""; 39 | } -------------------------------------------------------------------------------- /services/SuperApi/Model/Job.cs: -------------------------------------------------------------------------------- 1 | namespace SuperApi.Model; 2 | 3 | public class Job 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /services/SuperApi/Model/Post.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using SqlSugar; 3 | using SuperApi.Enum; 4 | 5 | namespace SuperApi.Model; 6 | /// 7 | /// 岗位表 8 | /// 9 | [SugarTable(null, "岗位表")] 10 | [SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)] 11 | [SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)] 12 | public class Post: Base 13 | { 14 | /// 15 | /// 名称 16 | /// 17 | [SugarColumn(ColumnDescription = "名称", Length = 64)] 18 | [Required, MaxLength(64)] 19 | public string Name { get; set; } = ""; 20 | 21 | /// 22 | /// 编码 23 | /// 24 | [SugarColumn(ColumnDescription = "编码", Length = 64)] 25 | [MaxLength(64)] 26 | public string? Code { get; set; } 27 | 28 | /// 29 | /// 排序 30 | /// 31 | [SugarColumn(ColumnDescription = "排序")] 32 | public int OrderNo { get; set; } = 100; 33 | 34 | /// 35 | /// 备注 36 | /// 37 | [SugarColumn(ColumnDescription = "备注", Length = 128)] 38 | [MaxLength(128)] 39 | public string? Remark { get; set; } 40 | 41 | /// 42 | /// 状态 43 | /// 44 | [SugarColumn(ColumnDescription = "状态")] 45 | public StatusEnum Status { get; set; } = StatusEnum.启用; 46 | } -------------------------------------------------------------------------------- /services/SuperApi/Model/Role.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using SqlSugar; 3 | using SuperApi.Enum; 4 | 5 | namespace SuperApi.Model; 6 | /// 7 | /// 角色表 8 | /// 9 | [SugarTable(null, "角色表")] 10 | [SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)] 11 | [SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)] 12 | public class Role : Base 13 | { 14 | /// 15 | /// 名称 16 | /// 17 | [SugarColumn(ColumnDescription = "名称", Length = 64)] 18 | [Required, MaxLength(64)] 19 | public string Name { get; set; } = ""; 20 | 21 | /// 22 | /// 编码 23 | /// 24 | [SugarColumn(ColumnDescription = "编码", Length = 64)] 25 | [MaxLength(64)] 26 | public string? Code { get; set; } 27 | 28 | /// 29 | /// 排序 30 | /// 31 | [SugarColumn(ColumnDescription = "排序")] 32 | public int OrderNo { get; set; } = 100; 33 | 34 | /// 35 | /// 数据范围(1全部数据 2本部门及以下数据 3本部门数据 4仅本人数据 5自定义数据) 36 | /// 37 | [SugarColumn(ColumnDescription = "数据范围")] 38 | public DataScopeEnum DataScope { get; set; } = DataScopeEnum.仅本人数据; 39 | 40 | /// 41 | /// 备注 42 | /// 43 | [SugarColumn(ColumnDescription = "备注", Length = 128)] 44 | [MaxLength(128)] 45 | public string? Remark { get; set; } 46 | 47 | /// 48 | /// 状态 49 | /// 50 | [SugarColumn(ColumnDescription = "状态")] 51 | public StatusEnum Status { get; set; } = StatusEnum.启用; 52 | } -------------------------------------------------------------------------------- /services/SuperApi/Model/RoleMenu.cs: -------------------------------------------------------------------------------- 1 | using SqlSugar; 2 | namespace SuperApi.Model; 3 | 4 | /// 5 | /// 角色菜单表 6 | /// 7 | [SugarTable(null, "角色菜单表")] 8 | public class RoleMenu:Base 9 | { 10 | /// 11 | /// 角色Id 12 | /// 13 | [SugarColumn(ColumnDescription = "角色Id")] 14 | public long RoleId { get; set; } 15 | 16 | /// 17 | /// 菜单Id 18 | /// 19 | [SugarColumn(ColumnDescription = "菜单Id")] 20 | public long MenuId { get; set; } 21 | 22 | /// 23 | /// 菜单 24 | /// 25 | [Newtonsoft.Json.JsonIgnore] 26 | [System.Text.Json.Serialization.JsonIgnore] 27 | [Navigate(NavigateType.OneToOne, nameof(MenuId))] 28 | public Menu Menu { get; set; } = new Menu(); 29 | } -------------------------------------------------------------------------------- /services/SuperApi/Model/Table.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using SqlSugar; 3 | 4 | namespace SuperApi.Model; 5 | 6 | /// 7 | /// 数据表 8 | /// 9 | [SugarTable(null, "Table表")] 10 | [SugarIndex("index_{table}_N", nameof(TableName), OrderByType.Asc)] 11 | public class Table : Base 12 | { 13 | /// 14 | /// 表名 15 | /// 16 | [SugarColumn(ColumnDescription = "表名", Length = 32)] 17 | [Required, MaxLength(32)] 18 | public string TableName { get; set; } = ""; 19 | 20 | /// 21 | /// 表注释 22 | /// 23 | [SugarColumn(ColumnDescription = "表注释", Length = 32)] 24 | [Required, MaxLength(32)] 25 | public string TableComment { get; set; } = ""; 26 | } -------------------------------------------------------------------------------- /services/SuperApi/Model/UserRole.cs: -------------------------------------------------------------------------------- 1 | using SqlSugar; 2 | 3 | namespace SuperApi.Model; 4 | 5 | /// 6 | /// 用户角色映射表 7 | /// 8 | [SugarTable(null, "用户角色映射表")] 9 | public class UserRole : Base 10 | { 11 | /// 12 | /// 用户Id 13 | /// 14 | [SugarColumn(ColumnDescription = "用户Id")] 15 | public long UserId { get; set; } 16 | 17 | /// 18 | /// 用户 19 | /// 20 | [Newtonsoft.Json.JsonIgnore] 21 | [System.Text.Json.Serialization.JsonIgnore] 22 | [Navigate(NavigateType.OneToOne, nameof(UserId))] 23 | public User User { get; set; } = new User(); 24 | 25 | /// 26 | /// 角色Id 27 | /// 28 | [SugarColumn(ColumnDescription = "角色Id")] 29 | public long RoleId { get; set; } 30 | 31 | /// 32 | /// 角色 33 | /// 34 | [Navigate(NavigateType.OneToOne, nameof(RoleId))] 35 | public Role Role { get; set; } = new Role(); 36 | } -------------------------------------------------------------------------------- /services/SuperApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:32615", 8 | "sslPort": 44395 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "http://localhost:3000", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "https": { 23 | "commandName": "Project", 24 | "dotnetRunMessages": true, 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "applicationUrl": "https://localhost:3001;http://localhost:3000", 28 | "environmentVariables": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | } 31 | }, 32 | "IIS Express": { 33 | "commandName": "IISExpress", 34 | "launchBrowser": true, 35 | "launchUrl": "swagger", 36 | "environmentVariables": { 37 | "ASPNETCORE_ENVIRONMENT": "Development" 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /services/SuperApi/Service/ConfigService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Panda.DynamicWebApi; 3 | using Panda.DynamicWebApi.Attributes; 4 | using SuperApi.SqlSugar; 5 | 6 | namespace SuperApi.Service; 7 | /// 8 | /// 系统参数配置 9 | /// 10 | [ApiExplorerSettings(GroupName = "default")] 11 | [DynamicWebApi(Module = "default")] 12 | public class ConfigService: BaseService, IDynamicWebApi 13 | { 14 | /// 15 | /// 数据表管理服务初始化 16 | /// 17 | /// 18 | public ConfigService(Repository db) : base(db) 19 | { 20 | } 21 | } -------------------------------------------------------------------------------- /services/SuperApi/Service/DepartmentService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Panda.DynamicWebApi; 3 | using Panda.DynamicWebApi.Attributes; 4 | using SuperApi.Model; 5 | using SuperApi.SqlSugar; 6 | 7 | namespace SuperApi.Service; 8 | /// 9 | /// 部门管理 10 | /// 11 | [ApiExplorerSettings(GroupName = "default")] 12 | [DynamicWebApi(Module = "default")] 13 | public class DepartmentService: BaseService, IDynamicWebApi 14 | { 15 | /// 16 | /// 部门管理服务 17 | /// 18 | /// 19 | public DepartmentService(Repository db) : base(db) 20 | { 21 | } 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Service/DictDataService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Panda.DynamicWebApi; 3 | using Panda.DynamicWebApi.Attributes; 4 | using SuperApi.Model; 5 | using SuperApi.SqlSugar; 6 | 7 | namespace SuperApi.Service; 8 | /// 9 | /// 字典值管理服务管理 10 | /// 11 | [ApiExplorerSettings(GroupName = "default")] 12 | [DynamicWebApi(Module = "default")] 13 | public class DictDataService: BaseService, IDynamicWebApi 14 | { 15 | /// 16 | /// 字典值管理服务 17 | /// 18 | /// 19 | public DictDataService(Repository db) : base(db) 20 | { 21 | } 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Service/DictTypeService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Panda.DynamicWebApi; 3 | using Panda.DynamicWebApi.Attributes; 4 | using SuperApi.Model; 5 | using SuperApi.SqlSugar; 6 | 7 | namespace SuperApi.Service; 8 | /// 9 | /// 字典类型管理 10 | /// 11 | [ApiExplorerSettings(GroupName = "default")] 12 | [DynamicWebApi(Module = "default")] 13 | public class DictTypeService: BaseService, IDynamicWebApi 14 | { 15 | /// 16 | /// 字典类型管理服务 17 | /// 18 | /// 19 | public DictTypeService(Repository db) : base(db) 20 | { 21 | } 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Service/DiyNodeDataService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Panda.DynamicWebApi; 3 | using Panda.DynamicWebApi.Attributes; 4 | using SuperApi.Model; 5 | using SuperApi.SqlSugar; 6 | 7 | namespace SuperApi.Service; 8 | /// 9 | /// DIY节点数据管理 10 | /// 11 | [ApiExplorerSettings(GroupName = "default")] 12 | [DynamicWebApi(Module = "default")] 13 | public class DiyNodeDataService: BaseService, IDynamicWebApi 14 | { 15 | /// 16 | /// DIY节点数据管理服务 17 | /// 18 | /// 19 | public DiyNodeDataService(Repository
db) : base(db) 20 | { 21 | } 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Service/DiyNodeService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Panda.DynamicWebApi; 3 | using Panda.DynamicWebApi.Attributes; 4 | using SuperApi.Model; 5 | using SuperApi.SqlSugar; 6 | 7 | namespace SuperApi.Service; 8 | /// 9 | /// DIY节点管理 10 | /// 11 | [ApiExplorerSettings(GroupName = "default")] 12 | [DynamicWebApi(Module = "default")] 13 | public class DiyNodeService: BaseService
, IDynamicWebApi 14 | { 15 | /// 16 | /// DIY节点管理服务 17 | /// 18 | /// 19 | public DiyNodeService(Repository
db) : base(db) 20 | { 21 | } 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Service/HomeService.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Microsoft.AspNetCore.Authorization; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Panda.DynamicWebApi; 5 | using Panda.DynamicWebApi.Attributes; 6 | 7 | namespace SuperApi.Service; 8 | 9 | /// 10 | /// 首页服务 11 | /// 12 | [ApiExplorerSettings(GroupName = "v1")] 13 | [DynamicWebApi] 14 | public class HomeService : IDynamicWebApi 15 | { 16 | private readonly IHttpContextAccessor _httpContextAccessor; 17 | 18 | /// 19 | /// 首页服务API服务实例 20 | /// 21 | /// 22 | public HomeService(IHttpContextAccessor httpContextAccessor) 23 | { 24 | _httpContextAccessor = httpContextAccessor; 25 | } 26 | 27 | /// 28 | /// 加载静态文件并返回html首页 29 | /// 30 | /// 31 | [AllowAnonymous] 32 | [HttpGet] 33 | [Route("/admin")] 34 | public async Task Index() 35 | { 36 | var file =await File.ReadAllTextAsync(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot/admin/index.html")); 37 | var data = Encoding.UTF8.GetBytes(file); 38 | _httpContextAccessor.HttpContext!.Response.ContentType = "text/html"; 39 | await _httpContextAccessor.HttpContext!.Response.Body.WriteAsync(data, 0, data.Length); 40 | } 41 | } -------------------------------------------------------------------------------- /services/SuperApi/Service/OpLogService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Panda.DynamicWebApi; 3 | using Panda.DynamicWebApi.Attributes; 4 | using SuperApi.Model; 5 | using SuperApi.SqlSugar; 6 | 7 | namespace SuperApi.Service; 8 | /// 9 | /// 日志管理 10 | /// 11 | [ApiExplorerSettings(GroupName = "default")] 12 | [DynamicWebApi(Module = "default")] 13 | public class OpLogService: BaseService, IDynamicWebApi 14 | { 15 | /// 16 | /// 日志管理服务 17 | /// 18 | /// 19 | public OpLogService(Repository db) : base(db) 20 | { 21 | } 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Service/PostService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Panda.DynamicWebApi; 3 | using Panda.DynamicWebApi.Attributes; 4 | using SuperApi.Model; 5 | using SuperApi.SqlSugar; 6 | 7 | namespace SuperApi.Service; 8 | /// 9 | /// 职位管理 10 | /// 11 | [ApiExplorerSettings(GroupName = "default")] 12 | [DynamicWebApi(Module = "default")] 13 | public class PostService: BaseService, IDynamicWebApi 14 | { 15 | /// 16 | /// 职位管理服务 17 | /// 18 | /// 19 | public PostService(Repository db) : base(db) 20 | { 21 | } 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Service/RoleService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Panda.DynamicWebApi; 3 | using Panda.DynamicWebApi.Attributes; 4 | using SuperApi.Model; 5 | using SuperApi.SqlSugar; 6 | 7 | namespace SuperApi.Service; 8 | /// 9 | /// 角色管理 10 | /// 11 | [ApiExplorerSettings(GroupName = "default")] 12 | [DynamicWebApi(Module = "default")] 13 | public class RoleService : BaseService, IDynamicWebApi 14 | { 15 | /// 16 | /// 角色管理服务 17 | /// 18 | /// 19 | public RoleService(Repository db) : base(db) 20 | { 21 | } 22 | } -------------------------------------------------------------------------------- /services/SuperApi/Service/UserService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Panda.DynamicWebApi; 3 | using Panda.DynamicWebApi.Attributes; 4 | using SuperApi.Config; 5 | using SuperApi.Enum; 6 | using SuperApi.Model; 7 | using SuperApi.SqlSugar; 8 | using SuperApi.Utils; 9 | 10 | namespace SuperApi.Service; 11 | /// 12 | /// 用户管理 13 | /// 14 | [ApiExplorerSettings(GroupName = "default")] 15 | [DynamicWebApi(Module = "default")] 16 | public class UserService: BaseService, IDynamicWebApi 17 | { 18 | /// 19 | /// 用户管理服务 20 | /// 21 | /// 22 | public UserService(Repository db) : base(db) 23 | { 24 | } 25 | /// 26 | /// PC创建用户 27 | /// 28 | /// 29 | /// 30 | [HttpPost] 31 | public async Task AddPcUser([FromBody] User model) 32 | { 33 | var isHave = await Db.AsQueryable().Where(x => x.Account.Equals(model.Account)).AnyAsync(); 34 | if (isHave) 35 | { 36 | throw new Exception("账号已存在!"); 37 | } 38 | var cryptoType = ConfigProvider.Config["Cryptogram:CryptoType"]!; 39 | if (cryptoType == CryptogramEnum.MD5.ToString()) 40 | { 41 | //默认密码 42 | model.Password = CryptogramUtil.Md5Encrypt("a88888888"); 43 | } 44 | else 45 | { 46 | //默认密码 47 | model.Password = CryptogramUtil.Sm2Encrypt("a88888888"); 48 | } 49 | return await Db.Add(model) > 0; 50 | } 51 | } -------------------------------------------------------------------------------- /services/SuperApi/SqlSugar/Seed/PostSeed.cs: -------------------------------------------------------------------------------- 1 | using SqlSugar; 2 | using SuperApi.Enum; 3 | using SuperApi.Model; 4 | using SuperApi.Utils; 5 | 6 | namespace SuperApi.SqlSugar.Seed; 7 | /// 8 | /// Seed岗位 9 | /// 10 | public class PostSeed 11 | { 12 | /// 13 | /// Seed岗位 14 | /// 15 | public static void Init(SqlSugarScope db) 16 | { 17 | var rows = new List 18 | { 19 | new Post() 20 | { 21 | Id = 1, 22 | Name = "全栈大神", 23 | Code = "P1", 24 | Status = StatusEnum.启用, 25 | CreateTime = new DateTime() 26 | }, 27 | new Post() 28 | { 29 | Id = 2, 30 | Name = "菜鸡", 31 | Code = "P2", 32 | Status = StatusEnum.启用, 33 | CreateTime = new DateTime() 34 | } 35 | }; 36 | var entityInfo = db.EntityMaintenance.GetEntityInfo(typeof(Post)); 37 | if (entityInfo.Columns.Any(u => u.IsPrimarykey)) 38 | { 39 | // 按主键进行批量增加和更新 40 | var storage = db.StorageableByObject(rows).ToStorage(); 41 | storage.AsInsertable.ExecuteCommand(); 42 | storage.AsUpdateable.ExecuteCommand(); 43 | } 44 | else 45 | { 46 | // 无主键则只进行插入 47 | if (!db.Queryable(entityInfo.DbTableName, entityInfo.DbTableName).Any()) 48 | db.InsertableByObject(rows).ExecuteCommand(); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /services/SuperApi/SuperApi.http: -------------------------------------------------------------------------------- 1 | @SuperApi_HostAddress = http://localhost:5059 2 | 3 | GET {{SuperApi_HostAddress}}/weatherforecast/ 4 | Accept: application/json 5 | 6 | ### 7 | -------------------------------------------------------------------------------- /services/SuperApi/Utils/LongToStringConverterUtil.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace SuperApi.Utils; 4 | /// 5 | /// 设置返回Json名称全小写 6 | /// 7 | public class LongToStringConverterUtil : JsonConverter 8 | { 9 | /// 10 | /// 11 | /// 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | public override long ReadJson(JsonReader reader, Type objectType, long existingValue, bool hasExistingValue, 19 | JsonSerializer serializer) 20 | { 21 | long value = Convert.ToInt64(reader.Value); 22 | return value; 23 | } 24 | 25 | /// 26 | /// 27 | /// 28 | /// 29 | /// 30 | /// 31 | public override void WriteJson(JsonWriter writer, long value, JsonSerializer serializer) 32 | { 33 | string stringValue = value.ToString(); 34 | writer.WriteValue(stringValue); 35 | } 36 | } -------------------------------------------------------------------------------- /services/SuperApi/Utils/RegularValidate.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Text.RegularExpressions; 3 | 4 | namespace SuperApi.Utils; 5 | 6 | 7 | 8 | /// 9 | /// 正则校验 10 | /// 11 | public static class RegularValidate 12 | { 13 | /// 14 | /// 验证密码规则 15 | /// 16 | /// 17 | /// 18 | public static bool ValidatePassword(string password) 19 | { 20 | var regex = new Regex(@" 21 | (?=.*[0-9]) #必须包含数字 22 | (?=.*[a-z]) #必须包含小写 23 | (?=.*[A-Z]) #必须包含大写 24 | (?=([\x21-\x7e]+)[^a-zA-Z0-9]) #必须包含特殊符号 25 | .{8,30} #至少8个字符,最多30个字符 26 | ", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace); 27 | 28 | //如果要求必须包含小写、大写字母,则上面的(?=.*[a-zA-Z]) 要改为: 29 | /* 30 | * (?=.*[a-z]) 31 | * (?=.*[A-Z]) 32 | */ 33 | return regex.IsMatch(password); 34 | } 35 | } -------------------------------------------------------------------------------- /services/SuperApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /services/SuperApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/Upload/1790278317430149121.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/services/SuperApi/wwwroot/Upload/1790278317430149121.png -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/Upload/1790288730997788673.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/services/SuperApi/wwwroot/Upload/1790288730997788673.png -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/Upload/1790301428166823937.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/services/SuperApi/wwwroot/Upload/1790301428166823937.png -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/Upload/1790301476749447169.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/services/SuperApi/wwwroot/Upload/1790301476749447169.png -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/Upload/1790563542529871873.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/services/SuperApi/wwwroot/Upload/1790563542529871873.png -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/Upload/1790586568491274241.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/services/SuperApi/wwwroot/Upload/1790586568491274241.jpg -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/_commonjsHelpers-2f131a27-flC_zxlv.js: -------------------------------------------------------------------------------- 1 | function u(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}function c(t){if(t.__esModule)return t;var n=t.default;if(typeof n=="function"){var e=function r(){return this instanceof r?Reflect.construct(n,arguments,this.constructor):n.apply(this,arguments)};e.prototype=n.prototype}else e={};return Object.defineProperty(e,"__esModule",{value:!0}),Object.keys(t).forEach(function(r){var o=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,o.get?o:{enumerable:!0,get:function(){return t[r]}})}),e}export{c,u as n}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/_url_-MePe-juJ.js: -------------------------------------------------------------------------------- 1 | import{d as o,M as s,Y as a,o as t,f as n,g as l}from"./index-BZUOWCTQ.js";const r={class:"h-full"},c=["src"],m=o({name:"iframe-page",__name:"[url]",props:{url:{}},setup(i){return s(()=>{console.log("mounted")}),a(()=>{console.log("activated")}),(e,d)=>(t(),n("div",r,[l("iframe",{id:"iframePage",class:"size-full",src:e.url},null,8,c)]))}});export{m as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/dynamic-gU_5PGvA.js: -------------------------------------------------------------------------------- 1 | import{o as s,f as n,g as r,a6 as t,a7 as a}from"./index-BZUOWCTQ.js";const l={class:"inline-block",viewBox:"0 0 24 24",width:"1em",height:"1em"},c=r("path",{fill:"currentColor",d:"M18 12.998h-5v5a1 1 0 0 1-2 0v-5H6a1 1 0 0 1 0-2h5v-5a1 1 0 0 1 2 0v5h5a1 1 0 0 1 0 2"},null,-1),o=[c];function u(e,i){return s(),n("svg",l,[...o])}const y={name:"ic-round-plus",render:u},f=async e=>t({url:"/default/Table/Table",method:"post",data:e}),m=async e=>t({url:"/default/Table/DelTable",method:"post",data:e}),g=async e=>t({url:"/default/Field/SaveAll",method:"post",data:e}),h=async e=>t({url:"/default/Table/List?"+a.stringify(e)}),D=async e=>t({url:"/default/Field/List?"+a.stringify(e)}),p=async e=>t({url:"/default/Dynamic/One?"+a.stringify(e)}),_=async e=>t({url:"/default/Dynamic/Page?"+a.stringify(e)}),b=async e=>t({url:"/default/Dynamic/Tree?"+a.stringify(e)}),T=async e=>t({url:"/default/Dynamic/List?"+a.stringify(e)}),v=async e=>t({url:"/default/Dynamic",method:"post",data:e}),B=async e=>t({url:"/default/Dynamic/Edit",method:"post",data:e}),L=async e=>t({url:"/default/Dynamic/Del",method:"post",data:e});export{y as _,b as a,_ as b,T as c,L as d,B as e,v as f,p as g,D as h,h as i,m as j,f as k,g as s}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/exception-base.vue_vue_type_script_setup_true_lang-Dd_RLJG2.js: -------------------------------------------------------------------------------- 1 | import{d as l,U as m,x as u,o as _,f as d,g as x,p as o,i as f,S as y,A as v,V as t,$ as B,W as h,X as g}from"./index-BZUOWCTQ.js";const k={class:"size-full min-h-520px flex-col-center gap-24px overflow-hidden"},N={class:"flex text-400px text-primary"},S=l({name:"ExceptionBase",__name:"exception-base",props:{type:{}},setup(n){const s=n,{routerPushByKey:a}=m(),c={403:"no-permission",404:"not-found",500:"service-error"},r=u(()=>c[s.type]);return(V,e)=>{const i=h,p=g;return _(),d("div",k,[x("div",N,[o(i,{"local-icon":r.value},null,8,["local-icon"])]),o(p,{type:"primary",onClick:e[0]||(e[0]=$=>t(a)("root"))},{default:f(()=>[y(v(t(B)("common.backToHome")),1)]),_:1})])}}});export{S as _}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/fs-uploader-0f406a2a-DKgNpGPZ.js: -------------------------------------------------------------------------------- 1 | import{d as p,H as n,_ as r}from"./index-BZUOWCTQ.js";const d=p({name:"FsUploader",props:{type:{}},setup(e){async function t(){const{getDefaultType:a}=r(),o=e.type||a();return await n(o)}return{getUploaderRef:t}}});export{d as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-2YcrU8FE.js: -------------------------------------------------------------------------------- 1 | import{_ as o}from"./exception-base.vue_vue_type_script_setup_true_lang-Dd_RLJG2.js";import{d as n,o as t,h as a}from"./index-BZUOWCTQ.js";const m=n({name:"404",__name:"index",setup(_){return(c,s)=>{const e=o;return t(),a(e,{type:"404"})}}});export{m as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-8Zat4c5B.js: -------------------------------------------------------------------------------- 1 | import{_ as o}from"./exception-base.vue_vue_type_script_setup_true_lang-Dd_RLJG2.js";import{d as n,o as t,h as a}from"./index-BZUOWCTQ.js";const m=n({name:"403",__name:"index",setup(_){return(c,s)=>{const e=o;return t(),a(e,{type:"403"})}}});export{m as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-BXdYPuBb.js: -------------------------------------------------------------------------------- 1 | import{_ as o}from"./look-forward.vue_vue_type_script_setup_true_lang-qO66lTGI.js";import{d as n,o as r,h as t}from"./index-BZUOWCTQ.js";const p=n({name:"user-center",__name:"index",setup(a){return(_,c)=>{const e=o;return r(),t(e)}}});export{p as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-C5CtqXlC.js: -------------------------------------------------------------------------------- 1 | import{_ as e}from"./look-forward.vue_vue_type_script_setup_true_lang-qO66lTGI.js";import{d as n,o as _,h as t}from"./index-BZUOWCTQ.js";const p=n({name:"multi-menu_second_child_home",__name:"index",setup(a){return(c,m)=>{const o=e;return _(),t(o)}}});export{p as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-CSL-_yYS.js: -------------------------------------------------------------------------------- 1 | import{_ as e}from"./look-forward.vue_vue_type_script_setup_true_lang-qO66lTGI.js";import{d as n,o as a,h as r}from"./index-BZUOWCTQ.js";const m=n({name:"function_super-page",__name:"index",setup(t){return(_,c)=>{const o=e;return a(),r(o)}}});export{m as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-CXvDrQgj.js: -------------------------------------------------------------------------------- 1 | import{_ as m}from"./look-forward.vue_vue_type_script_setup_true_lang-qO66lTGI.js";import{d as p,a8 as d,U as f,x,o as y,f as b,p as a,i as n,g as s,V as t,S as B,A as e,$ as u,X as g}from"./index-BZUOWCTQ.js";const k={class:"py-24px"},h=p({name:"function_multi-tab",__name:"index",setup(v){const r=d(),{routerPushByKey:c}=f(),i=x(()=>JSON.stringify(r.query));return(N,o)=>{const l=g,_=m;return y(),b("div",null,[a(_,null,{default:n(()=>[s("div",null,[a(l,{onClick:o[0]||(o[0]=T=>t(c)("function_tab"))},{default:n(()=>[B(e(t(u)("page.function.multiTab.backTab")),1)]),_:1}),s("div",k,e(t(u)("page.function.multiTab.routeParam"))+": "+e(i.value),1)])]),_:1})])}}});export{h as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-D0Yj8Qx6.js: -------------------------------------------------------------------------------- 1 | import{_ as e}from"./look-forward.vue_vue_type_script_setup_true_lang-qO66lTGI.js";import{d as n,o as _,h as t}from"./index-BZUOWCTQ.js";const i=n({name:"function_hide-child_one",__name:"index",setup(a){return(c,r)=>{const o=e;return _(),t(o)}}});export{i as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-DLfsA-ZK.js: -------------------------------------------------------------------------------- 1 | import{_ as o}from"./exception-base.vue_vue_type_script_setup_true_lang-Dd_RLJG2.js";import{d as n,o as t,h as a}from"./index-BZUOWCTQ.js";const m=n({name:"500",__name:"index",setup(_){return(c,s)=>{const e=o;return t(),a(e,{type:"500"})}}});export{m as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-DVuM67FR.js: -------------------------------------------------------------------------------- 1 | import{_ as e}from"./look-forward.vue_vue_type_script_setup_true_lang-qO66lTGI.js";import{d as n,o as t,h as _}from"./index-BZUOWCTQ.js";const i=n({name:"function_hide-child_three",__name:"index",setup(r){return(a,c)=>{const o=e;return t(),_(o)}}});export{i as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-DnZhkf2e.js: -------------------------------------------------------------------------------- 1 | import{_ as e}from"./look-forward.vue_vue_type_script_setup_true_lang-qO66lTGI.js";import{d as n,o as t,h as _}from"./index-BZUOWCTQ.js";const i=n({name:"function_hide-child_two",__name:"index",setup(a){return(c,r)=>{const o=e;return t(),_(o)}}});export{i as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-DrmDjbUF.js: -------------------------------------------------------------------------------- 1 | import{_ as e}from"./look-forward.vue_vue_type_script_setup_true_lang-qO66lTGI.js";import{d as n,o as t,h as _}from"./index-BZUOWCTQ.js";const i=n({name:"multi-menu_first_child",__name:"index",setup(r){return(a,c)=>{const o=e;return t(),_(o)}}});export{i as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/index-o00djbCc.js: -------------------------------------------------------------------------------- 1 | import{d as m,o as p,h as f,i as t,p as o,V as a,$ as e,S as r,A as l,a9 as c,X as g,a3 as h}from"./index-BZUOWCTQ.js";import{_ as k}from"./Space-CUMox7Fx.js";const M=m({name:"function_request",__name:"index",setup(q){async function i(){await c("8888",e("request.logoutMsg"))}async function u(){await c("7777",e("request.logoutWithModalMsg"))}async function d(){await c("9999",e("request.tokenExpired"))}return(w,C)=>{const s=g,n=h,_=k;return p(),f(_,{vertical:"",size:16},{default:t(()=>[o(n,{title:a(e)("request.logout"),bordered:!1,size:"small",segmented:"",class:"card-wrapper"},{default:t(()=>[o(s,{onClick:i},{default:t(()=>[r(l(a(e)("common.trigger")),1)]),_:1})]),_:1},8,["title"]),o(n,{title:a(e)("request.logoutWithModal"),bordered:!1,size:"small",segmented:"",class:"card-wrapper"},{default:t(()=>[o(s,{onClick:u},{default:t(()=>[r(l(a(e)("common.trigger")),1)]),_:1})]),_:1},8,["title"]),o(n,{title:a(e)("request.refreshToken"),bordered:!1,size:"small",segmented:"",class:"card-wrapper"},{default:t(()=>[o(s,{onClick:d},{default:t(()=>[r(l(a(e)("common.trigger")),1)]),_:1})]),_:1},8,["title"])]),_:1})}}});export{M as default}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/look-forward.vue_vue_type_script_setup_true_lang-qO66lTGI.js: -------------------------------------------------------------------------------- 1 | import{d as s,o as a,f as n,g as o,p as r,R as c,A as l,V as i,$ as p,W as _}from"./index-BZUOWCTQ.js";const d={class:"size-full min-h-520px flex-col-center gap-24px overflow-hidden"},m={class:"flex text-400px text-primary"},f={class:"text-28px text-primary font-500"},k=s({name:"LookForward",__name:"look-forward",setup(x){return(e,h)=>{const t=_;return a(),n("div",d,[o("div",m,[r(t,{"local-icon":"expectation"})]),c(e.$slots,"default",{},()=>[o("h3",f,l(i(p)("common.lookForward")),1)])])}}});export{k as _}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/soybean-JC38yUrs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TmmTop/SuperApi/9eb4bb683465d97b5fe60a90f3b756e4424e9686/services/SuperApi/wwwroot/assets/soybean-JC38yUrs.jpg -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/assets/uploader-form-b18e19b1-DSwjLPjC.js: -------------------------------------------------------------------------------- 1 | import{l as i,w as p,_ as c}from"./index-BZUOWCTQ.js";function l(t,r,s){let e;s.response?e=`${s.response.error||s.response}`:s.responseText?e=`${s.responseText}`:e=`fail to post ${t} ${s.status}`;const o=new Error(e);return o.status=s.status,o.method="post",o.url=t,o}function d(t){const r=t.responseText||t.response;if(!r)return r;try{return JSON.parse(r)}catch{return r}}function f(t,r,s){if(typeof XMLHttpRequest>"u")return;const e=new XMLHttpRequest,o=t.action;e.timeout=t.timeout,e.upload&&(e.upload.onprogress=function(n){n.total>0&&(n.percent=n.loaded/n.total*100),t.onProgress(n)});const u=new FormData;t.data&&Object.keys(t.data).forEach(n=>{u.append(n,t.data[n])}),u.append(t.name,t.file,t.file.name),e.onerror=function(n){s(n)},e.onload=function(){if(e.status<200||e.status>=300)return t.onError(l(o,t,e));r(d(e))},e.open("post",o,!0),t.withCredentials&&"withCredentials"in e&&(e.withCredentials=!0);const a=t.headers||{};for(const n in a)a.hasOwnProperty(n)&&a[n]!==null&&e.setRequestHeader(n,a[n]);return e.send(u),e}function w(t){return new Promise((r,s)=>{f(t,async e=>{r(e)},e=>{s(e)})})}async function m(t){const{file:r,fileName:s,onProgress:e}=t,o=t.options,u=await p(r,s,o);o.data==null&&(o.data={}),o.data.key=u;const a={file:r,onProgress:e,timeout:6e4,...o};delete a.uploadRequest;let n=await(o.uploadRequest??w)(a);return o.successHandle&&(n=await o.successHandle(n,a)),n&&typeof n=="object"&&n.key==null&&(n.key=u),n}async function h(t){const{getConfig:r}=c(),s=r("form");return t.options=i.merge({},i.cloneDeep(s),t.options),await m(t)}export{h as upload}; 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /services/SuperApi/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 超擎极致开放平台 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | --------------------------------------------------------------------------------