Repository: lmq2582609/minimalist-saas Branch: master Commit: 742e613f4a75 Files: 322 Total size: 1.4 MB Directory structure: gitextract_koj_vsiu/ ├── .gitignore ├── LICENSE ├── README.md ├── minimalist-application/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── minimalist/ │ │ └── application/ │ │ ├── MinimalistBasicApplication.java │ │ └── config/ │ │ ├── GlobalExceptionHandler.java │ │ └── satoken/ │ │ ├── SaTokenConfigure.java │ │ └── SaTokenInterfaceImpl.java │ └── resources/ │ ├── application-dev.yml │ ├── application.yml │ └── logback-dev.xml ├── minimalist-basic/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── minimalist/ │ │ │ └── basic/ │ │ │ ├── config/ │ │ │ │ ├── async/ │ │ │ │ │ ├── AsyncConfig.java │ │ │ │ │ └── ThreadPoolConfig.java │ │ │ │ ├── convert/ │ │ │ │ │ ├── FileSizeDeserializer.java │ │ │ │ │ ├── FileSizeSerializer.java │ │ │ │ │ └── LongArrJsonSerializer.java │ │ │ │ ├── dataConfig/ │ │ │ │ │ └── SystemConfigInit.java │ │ │ │ ├── eDict/ │ │ │ │ │ ├── BeanMethod.java │ │ │ │ │ ├── EDict.java │ │ │ │ │ ├── EDictConstant.java │ │ │ │ │ └── EDictInit.java │ │ │ │ ├── exception/ │ │ │ │ │ └── BusinessException.java │ │ │ │ ├── fileHandler/ │ │ │ │ │ ├── FileManager.java │ │ │ │ │ ├── FileResourcesInit.java │ │ │ │ │ ├── entity/ │ │ │ │ │ │ ├── LocalFileEntity.java │ │ │ │ │ │ ├── MinIOFileEntity.java │ │ │ │ │ │ └── QiNiuFileEntity.java │ │ │ │ │ └── handler/ │ │ │ │ │ ├── FileHandler.java │ │ │ │ │ └── impl/ │ │ │ │ │ ├── LocalFileHandler.java │ │ │ │ │ ├── MinIOFileHandler.java │ │ │ │ │ └── QiNiuFileHandler.java │ │ │ │ ├── mybatis/ │ │ │ │ │ ├── GeneratorCodeHandler.java │ │ │ │ │ ├── InsertFullColumnHandler.java │ │ │ │ │ ├── MyBatisFlexConfiguration.java │ │ │ │ │ ├── UpdateFullColumnHandler.java │ │ │ │ │ └── bo/ │ │ │ │ │ ├── BaseEntity.java │ │ │ │ │ ├── PageReq.java │ │ │ │ │ └── PageResp.java │ │ │ │ ├── redis/ │ │ │ │ │ ├── RedisManager.java │ │ │ │ │ └── RedissonConfiguration.java │ │ │ │ ├── resubmit/ │ │ │ │ │ ├── ReSubmit.java │ │ │ │ │ └── ReSubmitAspect.java │ │ │ │ ├── swagger/ │ │ │ │ │ ├── ParameterHandler.java │ │ │ │ │ ├── PropertyHandler.java │ │ │ │ │ ├── SchemaEnum.java │ │ │ │ │ ├── SchemaEnumHandler.java │ │ │ │ │ └── SwaggerConfig.java │ │ │ │ ├── tenant/ │ │ │ │ │ ├── TenantDatasourceInterceptor.java │ │ │ │ │ ├── TenantIgnore.java │ │ │ │ │ ├── TenantIgnoreAspect.java │ │ │ │ │ ├── TenantInit.java │ │ │ │ │ └── TenantWebMvcConfig.java │ │ │ │ └── trace/ │ │ │ │ ├── TraceIdInterceptor.java │ │ │ │ └── WebMvcConfig.java │ │ │ ├── controller/ │ │ │ │ ├── ConfigController.java │ │ │ │ ├── DeptController.java │ │ │ │ ├── DictController.java │ │ │ │ ├── FileController.java │ │ │ │ ├── NoticeController.java │ │ │ │ ├── PermController.java │ │ │ │ ├── PostController.java │ │ │ │ ├── RoleController.java │ │ │ │ ├── StorageController.java │ │ │ │ ├── TenantController.java │ │ │ │ ├── TenantPackageController.java │ │ │ │ └── UserController.java │ │ │ ├── entity/ │ │ │ │ ├── enums/ │ │ │ │ │ ├── ConfigEnum.java │ │ │ │ │ ├── DeptEnum.java │ │ │ │ │ ├── DictEnum.java │ │ │ │ │ ├── FileEnum.java │ │ │ │ │ ├── NoticeEnum.java │ │ │ │ │ ├── PermEnum.java │ │ │ │ │ ├── PostEnum.java │ │ │ │ │ ├── RespEnum.java │ │ │ │ │ ├── RoleEnum.java │ │ │ │ │ ├── StatusEnum.java │ │ │ │ │ ├── StorageEnum.java │ │ │ │ │ ├── TenantEnum.java │ │ │ │ │ └── UserEnum.java │ │ │ │ ├── po/ │ │ │ │ │ ├── MConfig.java │ │ │ │ │ ├── MDept.java │ │ │ │ │ ├── MDict.java │ │ │ │ │ ├── MFile.java │ │ │ │ │ ├── MNotice.java │ │ │ │ │ ├── MPerms.java │ │ │ │ │ ├── MPost.java │ │ │ │ │ ├── MRole.java │ │ │ │ │ ├── MRoleDept.java │ │ │ │ │ ├── MRolePerm.java │ │ │ │ │ ├── MStorage.java │ │ │ │ │ ├── MTenant.java │ │ │ │ │ ├── MTenantDatasource.java │ │ │ │ │ ├── MTenantPackage.java │ │ │ │ │ ├── MTenantPackagePerm.java │ │ │ │ │ ├── MUser.java │ │ │ │ │ ├── MUserDept.java │ │ │ │ │ ├── MUserPost.java │ │ │ │ │ └── MUserRole.java │ │ │ │ └── vo/ │ │ │ │ ├── config/ │ │ │ │ │ ├── ConfigQueryVO.java │ │ │ │ │ └── ConfigVO.java │ │ │ │ ├── dept/ │ │ │ │ │ ├── DeptQueryVO.java │ │ │ │ │ └── DeptVO.java │ │ │ │ ├── dict/ │ │ │ │ │ ├── DictCacheVO.java │ │ │ │ │ ├── DictDataVO.java │ │ │ │ │ ├── DictInfoVO.java │ │ │ │ │ ├── DictListVO.java │ │ │ │ │ ├── DictQueryVO.java │ │ │ │ │ └── DictVO.java │ │ │ │ ├── file/ │ │ │ │ │ ├── FileQueryVO.java │ │ │ │ │ ├── FileUploadBatchVO.java │ │ │ │ │ ├── FileUploadRespVO.java │ │ │ │ │ ├── FileUploadVO.java │ │ │ │ │ └── FileVO.java │ │ │ │ ├── notice/ │ │ │ │ │ ├── NoticeQueryVO.java │ │ │ │ │ └── NoticeVO.java │ │ │ │ ├── perm/ │ │ │ │ │ ├── PermQueryVO.java │ │ │ │ │ └── PermVO.java │ │ │ │ ├── post/ │ │ │ │ │ ├── PostQueryVO.java │ │ │ │ │ └── PostVO.java │ │ │ │ ├── role/ │ │ │ │ │ ├── RoleQueryVO.java │ │ │ │ │ └── RoleVO.java │ │ │ │ ├── storage/ │ │ │ │ │ ├── StorageQueryVO.java │ │ │ │ │ └── StorageVO.java │ │ │ │ ├── tenant/ │ │ │ │ │ ├── TenantDatasourceVO.java │ │ │ │ │ ├── TenantPackageQueryVO.java │ │ │ │ │ ├── TenantPackageVO.java │ │ │ │ │ ├── TenantQueryVO.java │ │ │ │ │ └── TenantVO.java │ │ │ │ └── user/ │ │ │ │ ├── ImageCaptchaVO.java │ │ │ │ ├── RePasswordVO.java │ │ │ │ ├── UserInfoVO.java │ │ │ │ ├── UserLoginReqVO.java │ │ │ │ ├── UserQueryVO.java │ │ │ │ ├── UserSettingVO.java │ │ │ │ └── UserVO.java │ │ │ ├── manager/ │ │ │ │ ├── TenantManager.java │ │ │ │ └── UserManager.java │ │ │ ├── mapper/ │ │ │ │ ├── MConfigMapper.java │ │ │ │ ├── MDeptMapper.java │ │ │ │ ├── MDictMapper.java │ │ │ │ ├── MFileMapper.java │ │ │ │ ├── MNoticeMapper.java │ │ │ │ ├── MPermsMapper.java │ │ │ │ ├── MPostMapper.java │ │ │ │ ├── MRoleDeptMapper.java │ │ │ │ ├── MRoleMapper.java │ │ │ │ ├── MRolePermMapper.java │ │ │ │ ├── MStorageMapper.java │ │ │ │ ├── MTenantDatasourceMapper.java │ │ │ │ ├── MTenantMapper.java │ │ │ │ ├── MTenantPackageMapper.java │ │ │ │ ├── MTenantPackagePermMapper.java │ │ │ │ ├── MUserDeptMapper.java │ │ │ │ ├── MUserMapper.java │ │ │ │ ├── MUserPostMapper.java │ │ │ │ └── MUserRoleMapper.java │ │ │ ├── mq/ │ │ │ │ ├── SystemConfigSyncConsumer.java │ │ │ │ └── TenantDatasourceSyncConsumer.java │ │ │ ├── service/ │ │ │ │ ├── ConfigService.java │ │ │ │ ├── DeptService.java │ │ │ │ ├── DictService.java │ │ │ │ ├── EDictService.java │ │ │ │ ├── FileService.java │ │ │ │ ├── NoticeService.java │ │ │ │ ├── PermService.java │ │ │ │ ├── PostService.java │ │ │ │ ├── RoleService.java │ │ │ │ ├── StorageService.java │ │ │ │ ├── TenantPackageService.java │ │ │ │ ├── TenantService.java │ │ │ │ ├── UserService.java │ │ │ │ └── impl/ │ │ │ │ ├── ConfigServiceImpl.java │ │ │ │ ├── DeptServiceImpl.java │ │ │ │ ├── DictServiceImpl.java │ │ │ │ ├── EDictServiceImpl.java │ │ │ │ ├── FileServiceImpl.java │ │ │ │ ├── NoticeServiceImpl.java │ │ │ │ ├── PermServiceImpl.java │ │ │ │ ├── PostServiceImpl.java │ │ │ │ ├── RoleServiceImpl.java │ │ │ │ ├── StorageServiceImpl.java │ │ │ │ ├── TenantPackageServiceImpl.java │ │ │ │ ├── TenantServiceImpl.java │ │ │ │ └── UserServiceImpl.java │ │ │ └── utils/ │ │ │ ├── Add.java │ │ │ ├── CommonConstant.java │ │ │ ├── RedisKeyConstant.java │ │ │ ├── TenantUtil.java │ │ │ ├── TextUtil.java │ │ │ ├── UnqIdUtil.java │ │ │ ├── Update.java │ │ │ └── ValidateUtil.java │ │ └── resources/ │ │ └── mappers/ │ │ ├── MConfigMapper.xml │ │ ├── MDeptMapper.xml │ │ ├── MDictMapper.xml │ │ ├── MFileMapper.xml │ │ ├── MNoticeMapper.xml │ │ ├── MPermsMapper.xml │ │ ├── MPostMapper.xml │ │ ├── MRoleDeptMapper.xml │ │ ├── MRoleMapper.xml │ │ ├── MRolePermMapper.xml │ │ ├── MStorageMapper.xml │ │ ├── MTenantDatasourceMapper.xml │ │ ├── MTenantMapper.xml │ │ ├── MTenantPackageMapper.xml │ │ ├── MTenantPackagePermMapper.xml │ │ ├── MUserDeptMapper.xml │ │ ├── MUserMapper.xml │ │ ├── MUserPostMapper.xml │ │ └── MUserRoleMapper.xml │ └── test/ │ └── java/ │ └── com/ │ └── minimalist/ │ └── basic/ │ └── MinimalistBasicApplicationTests.java ├── minimalist-vue3/ │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── public/ │ │ └── tinymce/ │ │ └── skins/ │ │ ├── content/ │ │ │ ├── dark/ │ │ │ │ └── content.css │ │ │ ├── default/ │ │ │ │ └── content.css │ │ │ ├── document/ │ │ │ │ └── content.css │ │ │ ├── tinymce-5/ │ │ │ │ └── content.css │ │ │ ├── tinymce-5-dark/ │ │ │ │ └── content.css │ │ │ └── writer/ │ │ │ └── content.css │ │ ├── langs/ │ │ │ └── zh-Hans.js │ │ └── ui/ │ │ ├── oxide/ │ │ │ ├── content.css │ │ │ ├── content.inline.css │ │ │ ├── skin.css │ │ │ └── skin.shadowdom.css │ │ ├── oxide-dark/ │ │ │ ├── content.css │ │ │ ├── content.inline.css │ │ │ ├── skin.css │ │ │ └── skin.shadowdom.css │ │ ├── tinymce-5/ │ │ │ ├── content.css │ │ │ ├── content.inline.css │ │ │ ├── skin.css │ │ │ └── skin.shadowdom.css │ │ └── tinymce-5-dark/ │ │ ├── content.css │ │ ├── content.inline.css │ │ ├── skin.css │ │ └── skin.shadowdom.css │ ├── src/ │ │ ├── App.vue │ │ ├── api/ │ │ │ ├── config.js │ │ │ ├── dept.js │ │ │ ├── dict.js │ │ │ ├── file.js │ │ │ ├── notice.js │ │ │ ├── perm.js │ │ │ ├── post.js │ │ │ ├── role.js │ │ │ ├── storage.js │ │ │ ├── tenant.js │ │ │ ├── tenantPackage.js │ │ │ └── user.js │ │ ├── assets/ │ │ │ └── globalStyle.css │ │ ├── axios.js │ │ ├── components/ │ │ │ ├── MHeader.vue │ │ │ ├── MSider.vue │ │ │ ├── PageTabList.vue │ │ │ ├── dictValue/ │ │ │ │ └── index.vue │ │ │ ├── iconSelect/ │ │ │ │ ├── FunctionalIcons.vue │ │ │ │ └── index.vue │ │ │ ├── menuTree/ │ │ │ │ └── index.vue │ │ │ ├── pagination/ │ │ │ │ └── index.vue │ │ │ ├── tinymceEditor/ │ │ │ │ └── index.vue │ │ │ └── uploadFile/ │ │ │ └── index.vue │ │ ├── directives/ │ │ │ ├── permission.js │ │ │ └── role.js │ │ ├── main.js │ │ ├── pages/ │ │ │ ├── 404.vue │ │ │ ├── basic/ │ │ │ │ ├── config/ │ │ │ │ │ ├── ConfigDetail.vue │ │ │ │ │ ├── ConfigEdit.vue │ │ │ │ │ └── ConfigMgt.vue │ │ │ │ ├── dept/ │ │ │ │ │ ├── DeptDetail.vue │ │ │ │ │ ├── DeptEdit.vue │ │ │ │ │ └── DeptMgt.vue │ │ │ │ ├── dict/ │ │ │ │ │ ├── DictDetail.vue │ │ │ │ │ ├── DictEdit.vue │ │ │ │ │ └── DictMgt.vue │ │ │ │ ├── file/ │ │ │ │ │ ├── FileMgt.vue │ │ │ │ │ └── FileSelect.vue │ │ │ │ ├── notice/ │ │ │ │ │ ├── NoticeDetail.vue │ │ │ │ │ ├── NoticeEdit.vue │ │ │ │ │ └── NoticeMgt.vue │ │ │ │ ├── perm/ │ │ │ │ │ ├── PermDetail.vue │ │ │ │ │ ├── PermEdit.vue │ │ │ │ │ └── PermMgt.vue │ │ │ │ ├── post/ │ │ │ │ │ ├── PostDetail.vue │ │ │ │ │ ├── PostEdit.vue │ │ │ │ │ └── PostMgt.vue │ │ │ │ ├── role/ │ │ │ │ │ ├── RoleDetail.vue │ │ │ │ │ ├── RoleEdit.vue │ │ │ │ │ └── RoleMgt.vue │ │ │ │ ├── storage/ │ │ │ │ │ ├── Local.vue │ │ │ │ │ ├── Minio.vue │ │ │ │ │ ├── QiNiu.vue │ │ │ │ │ ├── StorageDetail.vue │ │ │ │ │ ├── StorageEdit.vue │ │ │ │ │ └── StorageMgt.vue │ │ │ │ ├── system/ │ │ │ │ │ └── Swagger.vue │ │ │ │ ├── tenant/ │ │ │ │ │ ├── TenantDetail.vue │ │ │ │ │ ├── TenantEdit.vue │ │ │ │ │ └── TenantMgt.vue │ │ │ │ ├── tenantPackage/ │ │ │ │ │ ├── TenantPackageDetail.vue │ │ │ │ │ ├── TenantPackageEdit.vue │ │ │ │ │ └── TenantPackageMgt.vue │ │ │ │ └── user/ │ │ │ │ ├── UserDetail.vue │ │ │ │ ├── UserEdit.vue │ │ │ │ ├── UserMgt.vue │ │ │ │ └── UserSetting.vue │ │ │ ├── container.vue │ │ │ ├── index.vue │ │ │ └── login.vue │ │ ├── router/ │ │ │ └── index.js │ │ ├── store/ │ │ │ ├── index.js │ │ │ └── module/ │ │ │ └── sys-store.js │ │ └── utils/ │ │ ├── cookie.js │ │ ├── dict.js │ │ ├── msg.js │ │ └── sys.js │ └── vite.config.js ├── pom.xml └── resources/ └── sql/ └── mysql/ ├── 2024-12-03 ~ 2025-03-12期间的SQL变更(第一次使用本项目忽略).sql └── minimalist_全部sql,如果是第一次使用本项目直接执行这个.sql ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ ###################################################################### # Build Tools .gradle /build/ !gradle/wrapper/gradle-wrapper.jar target/ !.mvn/wrapper/maven-wrapper.jar ###################################################################### # IDE ### STS ### .apt_generated .classpath .factorypath .project .settings .springBeans ### IntelliJ IDEA ### .idea *.iws *.iml *.ipr ### NetBeans ### nbproject/private/ build/* nbbuild/ dist/ nbdist/ .nb-gradle/ ###################################################################### # Others *.log *.xml.versionsBackup *.swp !*/build/*.java !*/build/*.html !*/build/*.xml /files/ ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2023 小太阳 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================
logo

极简多租户管理系统

基于SpringBoot3+Vue3前后端分离的Java快速开发脚手架
## 项目简介 极简多租户管理系统是一个多租户管理系统,基于SpringBoot3+Vue3的前后端分离的后台开发脚手架,具备一些常用的基础功能。 ## 项目地址 演示地址:[https://www.jjian.com.cn](https://www.jjian.com.cn) 文档地址:[https://apebbs.cn/docs/minimalist-saas/1.0.0/introduction.html](https://apebbs.cn/docs/minimalist-saas/1.0.0/introduction.html) Gitee:[https://gitee.com/marlife/minimalist-saas](https://gitee.com/marlife/minimalist-saas) Github:[https://github.com/lmq2582609/minimalist-saas](https://github.com/lmq2582609/minimalist-saas) 管理员账号/密码: `admin`/`111111` 租户账号/密码:`dongdong`/`111111` ## 技术选型 ### 前端 | 名称 | 版本 | 说明 | | ----------- | ------ | ----------------------- | | Vue | 3.2.47 | 用于构建用户界面的 JavaScript 框架 | | Vite | 4.3.2 | 前端构建工具 | | Arco-Design | 2.45.3 | 字节出的 Vue3 UI 组件库 | | Windicss | 3.5.6 | CSS 框架 | | Vue-Router | 4.1.6 | Vue官方路由 | | Vueuse | 10.1.2 | 基于Composition API的实用函数库 | | Axios | 1.4.0 | 基于Promise的HTTP客户端 | | Pinia | 2.0.36 | Vue 状态管理 | | Vue-Cropper | 1.0.9 | 图片裁剪 | | Nprogress | 0.2.0 | 进度条 | | Tinymce | 6.6.0 | 富文本编辑器 | ### 后端 | 名称 | 版本 | 说明 | | -------------------------- | ------ | ----------------------- | | Java | 17 | 无需多言 | | SpringBoot | 3.1.1 | Java开发框架 | | Redisson | 3.36.0 | Redis Java客户端 | | Mysql | 8.0.33 | Mysql数据库驱动 | | Mybatis-flex | 1.9.7 | ORM框架 | | Hutool | 5.8.32 | Java工具库 | | Satoken | 1.39.0 | Java权限认证框架 | | Knife4j | 4.1.0 | Swagger2和OpenAPI3增强解决方案 | | Mica-xss | 3.3.2 | xss防护 | ## 中间件 | 名称 | 版本 | 说明 | | ----- | ------ | -------- | | mysql | 8.0.24 | 关系型数据库 | | redis | 7.2.4 | NoSQL数据库 | ## 演示图
================================================ FILE: minimalist-application/pom.xml ================================================ com.cn minimalist-saas 1.0.0-SNAPSHOT 4.0.0 minimalist-application minimalist-application Maven Webapp 启动 jar com.cn minimalist-basic 1.0.0-SNAPSHOT ${project.package.name} org.springframework.boot spring-boot-maven-plugin repackage com.minimalist.application.MinimalistBasicApplication org.projectlombok lombok org.apache.maven.plugins maven-compiler-plugin ${maven.compiler.source} ${maven.compiler.target} ${project.package.encoding} --enable-preview src/main/resources true spring-milestones Spring Milestones https://repo.spring.io/milestone false spring-milestones Spring Milestones https://repo.spring.io/milestone false dev true dev prod prod ================================================ FILE: minimalist-application/src/main/java/com/minimalist/application/MinimalistBasicApplication.java ================================================ package com.minimalist.application; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @MapperScan("com.minimalist.**.mapper") @SpringBootApplication(scanBasePackages = {"com.minimalist.*", "cn.hutool.extra.spring"}) public class MinimalistBasicApplication { public static void main(String[] args) { SpringApplication.run(MinimalistBasicApplication.class, args); } } ================================================ FILE: minimalist-application/src/main/java/com/minimalist/application/config/GlobalExceptionHandler.java ================================================ package com.minimalist.application.config; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotPermissionException; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.entity.enums.RespEnum; import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; import net.dreamlu.mica.xss.core.XssException; import org.springframework.core.NestedExceptionUtils; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException; import java.util.List; import java.util.Set; import java.util.StringJoiner; /** * 全局异常处理 */ @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { /** * 参数异常 * @param e 异常 * @return 响应 */ @ExceptionHandler(value = {IllegalArgumentException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class}) public ResponseEntity paramsException(Exception e) { if (e instanceof IllegalArgumentException) { log.warn(e.getMessage(), e); return ResponseEntity.status(RespEnum.PARAM_ERROR.getCode()).body(RespEnum.PARAM_ERROR.getDesc()); } else if (e instanceof MethodArgumentNotValidException) { //参数异常处理 log.warn(e.getMessage(), e); BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult(); List errors = bindingResult.getFieldErrors(); StringJoiner sj = new StringJoiner(","); errors.forEach(error -> sj.add(error.getDefaultMessage())); return ResponseEntity.status(RespEnum.PARAM_ERROR.getCode()).body(sj.toString()); } else if (e instanceof ConstraintViolationException) { //参数异常处理 log.warn(e.getMessage(), e); Set> constraintViolations = ((ConstraintViolationException) e).getConstraintViolations(); StringJoiner sj = new StringJoiner(","); constraintViolations.forEach(c -> sj.add(c.getMessageTemplate())); return ResponseEntity.status(RespEnum.PARAM_ERROR.getCode()).body(sj.toString()); } else { return exception(e); } } /** * 自定义异常 * @param e 异常 * @return 响应 */ @ExceptionHandler(value = {BusinessException.class}) public ResponseEntity customException(Exception e) { //业务异常 if (e instanceof BusinessException) { //记录日志 log(e); //响应 业务异常 return ResponseEntity.status(((BusinessException) e).getCode()).body(e.getMessage()); } else { return exception(e); } } /** * 未登录异常处理 */ @ExceptionHandler(value = {NotLoginException.class}) public ResponseEntity customNotLoginException(Exception e) { return ResponseEntity.status(RespEnum.REQUEST_UNAUTH.getCode()).body(RespEnum.REQUEST_UNAUTH.getDesc()); } /** * 无权限异常处理 */ @ExceptionHandler(value = {NotPermissionException.class}) public ResponseEntity customNotPermissionException(Exception e) { return ResponseEntity.status(RespEnum.NO_OPERATION_PERMISSION.getCode()).body(RespEnum.NO_OPERATION_PERMISSION.getDesc()); } /** * XSS异常 * @param e 异常 * @return 响应 */ @ExceptionHandler(value = {HttpMessageNotReadableException.class, MethodArgumentConversionNotSupportedException.class}) public ResponseEntity xssException(Exception e) { Throwable rootCause = NestedExceptionUtils.getRootCause(e); if (rootCause instanceof XssException) { //记录日志 log(e); return ResponseEntity.status(RespEnum.PARAM_XSS_ERROR.getCode()).body(RespEnum.PARAM_XSS_ERROR.getDesc()); } else { return exception(e); } } /** * 未知异常 * @param e 异常 * @return 响应 */ @ExceptionHandler(value = {Exception.class}) public ResponseEntity exception(Exception e) { //记录日志 log(e); //响应 系统异常 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(RespEnum.FAILED.getDesc()); } private void log(Exception e) { //记录日志 log.error(e.getMessage(), e); //邮件、通知、告警 } } ================================================ FILE: minimalist-application/src/main/java/com/minimalist/application/config/satoken/SaTokenConfigure.java ================================================ package com.minimalist.application.config.satoken; import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.router.SaHttpMethod; import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.stp.StpUtil; import com.minimalist.basic.config.exception.BusinessException; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class SaTokenConfigure implements WebMvcConfigurer { /** * 注册 Sa-Token 拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { // /** 演示环境,可以删除 ------- start */ // SaInterceptor saInterceptor = new SaInterceptor(handle -> { // //校验登录 // StpUtil.checkLogin(); // // 根据请求类型匹配 // SaRouter.match(SaHttpMethod.POST, SaHttpMethod.DELETE, SaHttpMethod.PUT) // .check(() -> { // throw new BusinessException("演示环境,只能查询,不能进行操作"); // }); // }); // registry.addInterceptor(saInterceptor).addPathPatterns("/**") // .excludePathPatterns("/basic/user/logout"); // /** 演示环境,可以删除 ------- end */ //上面演示环境删除后,下面的注视需要放开 //全局拦截配置,必须登陆后才可访问,如果某个接口需要跳过拦截,需要在接口上增加@SaIgnore注解 SaInterceptor saInterceptor = new SaInterceptor(handle -> StpUtil.checkLogin()); registry.addInterceptor(saInterceptor).addPathPatterns("/**"); } } ================================================ FILE: minimalist-application/src/main/java/com/minimalist/application/config/satoken/SaTokenInterfaceImpl.java ================================================ package com.minimalist.application.config.satoken; import cn.dev33.satoken.stp.StpInterface; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.minimalist.basic.config.redis.RedisManager; import com.minimalist.basic.utils.RedisKeyConstant; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; import java.util.Set; /** * sa-token,自定义权限加载接口实现类 */ @Component public class SaTokenInterfaceImpl implements StpInterface { @Autowired private RedisManager redisManager; /** * 返回指定账号id所拥有的权限码集合,loginId即登陆时传入的UserId * @param loginId 用户ID * @param loginType 账号体系标识 * @return 权限编码集合 */ @Override public List getPermissionList(Object loginId, String loginType) { //从redis获取权限数据,在请求getUserInfo接口时会set权限数据 Set permCodes = redisManager.get(StrUtil.indexedFormat(RedisKeyConstant.USER_PERM_CACHE_KEY, Long.parseLong(loginId.toString()))); return CollectionUtil.newArrayList(permCodes); } /** * 返回指定账号id所拥有的角色标识集合,loginId即登陆时传入的ID * @param loginId 用户ID * @param loginType 账号体系标识 * @return 角色编码集合 */ @Override public List getRoleList(Object loginId, String loginType) { //从redis获取角色数据,在请求getUserInfo接口时会set角色数据 Set roleCodes = redisManager.get(StrUtil.indexedFormat(RedisKeyConstant.USER_ROLE_CACHE_KEY, Long.parseLong(loginId.toString()))); return CollectionUtil.newArrayList(roleCodes); } } ================================================ FILE: minimalist-application/src/main/resources/application-dev.yml ================================================ mybatis-flex: configuration: map-underscore-to-camel-case: true auto-mapping-behavior: full mapper-locations: - classpath*:mappers/**/*.xml global-config: # 逻辑删除字段 logic-delete-column: deleted # 别名包扫描路径 type-aliases-package: com.minimalist.**.entity # springdoc-openapi 项目文档配置 springdoc: title: 极简多租户开发平台 authorName: 小太阳 authorUrl: https://apebbs.cn authorEmail: 438562332@qq.com swagger-ui: path: /swagger-ui.html tags-sorter: alpha operations-sorter: alpha api-docs: path: /v3/api-docs group-configs: - group: '1.全部' paths-to-match: '/**' packages-to-scan: com.minimalist - group: '3.basic基础模块' paths-to-match: '/basic/**' packages-to-scan: com.minimalist.basic # knife4j的增强配置,不需要增强可以不配 knife4j: # 启用增强模式 enable: true setting: language: zh_cn swagger-model-name: 实体说明 spring: datasource: dynamic: primary: master strict: false hikari: # 最小空闲连接数量 minimum-idle: 20 # 连接池最大连接数,默认是10 maximum-pool-size: 100 # 空闲连接存活最大时间,默认600000 idle-timeout: 30000 # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟 max-lifetime: 60000 # 数据库连接超时时间,默认30秒,即30000 connection-timeout: 30000 # 测试连接 connection-test-query: "SELECT 1" datasource: master: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 123456 url: jdbc:mysql://localhost:3306/minimalist?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true&useAffectedRows=true&rewriteBatchedStatements=true servlet: multipart: # 单个文件大小 max-file-size: 100MB # 总文件大小 max-request-size: 256MB data: # redis配置 redis: # Redis数据库索引(默认为0) database: 3 # Redis服务器地址 host: 127.0.0.1 # Redis服务器连接端口 port: 6379 # Redis服务器连接密码(默认为空) password: 1 # 读取超时时间 timeout: 10s # 连接超时时间 connect-timeout: 5s lettuce: pool: enabled: true # 连接池最大连接数 max-active: 200 # 连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # 连接池中的最大空闲连接 max-idle: 10 # 连接池中的最小空闲连接 min-idle: 0 redisson: address: redis://${spring.data.redis.host}:${spring.data.redis.port} password: ${spring.data.redis.password} database: 3 pingInterval: 10000 connectionPoolSize: 100 connectionMinimumIdleSize: 0 # 防XSS,使用说明文档请访问:https://gitee.com/596392912/mica 找到其中的mica-xss中的 README.md 查看 mica: xss: # 开启xss enabled: true # 【全局】是否去除文本首尾空格 trim-text: true # mode有三个模式:clear清理(默认)、escape转义、validate校验, # validate校验模式,校验未通过会抛出异常,可使用全局异常捕获进行处理 # clear模式,会将不允许的数据清理掉 # escape模式,会将不允许的数据转义 # 出错抛出的异常: # json处理默认使用jackson,jackson校验未通过异常:HttpMessageNotReadableException # form表单校验未通过异常:MethodArgumentConversionNotSupportedException mode: clear # 是否保留换行 pretty-print: false # 是否转义 enable-escape: false # 需要拦截的路由 path-patterns: /** # 需要放行的路由,可以配置,也可以使用 @XssCleanIgnore 注解对某个方法和类进行忽略 # 若需要对实体类的某个字段忽略,使用 @JsonDeserialize(using = XssCleanDeserializer.class) 注解忽略 path-exclude-patterns: ############## Sa-Token 配置 (文档: https://sa-token.cc) ############## sa-token: # token 名称,默认:satoken token-name: Authentication # token 有效期(单位:秒) 604800秒=7天,默认2592000秒=30天,-1=永久有效 timeout: 604800 # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 active-timeout: -1 # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录) is-concurrent: true # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) is-share: false # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) token-style: simple-uuid # 是否输出操作日志 is-log: true # 日志配置 logging: level: com.minimalist: debug org.springframework: warn config: classpath:logback-dev.xml ================================================ FILE: minimalist-application/src/main/resources/application.yml ================================================ server: port: 9090 servlet: context-path: /minimalist encoding: charset: UTF-8 force: true spring: profiles: active: @spring.profiles.active@ ================================================ FILE: minimalist-application/src/main/resources/logback-dev.xml ================================================ ${LOG_PATTERN} ${LOG_PATH}/minimalist.log ${LOG_PATH}/minimalist-%d{yyyy-MM-dd}.log 30 ${LOG_PATTERN} ================================================ FILE: minimalist-basic/pom.xml ================================================ minimalist-saas com.cn 1.0.0-SNAPSHOT 4.0.0 minimalist-basic minimalist-basic 基础模块 jar org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-aop com.github.xiaoymin knife4j-openapi3-jakarta-spring-boot-starter ${knife4j.version} mysql mysql-connector-java ${mysql.version} org.projectlombok lombok org.springframework.boot spring-boot-starter-validation cn.dev33 sa-token-spring-boot3-starter ${satoken.version} cn.dev33 sa-token-redis-jackson ${satoken.version} org.apache.commons commons-pool2 org.redisson redisson ${redisson.version} cn.hutool hutool-all ${hutool.version} net.dreamlu mica-xss ${mica-xss.version} net.coobird thumbnailator ${thumbnailator.version} org.sejda.imageio webp-imageio ${webp-imageio.version} com.mybatis-flex mybatis-flex-spring-boot3-starter ${mybatis-flex.version} com.mybatis-flex mybatis-flex-processor ${mybatis-flex.version} provided com.mybatis-flex mybatis-flex-codegen ${mybatis-flex.codegen.version} com.zaxxer HikariCP ${mybatis-flex.hikariCP.version} com.baomidou dynamic-datasource-spring-boot3-starter ${dynamic-datasource.version} com.qiniu qiniu-java-sdk ${qiniu.version} ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/async/AsyncConfig.java ================================================ package com.minimalist.basic.config.async; import org.slf4j.MDC; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; /** * EnableAsync 开启 @Async 支持 * 自定义Async线程池,跨线程传递traceId */ @EnableAsync @Configuration public class AsyncConfig implements AsyncConfigurer { /** * 核心线程数 = cpu核心数 + 1 */ private final int coreSize = Runtime.getRuntime().availableProcessors() + 1; @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(coreSize); executor.setMaxPoolSize(coreSize * 2); executor.setQueueCapacity(100); //队列数 executor.setThreadNamePrefix("Async-Thread-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.setTaskDecorator(runnable -> { Map copyOfContextMap = MDC.getCopyOfContextMap(); return () -> { try { MDC.setContextMap(copyOfContextMap); runnable.run(); } finally { MDC.clear(); } }; }); executor.initialize(); return executor; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/async/ThreadPoolConfig.java ================================================ package com.minimalist.basic.config.async; import org.slf4j.MDC; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.Map; import java.util.concurrent.ThreadPoolExecutor; @Configuration public class ThreadPoolConfig { /** * 核心线程数 = cpu核心数 + 1 */ private final int coreSize = Runtime.getRuntime().availableProcessors() + 1; @Bean(name = "threadPoolExecutor") public ThreadPoolTaskExecutor threadPoolExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(coreSize); executor.setMaxPoolSize(coreSize * 2); executor.setQueueCapacity(100); executor.setThreadNamePrefix("ThreadPool-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.setTaskDecorator(runnable -> { Map copyOfContextMap = MDC.getCopyOfContextMap(); return () -> { try { MDC.setContextMap(copyOfContextMap); runnable.run(); } finally { MDC.clear(); } }; }); executor.initialize(); return executor; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/convert/FileSizeDeserializer.java ================================================ package com.minimalist.basic.config.convert; import cn.hutool.core.io.unit.DataSizeUtil; import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import java.io.IOException; /** * 接收数据时,对String类型的文件大小进行处理 */ public class FileSizeDeserializer extends JsonDeserializer { @Override public Long deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException { String text = jsonParser.getText(); return StrUtil.isBlank(text) ? null : DataSizeUtil.parse(text); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/convert/FileSizeSerializer.java ================================================ package com.minimalist.basic.config.convert; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ObjectUtil; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; /** * 返回数据时,对Long类型的文件大小进行处理 */ public class FileSizeSerializer extends JsonSerializer { @Override public void serialize(Long value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (ObjectUtil.isNotNull(value)) { jsonGenerator.writeString(FileUtil.readableFileSize(value)); } else { jsonGenerator.writeNull(); } } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/convert/LongArrJsonSerializer.java ================================================ package com.minimalist.basic.config.convert; import cn.hutool.core.collection.CollectionUtil; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.util.Collection; /** * 返回数据时,对Long类型的集合转换成String后再返回,防止Long类型精度丢失 */ public class LongArrJsonSerializer extends JsonSerializer> { @Override public void serialize(Collection values, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (CollectionUtil.isNotEmpty(values)) { String [] strArr = values.stream().map(l -> Long.toString(l)).toArray(String[]::new); jsonGenerator.writeArray(strArr, 0, strArr.length); } else { jsonGenerator.writeNull(); } } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/dataConfig/SystemConfigInit.java ================================================ package com.minimalist.basic.config.dataConfig; import com.minimalist.basic.service.ConfigService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; @Component public class SystemConfigInit implements ApplicationRunner { @Autowired private ConfigService configService; @Override public void run(ApplicationArguments args) throws Exception { //初始化将系统参数缓存到Map中 configService.refreshConfigCache(); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/eDict/BeanMethod.java ================================================ package com.minimalist.basic.config.eDict; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.lang.reflect.Method; /** * 存放class和method * @param */ @Data @NoArgsConstructor @AllArgsConstructor public class BeanMethod { /** * class */ private T bean; /** * method */ private Method method; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/eDict/EDict.java ================================================ package com.minimalist.basic.config.eDict; import java.lang.annotation.*; /** * 额外字典数据处理 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EDict { /** * 字典类型 */ String dictType() default ""; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/eDict/EDictConstant.java ================================================ package com.minimalist.basic.config.eDict; import cn.hutool.core.map.MapUtil; import org.springframework.stereotype.Component; import java.util.Map; @Component public class EDictConstant { /** 存储额外字典数据处理的方法 */ public static final Map> dictMethodMap = MapUtil.newConcurrentHashMap(); /** 部门字典type */ public static final String DEPT_LIST = "dict-dept-list"; /** 岗位字典type */ public static final String POST_LIST = "dict-post-list"; /** 角色字典type */ public static final String ROLE_LIST = "dict-role-list"; /** 用户字典type */ public static final String USER_LIST = "dict-user-list"; /** 租户字典type */ public static final String TENANT_LIST = "dict-tenant-list"; /** 租户套餐字典type */ public static final String TENANT_PACKAGE_LIST = "tenant-package-list"; /** 存储方式字典type */ public static final String STORAGE_LIST = "storage-list"; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/eDict/EDictInit.java ================================================ package com.minimalist.basic.config.eDict; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.context.ApplicationContext; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; /** * 额外字典处理,初始化加载字典处理方法 */ @Order(-1) @Component public class EDictInit implements ApplicationRunner { @Autowired private ApplicationContext applicationContext; @Override public void run(ApplicationArguments args) throws Exception { String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); //getBean,找到含有额外字典处理的注解方法 for (String beanDefinitionName : beanDefinitionNames) { Object bean = applicationContext.getBean(beanDefinitionName); postProcessAfterInitialization(bean); } System.out.println("-------------------- 初始化自定义字典完毕 --------------------"); } public void postProcessAfterInitialization(Object bean) { //Spring代理类中的方法 Method[] proxyMethods = bean.getClass().getDeclaredMethods(); //Spring代理类中的方法转Map,key:方法名,value:代理方法 Map proxyMethodMap = Arrays.stream(proxyMethods).collect(Collectors.toMap(Method::getName, Function.identity(), (v1, v2) -> v1)); //判断是否是cglib动态代理 boolean cglibProxy = AopUtils.isCglibProxy(bean); if (cglibProxy) { //获取Spring代理类,再获取代理目标类 Class superclass = bean.getClass().getSuperclass(); //获取代理目标类中的方法,目的是为了获取到 ExtraDict 自定义注解 Method[] methods = superclass.getDeclaredMethods(); for (Method method : methods) { cacheBeanMethod(method, proxyMethodMap, bean); } } else { //不是cglib动态代理,可能是其他代理,暂时还没遇到其他代理扫描不到的情况 for (Method method : proxyMethods) { cacheBeanMethod(method, proxyMethodMap, bean); } } } private void cacheBeanMethod(Method method, Map proxyMethodMap, Object bean) { //获取自定义注解 EDict eDict = method.getDeclaredAnnotation(EDict.class); if (ObjectUtil.isNotNull(eDict) && StrUtil.isNotBlank(eDict.dictType())) { //从代理方法中查找并缓存代理方法,如果代理方法不存在,则缓存代理目标类方法 Method proxyMethod = proxyMethodMap.get(method.getName()); if (ObjectUtil.isNotNull(proxyMethod)) { EDictConstant.dictMethodMap.put(eDict.dictType(), new BeanMethod<>(bean, proxyMethod)); } else { EDictConstant.dictMethodMap.put(eDict.dictType(), new BeanMethod<>(bean, method)); } } } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/exception/BusinessException.java ================================================ package com.minimalist.basic.config.exception; import com.minimalist.basic.entity.enums.RespEnum; import lombok.Data; import java.io.Serializable; @Data public class BusinessException extends RuntimeException implements Serializable { private static final long serialVersionUID = 1L; /** 状态码 */ private Integer code; /** 异常信息 */ private String message; public BusinessException(Integer code, String message) { this.code = code; this.message = message; } public BusinessException(String message) { this.code = RespEnum.FAILED.getCode(); this.message = message; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/fileHandler/FileManager.java ================================================ package com.minimalist.basic.config.fileHandler; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.fileHandler.handler.FileHandler; import com.minimalist.basic.entity.po.MDict; import com.minimalist.basic.mapper.MDictMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; import java.util.Map; import java.util.Optional; @Component public class FileManager { @Autowired private ApplicationContext applicationContext; @Autowired private MDictMapper dictMapper; /** * 根据存储类型获取对应的处理类 * @param storageType 存储类型 * @return 处理类 */ public FileHandler getFileHandler(String storageType) { if (StrUtil.isBlank(storageType)) { throw new BusinessException("处理文件时,存储平台参数为空"); } Map beansMaps = applicationContext.getBeansOfType(FileHandler.class); if (MapUtil.isEmpty(beansMaps)) { throw new BusinessException("处理文件时,未找到指定的处理方法"); } return beansMaps.values().stream() .filter(bean -> bean.isHandler(storageType)) .findFirst() .orElseThrow(() -> new BusinessException("未找到 [" + storageType + "] 的处理方法")); } /** * 根据文件来源获取存储路径 * @param fileSource 文件来源 * @return 路径 */ public String getPathByFileSource(Integer fileSource) { MDict dict = dictMapper.selectDictByDictTypeAndKey("file-source-path", String.valueOf(fileSource)); return Optional.ofNullable(dict) .map(MDict::getDictValue) .orElse("common/"); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/fileHandler/FileResourcesInit.java ================================================ package com.minimalist.basic.config.fileHandler; import cn.hutool.json.JSONUtil; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.fileHandler.entity.LocalFileEntity; import com.minimalist.basic.entity.enums.StorageEnum; import com.minimalist.basic.entity.po.MStorage; import com.minimalist.basic.mapper.MStorageMapper; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; /** * 静态资源目录映射,只有本地存储需要映射,启动后执行一次 * 如果在存储管理中,修改了本地存储的文件存储路径,那么程序需要重启才可以生效 */ @Order(-1) @Configuration public class FileResourcesInit implements WebMvcConfigurer { @Autowired private MStorageMapper storageMapper; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { //查询本地存储 List storageList = storageMapper.selectListByQuery(QueryWrapper.create() .eq(MStorage::getStorageType, StorageEnum.StorageType.LOCAL.getCode()) .eq(MStorage::getStatus, StatusEnum.STATUS_1.getCode()) ); for (MStorage storage : storageList) { LocalFileEntity localFileEntity = JSONUtil.toBean(storage.getStorageConfig(), LocalFileEntity.class); registry.addResourceHandler("/files/**").addResourceLocations("file:" + localFileEntity.getStoragePath()); } System.out.println("-------------------- 初始化静态资源映射完毕 --------------------"); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/fileHandler/entity/LocalFileEntity.java ================================================ package com.minimalist.basic.config.fileHandler.entity; import jakarta.validation.constraints.NotBlank; import lombok.Data; @Data public class LocalFileEntity { @NotBlank(message = "本地存储路径不能为空") private String storagePath; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/fileHandler/entity/MinIOFileEntity.java ================================================ package com.minimalist.basic.config.fileHandler.entity; import jakarta.validation.constraints.NotBlank; import lombok.Data; @Data public class MinIOFileEntity { @NotBlank(message = "访问密钥不能为空") private String accessKey; @NotBlank(message = "私有密钥不能为空") private String secretKey; @NotBlank(message = "域名不能为空") private String endPoint; @NotBlank(message = "桶名称不能为空") private String bucketName; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/fileHandler/entity/QiNiuFileEntity.java ================================================ package com.minimalist.basic.config.fileHandler.entity; import jakarta.validation.constraints.NotBlank; import lombok.Data; @Data public class QiNiuFileEntity { @NotBlank(message = "访问密钥不能为空") private String accessKey; @NotBlank(message = "私有密钥不能为空") private String secretKey; @NotBlank(message = "桶名称不能为空") private String bucketName; @NotBlank(message = "域名不能为空") private String endPoint; @NotBlank(message = "七牛云存储区域ID不能为空") private String regionId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/fileHandler/handler/FileHandler.java ================================================ package com.minimalist.basic.config.fileHandler.handler; import com.minimalist.basic.entity.po.MFile; import com.minimalist.basic.entity.po.MStorage; import org.springframework.web.multipart.MultipartFile; public interface FileHandler { /** * 是否是对应的处理类 * @param storageType 存储类型 * @return 处理类 */ boolean isHandler(String storageType); /** * 参数校验 * @param storageConfig JSON存储配置信息 * @return 格式化后的配置信息 */ String valid(String storageConfig); /** * 单文件上传 * @param multipartFile 文件 * @param fileSource 文件来源 * @param storage 存储信息 * @return 文件信息 */ MFile uploadFile(MultipartFile multipartFile, Integer fileSource, MStorage storage); /** * 删除文件 * @param file 文件信息 * @return 是否删除成功 */ boolean deleteFile(MFile file, MStorage storage); /** * 移动文件 * @param file 文件信息 * @param storage 存储信息 * @return 是否成功 */ boolean moveFile(MFile file, MStorage storage); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/fileHandler/handler/impl/LocalFileHandler.java ================================================ package com.minimalist.basic.config.fileHandler.handler.impl; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.file.FileNameUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.fileHandler.FileManager; import com.minimalist.basic.config.fileHandler.entity.LocalFileEntity; import com.minimalist.basic.config.fileHandler.handler.FileHandler; import com.minimalist.basic.entity.enums.FileEnum; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.enums.StorageEnum; import com.minimalist.basic.entity.po.MFile; import com.minimalist.basic.entity.po.MStorage; import com.minimalist.basic.mapper.MFileMapper; import com.minimalist.basic.mapper.MStorageMapper; import com.minimalist.basic.utils.CommonConstant; import com.minimalist.basic.utils.UnqIdUtil; import com.minimalist.basic.utils.ValidateUtil; import com.mybatisflex.core.query.QueryWrapper; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import net.coobird.thumbnailator.Thumbnails; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.time.LocalDateTime; @Slf4j @Service public class LocalFileHandler implements FileHandler { @Value("${server.servlet.context-path}") private String contextPath; @Autowired private FileManager fileManager; @Autowired private MFileMapper fileMapper; @Autowired private MStorageMapper storageMapper; /** * 是否是对应的处理类 * @param storageType 存储类型 * @return 处理类 */ @Override public boolean isHandler(String storageType) { return StorageEnum.StorageType.LOCAL.getCode().equals(storageType); } /** * 参数校验 * @param storageConfig JSON存储配置信息 */ @Override public String valid(String storageConfig) { LocalFileEntity localFileEntity = JSONUtil.toBean(storageConfig, LocalFileEntity.class); ValidateUtil.valid(localFileEntity); //格式化路径 String normalize = FileUtil.normalize(localFileEntity.getStoragePath()); localFileEntity.setStoragePath(normalize); return JSONUtil.toJsonStr(localFileEntity); } /** * 单文件上传 * @param multipartFile 文件 * @param fileSource 文件来源 * @param storage 存储信息 * @return 文件信息 */ @Override public MFile uploadFile(MultipartFile multipartFile, Integer fileSource, MStorage storage) { //根据文件来源,获取相对路径 String fileSourcePath = fileManager.getPathByFileSource(fileSource); //本地存储路径 LocalFileEntity localFileEntity = JSONUtil.toBean(storage.getStorageConfig(), LocalFileEntity.class); String storagePath = localFileEntity.getStoragePath(); //文件后缀 String fileSuffix = FileNameUtil.extName(multipartFile.getOriginalFilename()); //新文件名 String newFileName = IdUtil.objectId() + "." + fileSuffix; //拼接路径 String path = FileUtil.normalize(storagePath + "/" + fileSourcePath + newFileName); //request请求信息 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + contextPath + "/files/"; //返回的文件信息 MFile fileInfo = new MFile(); fileInfo.setFileId(UnqIdUtil.uniqueId()); fileInfo.setFileName(multipartFile.getOriginalFilename()); fileInfo.setNewFileName(newFileName); fileInfo.setFileSize(multipartFile.getSize()); fileInfo.setFileType(multipartFile.getContentType()); fileInfo.setFileBasePath(storagePath); fileInfo.setFilePath(FileUtil.normalize(storagePath + "/" + fileSourcePath)); fileInfo.setFileUrl(url + fileSourcePath + newFileName); fileInfo.setFileSource(fileSource); fileInfo.setStorageId(storage.getStorageId()); //如果未指定文件来源,将状态置为正常 //因为这是从文件选择组件中上传的文件,不置为正常,在选择文件时查询条件是正常的才能被查出来 if (fileSource < CommonConstant.ZERO) { fileInfo.setStatus(StatusEnum.STATUS_1.getCode()); } try { log.info("上传文件,路径:{}", path); File file = FileUtil.touch(path); multipartFile.transferTo(file); if (StrUtil.isNotBlank(multipartFile.getContentType()) && multipartFile.getContentType().contains("image")) { //如果是图片,生成缩略图 String thFileName = "thumbnail-" + newFileName; String thPath = FileUtil.normalize(storagePath + "/" + fileSourcePath + "/" + thFileName); File thFile = FileUtil.touch(thPath); Thumbnails.of(file) .scale(0.4) .toFile(thFile); fileInfo.setFileThUrl(url + fileSourcePath + thFileName); fileInfo.setFileThFilename(thFileName); fileInfo.setFileThSize(thFile.length()); } } catch (IOException e) { FileUtil.del(path); log.warn("上传文件,异常:", e); throw new BusinessException(FileEnum.ErrorMsg.FILE_UPLOAD_FAIL.getDesc()); } return fileInfo; } /** * 删除文件 * @param file 文件信息 * @return 是否删除成功 */ @Override public boolean deleteFile(MFile file, MStorage storage) { String filePath = file.getFilePath() + file.getNewFileName(); boolean result = FileUtil.del(filePath); //如果有缩略图,删除缩略图 if (StrUtil.isNotBlank(file.getFileThFilename())) { String fileThPath = file.getFilePath() + file.getFileThFilename(); FileUtil.del(fileThPath); } return result; } /** * 移动文件 * @param file 文件信息 * @param storage 存储信息 * @return 是否成功 */ @Override public boolean moveFile(MFile file, MStorage storage) { //根据文件来源,获取相对路径 String fileSourcePath = fileManager.getPathByFileSource(file.getFileSource()); //本地存储路径 LocalFileEntity localFileEntity = JSONUtil.toBean(storage.getStorageConfig(), LocalFileEntity.class); String storagePath = localFileEntity.getStoragePath(); //request请求信息 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + contextPath + "/files/"; //源文件路径 Path sourcePath = Paths.get(FileUtil.normalize(file.getFilePath() + "/" + file.getNewFileName())); //目标文件路径 Path targetPath = Paths.get(FileUtil.normalize(storagePath + "/" + fileSourcePath + "/" + file.getNewFileName())); try { FileUtil.move(sourcePath, targetPath, true); //修改文件url file.setFileUrl(url + fileSourcePath + file.getNewFileName()); //如果有缩略图,需要将缩略图移动 if (StrUtil.isNotBlank(file.getFileThFilename())) { //源文件路径 Path sourcePathTh = Paths.get(FileUtil.normalize(file.getFilePath() + "/" + file.getFileThFilename())); //目标文件路径 Path targetPathTh = Paths.get(FileUtil.normalize(storagePath + "/" + fileSourcePath + "/" + file.getFileThFilename())); //移动缩略图 FileUtil.move(sourcePathTh, targetPathTh, true); //修改缩略图url file.setFileThUrl(url + fileSourcePath + file.getFileThFilename()); } //修改文件路径 file.setFilePath(FileUtil.normalize(storagePath + "/" + fileSourcePath)); return true; } catch (Exception e) { log.warn("移动文件,异常:", e); } return false; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/fileHandler/handler/impl/MinIOFileHandler.java ================================================ package com.minimalist.basic.config.fileHandler.handler.impl; import cn.hutool.json.JSONUtil; import com.minimalist.basic.config.fileHandler.entity.MinIOFileEntity; import com.minimalist.basic.config.fileHandler.handler.FileHandler; import com.minimalist.basic.entity.enums.StorageEnum; import com.minimalist.basic.entity.po.MFile; import com.minimalist.basic.entity.po.MStorage; import com.minimalist.basic.utils.ValidateUtil; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @Service public class MinIOFileHandler implements FileHandler { /** * 是否是对应的处理类 * @param storageType 存储类型 * @return 处理类 */ @Override public boolean isHandler(String storageType) { return StorageEnum.StorageType.MINIO.getCode().equals(storageType); } /** * 参数校验 * @param storageConfig JSON存储配置信息 */ @Override public String valid(String storageConfig) { MinIOFileEntity minIOFileEntity = JSONUtil.toBean(storageConfig, MinIOFileEntity.class); ValidateUtil.valid(minIOFileEntity); return storageConfig; } /** * 单文件上传 * @param multipartFile 文件 * @param fileSource 文件来源 * @param storage 存储信息 * @return 文件信息 */ @Override public MFile uploadFile(MultipartFile multipartFile, Integer fileSource, MStorage storage) { //没做,做了需要引jar包,可自行实现 return null; } /** * 删除文件 * @param file 文件信息 * @return 是否删除成功 */ @Override public boolean deleteFile(MFile file, MStorage storage) { //没做,做了需要引jar包,可自行实现 return false; } /** * 移动文件 * @param file 文件信息 * @param storage 存储信息 * @return 是否成功 */ @Override public boolean moveFile(MFile file, MStorage storage) { //没做,做了需要引jar包,可自行实现 return false; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/fileHandler/handler/impl/QiNiuFileHandler.java ================================================ package com.minimalist.basic.config.fileHandler.handler.impl; import cn.hutool.core.io.file.FileNameUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.fileHandler.FileManager; import com.minimalist.basic.config.fileHandler.entity.QiNiuFileEntity; import com.minimalist.basic.config.fileHandler.handler.FileHandler; import com.minimalist.basic.entity.enums.FileEnum; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.enums.StorageEnum; import com.minimalist.basic.entity.po.MFile; import com.minimalist.basic.entity.po.MStorage; import com.minimalist.basic.mapper.MFileMapper; import com.minimalist.basic.mapper.MStorageMapper; import com.minimalist.basic.utils.*; import com.qiniu.common.QiniuException; import com.qiniu.http.Response; import com.qiniu.storage.BucketManager; import com.qiniu.storage.Configuration; import com.qiniu.storage.Region; import com.qiniu.storage.UploadManager; import com.qiniu.util.Auth; import com.qiniu.util.StringMap; import lombok.extern.slf4j.Slf4j; import net.coobird.thumbnailator.Thumbnails; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayOutputStream; @Slf4j @Service public class QiNiuFileHandler implements FileHandler { @Autowired private FileManager fileManager; @Autowired private MFileMapper fileMapper; @Autowired private MStorageMapper storageMapper; /** * 是否是对应的处理类 * @param storageType 存储类型 * @return 处理类 */ @Override public boolean isHandler(String storageType) { return StorageEnum.StorageType.QINIU.getCode().equals(storageType); } /** * 参数校验 * @param storageConfig JSON存储配置信息 */ @Override public String valid(String storageConfig) { QiNiuFileEntity qiNiuFileEntity = JSONUtil.toBean(storageConfig, QiNiuFileEntity.class); ValidateUtil.valid(qiNiuFileEntity); return storageConfig; } /** * 单文件上传 * @param multipartFile 文件 * @param fileSource 文件来源 * @param storage 存储信息 * @return 文件信息 */ @Override public MFile uploadFile(MultipartFile multipartFile, Integer fileSource, MStorage storage) { //根据文件来源,获取相对路径 String fileSourcePath = fileManager.getPathByFileSource(fileSource); //文件后缀 String fileSuffix = FileNameUtil.extName(multipartFile.getOriginalFilename()); //新文件名 String newFileName = IdUtil.objectId() + "." + fileSuffix; //文件信息 QiNiuFileEntity qnConfig = JSONUtil.toBean(storage.getStorageConfig(), QiNiuFileEntity.class); MFile fileInfo = new MFile(); fileInfo.setFileId(UnqIdUtil.uniqueId()); fileInfo.setFileName(multipartFile.getOriginalFilename()); fileInfo.setNewFileName(newFileName); fileInfo.setFileSize(multipartFile.getSize()); fileInfo.setFileType(multipartFile.getContentType()); //基础路径 = 租户ID String basePath = String.valueOf(TenantUtil.getTenantId()); fileInfo.setFileBasePath(basePath); String fileKey = basePath + "/" + fileSourcePath + newFileName; fileInfo.setFilePath(basePath + "/" + fileSourcePath); fileInfo.setFileUrl(TextUtil.urlNormalize(qnConfig.getEndPoint() + "/" + fileKey)); fileInfo.setFileSource(fileSource); fileInfo.setStorageId(storage.getStorageId()); //如果未指定文件来源,将状态置为正常 //因为这是从文件选择组件中上传的文件,不置为正常,在选择文件时查询条件是正常的才能被查出来 if (fileSource < CommonConstant.ZERO) { fileInfo.setStatus(StatusEnum.STATUS_1.getCode()); } try { Auth auth = Auth.create(qnConfig.getAccessKey(), qnConfig.getSecretKey()); String upToken = auth.uploadToken(qnConfig.getBucketName()); Configuration cfg = new Configuration(Region.createWithRegionId(qnConfig.getRegionId())); UploadManager uploadManager = new UploadManager(cfg); StringMap params = new StringMap(); params.put("tenantId", basePath); Response response = uploadManager.put(multipartFile.getInputStream(), fileKey, upToken, params, null); if (!response.isOK()) { log.error("上传文件失败:{}", JSONUtil.toJsonStr(response)); throw new BusinessException(FileEnum.ErrorMsg.FILE_UPLOAD_FAIL.getDesc()); } //生成图片缩略图 if (StrUtil.isNotBlank(multipartFile.getContentType()) && multipartFile.getContentType().contains("image")) { ByteArrayOutputStream thumbnailOutputStream = new ByteArrayOutputStream(); Thumbnails.of(multipartFile.getInputStream()) .scale(0.4) .toOutputStream(thumbnailOutputStream); byte[] fileByte = thumbnailOutputStream.toByteArray(); String thFileName = "thumbnail-" + newFileName; String thumbnailsFileKey = basePath + "/" + fileSourcePath + thFileName; Response thumbnailsResponse = uploadManager.put(fileByte, thumbnailsFileKey, upToken, params, null, false); if (thumbnailsResponse.isOK()) { fileInfo.setFileThUrl(qnConfig.getEndPoint() + "/" + thumbnailsFileKey); fileInfo.setFileThFilename(thFileName); fileInfo.setFileThSize((long) fileByte.length); } else { log.error("上传缩略图失败:{}", JSONUtil.toJsonStr(thumbnailsResponse)); throw new BusinessException(FileEnum.ErrorMsg.FILE_THUMBNAILS_UPLOAD_FAIL.getDesc()); } } } catch (Exception e) { //删除刚上传的图片 deleteFile(fileInfo, storage); log.error("上传文件,异常:", e); throw new BusinessException(FileEnum.ErrorMsg.FILE_UPLOAD_FAIL.getDesc()); } return fileInfo; } /** * 删除文件 * @param file 文件信息 * @return 是否删除成功 */ @Override public boolean deleteFile(MFile file, MStorage storage) { try { QiNiuFileEntity qnConfig = JSONUtil.toBean(storage.getStorageConfig(), QiNiuFileEntity.class); Auth auth = Auth.create(qnConfig.getAccessKey(), qnConfig.getSecretKey()); Configuration cfg = new Configuration(Region.createWithRegionId(qnConfig.getRegionId())); BucketManager bucketManager = new BucketManager(auth, cfg); Response response = bucketManager.delete(qnConfig.getBucketName(), file.getFilePath() + file.getNewFileName()); if (!response.isOK()) { log.warn("删除文件失败:{}", JSONUtil.toJsonStr(response)); return false; } //如果存在缩略图,删除 if (StrUtil.isNotBlank(file.getFileThFilename())) { //删除缩略图 bucketManager.delete(qnConfig.getBucketName(), file.getFilePath() + file.getFileThFilename()); } return true; } catch (Exception e) { log.error("删除文件失败:", e); } return false; } /** * 移动文件 * @param file 文件信息 * @param storage 存储信息 * @return 是否成功 */ public boolean moveFile(MFile file, MStorage storage) { try { QiNiuFileEntity qnConfig = JSONUtil.toBean(storage.getStorageConfig(), QiNiuFileEntity.class); Auth auth = Auth.create(qnConfig.getAccessKey(), qnConfig.getSecretKey()); Configuration cfg = new Configuration(Region.createWithRegionId(qnConfig.getRegionId())); BucketManager bucketManager = new BucketManager(auth, cfg); //源文件名 String fromKey = file.getFilePath() + file.getNewFileName(); //基础路径 = 租户ID String basePath = String.valueOf(TenantUtil.getTenantId()); //根据文件来源,获取相对路径 String fileSourcePath = fileManager.getPathByFileSource(file.getFileSource()); //目标文件名 String toKey = basePath + "/" + fileSourcePath + file.getNewFileName(); //移动文件 Response response = bucketManager.move(qnConfig.getBucketName(), fromKey, qnConfig.getBucketName(), toKey, true); if (!response.isOK()) { log.warn("移动文件失败:{}", JSONUtil.toJsonStr(response)); return false; } //修改文件url file.setFileUrl(TextUtil.urlNormalize(qnConfig.getEndPoint() + "/" + toKey)); //如果有缩略图,需要将缩略图移动 if (StrUtil.isNotBlank(file.getFileThFilename())) { //源文件名 String fromKeyTh = file.getFilePath() + file.getFileThFilename(); //目标文件名 String toKeyTh = basePath + "/" + fileSourcePath + file.getFileThFilename(); //移动文件 Response responseTh = bucketManager.move(qnConfig.getBucketName(), fromKeyTh, qnConfig.getBucketName(), toKeyTh, true); if (!responseTh.isOK()) { log.warn("移动文件失败:{}", JSONUtil.toJsonStr(responseTh)); return false; } //修改缩略图url file.setFileThUrl(TextUtil.urlNormalize(qnConfig.getEndPoint() + "/" + toKeyTh)); } //修改文件路径 file.setFilePath(basePath + "/" + fileSourcePath); return true; } catch (QiniuException ex) { log.error("移动文件失败,错误码:{},错误信息:{}", ex.code(), ex.response.toString()); log.error("移动文件失败:", ex); } catch (Exception e) { log.error("移动文件失败:", e); } return false; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/mybatis/GeneratorCodeHandler.java ================================================ package com.minimalist.basic.config.mybatis; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.codegen.Generator; import com.mybatisflex.codegen.config.GlobalConfig; import com.mybatisflex.codegen.config.TableConfig; import com.zaxxer.hikari.HikariDataSource; /** * 配置Mybatis-Flex生成代码 */ public class GeneratorCodeHandler { public static final String url = "jdbc:mysql://127.0.0.1:3306/minimalist?characterEncoding=utf-8"; public static final String username = "root"; public static final String password = "123456"; public static void main(String[] args) { //配置数据源 HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); //项目根目录 String projectPath = System.getProperty("user.dir"); //生成配置 GlobalConfig globalConfig = new GlobalConfig(); //设置根包 globalConfig.setBasePackage("com.minimalist.basic"); //生成路径 globalConfig.setSourceDir(projectPath + "\\generator\\java"); /* ------------------------ 实体配置 ------------------------ */ //生成实体 globalConfig.setEntityGenerateEnable(true); //使用lombok globalConfig.setEntityWithLombok(true); //设置项目的JDK版本,项目的JDK为14及以上时建议设置该项,小于14则可以不设置 globalConfig.setEntityJdkVersion(17); //设置生成 entity 包名 globalConfig.setEntityPackage("com.minimalist.basic.entity.po"); //自动填充 TableConfig tableConfig = new TableConfig(); tableConfig.setInsertListenerClass(InsertFullColumnHandler.class); tableConfig.setUpdateListenerClass(UpdateFullColumnHandler.class); globalConfig.setTableConfig(tableConfig); //设置实体类的父类 globalConfig.setEntitySuperClass(BaseEntity.class); //父类字段忽略 globalConfig.getStrategyConfig() .setIgnoreColumns("id", "deleted", "create_time", "create_id", "update_id", "update_time", "version"); /* ------------------------ mapper 配置 ------------------------ */ //设置生成 mapper globalConfig.setMapperGenerateEnable(true); //mapper包 globalConfig.setMapperPackage("com.minimalist.basic.mapper"); //生成mapper xml文件 globalConfig.enableMapperXml(); //生成mapper.xml路径 globalConfig.setMapperXmlPath(projectPath + "/generator/resources/mapper"); /* ------------------------ 生成哪些表 ------------------------ */ globalConfig.setGenerateTable( "m_config", "m_dept", "m_dict", "m_file", "m_notice", "m_perms", "m_post", "m_role", "m_role_dept", "m_role_perm", "m_storage", "m_tenant", "m_tenant_package", "m_tenant_package_perm", "m_user", "m_user_dept", "m_user_post", "m_user_role" ); //是否生成service和controller globalConfig.setServiceGenerateEnable(true); globalConfig.setServiceImplGenerateEnable(true); globalConfig.setControllerGenerateEnable(true); //通过 datasource 和 globalConfig 创建代码生成器 Generator generatorHandler = new Generator(dataSource, globalConfig); generatorHandler.generate(); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/mybatis/InsertFullColumnHandler.java ================================================ package com.minimalist.basic.config.mybatis; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.util.ObjectUtil; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.minimalist.basic.utils.CommonConstant; import com.mybatisflex.annotation.InsertListener; import org.springframework.stereotype.Component; /** * Mybatis-Flex 插入时字段自动填充。注:xml中和Db+Row插入不会生效需要手动set */ @Component public class InsertFullColumnHandler implements InsertListener { @Override public void onInsert(Object entity) { BaseEntity t = (BaseEntity) entity; SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); if (ObjectUtil.isNotNull(tokenInfo) && ObjectUtil.isNotNull(tokenInfo.getLoginId())) { long userId = Long.parseLong(tokenInfo.getLoginId().toString()); t.setCreateId(userId); t.setUpdateId(userId); } else { t.setCreateId((long) CommonConstant.ZERO); t.setUpdateId((long) CommonConstant.ZERO); } } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/mybatis/MyBatisFlexConfiguration.java ================================================ package com.minimalist.basic.config.mybatis; import com.minimalist.basic.utils.TenantUtil; import com.mybatisflex.core.audit.AuditManager; import com.mybatisflex.core.tenant.TenantManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; @Configuration public class MyBatisFlexConfiguration { private static final Logger logger = LoggerFactory.getLogger("mybatis-flex-sql"); public MyBatisFlexConfiguration() { //开启审计功能 AuditManager.setAuditEnable(true); //设置 SQL 审计收集器 AuditManager.setMessageCollector(auditMessage -> logger.info("{},{} ms", auditMessage.getFullSql(), auditMessage.getElapsedTime()) ); //获取租户ID,目前支持返回一个租户ID TenantManager.setTenantFactory(() -> { //校验系统多租户是否开启 if (!TenantUtil.checkTenantOnOff()) { //未打开,忽略多租户 return null; } //放回当前要操作的租户ID return new Object[]{ TenantUtil.getTenantId() }; }); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/mybatis/UpdateFullColumnHandler.java ================================================ package com.minimalist.basic.config.mybatis; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.util.ObjectUtil; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.minimalist.basic.utils.CommonConstant; import com.mybatisflex.annotation.UpdateListener; import org.springframework.stereotype.Component; /** * Mybatis-Flex 修改时字段自动填充。注:xml中和Db+Row插入不会生效需要手动set */ @Component public class UpdateFullColumnHandler implements UpdateListener { @Override public void onUpdate(Object entity) { BaseEntity t = (BaseEntity) entity; SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); if (ObjectUtil.isNotNull(tokenInfo) && ObjectUtil.isNotNull(tokenInfo.getLoginId())) { long userId = Long.parseLong(tokenInfo.getLoginId().toString()); t.setUpdateId(userId); } else { t.setUpdateId((long) CommonConstant.ZERO); } } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/mybatis/bo/BaseEntity.java ================================================ package com.minimalist.basic.config.mybatis.bo; import com.mybatisflex.annotation.Column; import com.mybatisflex.annotation.Id; import com.mybatisflex.annotation.KeyType; import lombok.Getter; import lombok.Setter; import java.time.LocalDateTime; @Getter @Setter public class BaseEntity { /** ID自增 */ @Id(keyType = KeyType.Auto) private Long id; /** 逻辑删除 */ @Column(isLogicDelete = true) private Boolean deleted; /** 创建人ID */ private Long createId; /** 更新人ID */ private Long updateId; /** 创建时间 */ @Column(onInsertValue = "now()") private LocalDateTime createTime; /** 更新时间 */ @Column(onInsertValue = "now()", onUpdateValue = "now()") private LocalDateTime updateTime; /** 版本号 */ @Column(version = true, onInsertValue = "0", onUpdateValue = "version + 1") private Integer version; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/mybatis/bo/PageReq.java ================================================ package com.minimalist.basic.config.mybatis.bo; import lombok.Getter; import lombok.Setter; /** * 分页请求 */ @Getter @Setter public class PageReq { /** 页码 */ private Long pageNum = 1L; /** 分页条数 默认10条 */ private Long pageSize = 10L; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/mybatis/bo/PageResp.java ================================================ package com.minimalist.basic.config.mybatis.bo; import lombok.AllArgsConstructor; import lombok.Data; import java.util.Collections; import java.util.List; /** * 分页响应 */ @Data @AllArgsConstructor public class PageResp { /** 数据 */ private List records = Collections.emptyList(); /** 总条数 */ private long total = 0; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/redis/RedisManager.java ================================================ package com.minimalist.basic.config.redis; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RBucket; import org.redisson.api.RLock; import org.redisson.api.RTopic; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.concurrent.TimeUnit; @Slf4j @Component public class RedisManager { @Autowired private RedissonClient redissonClient; /** * 获取缓存 * @param key 缓存key * @param 泛型 * @return 泛型 */ public T get(String key) { RBucket bucket = redissonClient.getBucket(key); return bucket.get(); } /** * 获取缓存 并删除 * @param key 缓存key * @param 泛型 * @return 泛型 */ public T getAndDelete(String key) { RBucket bucket = redissonClient.getBucket(key); return bucket.getAndDelete(); } /** * 删除缓存 * @param key 缓存key */ public void delete(String key) { redissonClient.getBucket(key).delete(); } /** * 存放缓存 * @param key 缓存key * @param value 缓存value * @param seconds 过期时间: 秒 * @param 泛型 */ public void set(String key, T value, int seconds) { RBucket bucket = redissonClient.getBucket(key); bucket.set(value, seconds, TimeUnit.SECONDS); } /** * 获取分布式锁 * @param key 缓存key * @param waitTime 获取锁时等待的时间 * @param leaseTime 持有锁的时间 * @return true获取到锁,false未获取到 */ public boolean tryLock(String key, long waitTime, long leaseTime) { RLock lock = redissonClient.getLock(key); try { return lock.tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { log.error("尝试获取分布式锁异常:", e); } return false; } /** * 释放锁 * @param key 缓存key */ public void unLock(String key) { RLock lock = redissonClient.getLock(key); //检查是否已加锁,已加锁返回true if (lock.isLocked()) { //检查是否是当前线程加的锁,是同一线程则释放锁 if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } /** * 随机秒数 * @return 秒数 */ public int randomSeconds() { return BigDecimal.valueOf(Math.random()).multiply(new BigDecimal(20)).intValue(); } /** * 发布消息 * @param topic 主题 * @param message 消息 */ public void publishMessage(String topic, String message) { RTopic rTopic = redissonClient.getTopic(topic); rTopic.publish(message); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/redis/RedissonConfiguration.java ================================================ package com.minimalist.basic.config.redis; import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.codec.JsonJacksonCodec; import org.redisson.config.Config; import org.redisson.config.SingleServerConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; @Configuration public class RedissonConfiguration { @Autowired private Environment environment; /** * redisson单节点 * @return RedissonClient */ @Bean public RedissonClient getSingleRedissonClient() { Config config = new Config(); String address = environment.getProperty("redisson.address"); String password = environment.getProperty("redisson.password"); Integer pingInterval = environment.getProperty("redisson.pingInterval", Integer.class); Integer connectionPoolSize = environment.getProperty("redisson.connectionPoolSize", Integer.class); Integer connectionMinimumIdleSize = environment.getProperty("redisson.connectionMinimumIdleSize", Integer.class); Integer database = environment.getProperty("redisson.database", Integer.class); SingleServerConfig singleServerConfig = config.useSingleServer() .setAddress(address) .setKeepAlive(true) .setDatabase(database) .setConnectionPoolSize(connectionPoolSize) .setConnectionMinimumIdleSize(connectionMinimumIdleSize) .setPingConnectionInterval(pingInterval); if (StrUtil.isNotBlank(password)) { singleServerConfig.setPassword(password); } //设置redisson序列化与反序列化,jackson增加java时间模块处理 JsonJacksonCodec jsonJacksonCodec = new JsonJacksonCodec(); ObjectMapper objectMapper = jsonJacksonCodec.getObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); config.setCodec(jsonJacksonCodec); return Redisson.create(config); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/resubmit/ReSubmit.java ================================================ package com.minimalist.basic.config.resubmit; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ReSubmit { /** * 持有锁的租期时间 * 第一次请求和第二次请求,时间相隔 leaseTime 毫秒算重复请求,将被拒绝 */ long leaseTime() default 3000; /** * 获取锁时,等待 waitTime 毫秒,超过 waitTimeout 毫秒,就不再尝试获取锁 * 默认 0 不等待,即获取锁时只要获取不到就返回 */ long waitTime() default 0; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/resubmit/ReSubmitAspect.java ================================================ package com.minimalist.basic.config.resubmit; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.extra.servlet.JakartaServletUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.minimalist.basic.config.redis.RedisManager; import com.minimalist.basic.entity.enums.RespEnum; import com.minimalist.basic.utils.RedisKeyConstant; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.Comparator; import java.util.TreeMap; /** * 防重复提交处理 */ @Slf4j @Aspect @Component public class ReSubmitAspect { @Autowired private RedisManager redisManager; @Around("@annotation(re)") public Object around(ProceedingJoinPoint joinPoint, ReSubmit re) throws Throwable { Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); ReSubmit reSubmit = method.getAnnotation(ReSubmit.class); //如果不需要防重复提交校验,则放行 if (ObjectUtil.isNull(reSubmit)) { return joinPoint.proceed(); } //获取请求参数 String lockKey = getReqParams(joinPoint, method); //根据请求参数,加锁 boolean acquireLock = redisManager.tryLock(lockKey, reSubmit.waitTime(), reSubmit.leaseTime()); //重复提交 if (!acquireLock) { return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(RespEnum.RESUBMIT_ERROR.getDesc()); } try { return joinPoint.proceed(); } finally { redisManager.unLock(lockKey); } } /** * 获取请求参数 * @param joinPoint joinPoint * @return 缓存key */ private String getReqParams(ProceedingJoinPoint joinPoint, Method method) { //获取请求参数 Object [] args = joinPoint.getArgs(); //方法的参数 Parameter[] parameters = method.getParameters(); //参数有序存放 TreeMap paramTreeMap = MapUtil.newTreeMap(Comparator.naturalOrder()); //参数转为key if (ArrayUtil.isNotEmpty(args) && ArrayUtil.isNotEmpty(parameters) && args.length == parameters.length) { //取参数 for (int i = 0; i < args.length; i++) { //参数值 Object arg = args[i]; //参数 Parameter param = parameters[i]; //是否为基本数据类型,可能是单参数 boolean basicType = ClassUtil.isBasicType(arg.getClass()); if (basicType || arg instanceof String) { paramTreeMap.put(param.getName(), arg); } else { //其余参数视为对象,转Map String json = JSONUtil.toJsonStr(arg); JSONObject jsonObject = JSONUtil.parseObj(json); paramTreeMap.putAll(jsonObject); } } return StrUtil.indexedFormat(RedisKeyConstant.REPEAT_SUBMIT_KEY, SecureUtil.sha256(JSONUtil.toJsonStr(paramTreeMap))); } //获取IP HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); //使用 IP:包.类名.方法名 生成一个key String sha256 = SecureUtil.sha256(JakartaServletUtil.getClientIP(request) + ":" + method.getDeclaringClass().getName() + "." + method.getName()); return StrUtil.indexedFormat(RedisKeyConstant.REPEAT_SUBMIT_KEY, sha256); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/swagger/ParameterHandler.java ================================================ package com.minimalist.basic.config.swagger; import cn.hutool.core.util.ObjectUtil; import io.swagger.v3.oas.models.parameters.Parameter; import lombok.extern.slf4j.Slf4j; import org.springdoc.core.customizers.ParameterCustomizer; import org.springframework.core.MethodParameter; /** * 对单字段的枚举进行处理 * 单字段对应的swagger注解:@Parameter */ @Slf4j public class ParameterHandler extends SchemaEnumHandler implements ParameterCustomizer { @Override public Parameter customize(Parameter property, MethodParameter parameter) { //检查是否包含自定义注解 SchemaEnum schemaEnumAnnotation = getSchemaEnumAnnotation(parameter.getParameterAnnotations()); if (ObjectUtil.isNull(schemaEnumAnnotation)) { return property; } String columnDescription = getColumnDescription(schemaEnumAnnotation, property.getDescription()); property.setDescription(columnDescription); return property; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/swagger/PropertyHandler.java ================================================ package com.minimalist.basic.config.swagger; import cn.hutool.core.util.ObjectUtil; import io.swagger.v3.core.converter.AnnotatedType; import io.swagger.v3.oas.models.media.Schema; import lombok.extern.slf4j.Slf4j; import org.springdoc.core.customizers.PropertyCustomizer; /** * 对实体类中的枚举进行处理 * 实体类中对应的swagger注解:@Schema */ @Slf4j public class PropertyHandler extends SchemaEnumHandler implements PropertyCustomizer { @Override public Schema customize(Schema property, AnnotatedType type) { //检查是否包含自定义注解 SchemaEnum schemaEnumAnnotation = getSchemaEnumAnnotation(type.getCtxAnnotations()); if (ObjectUtil.isNull(schemaEnumAnnotation)) { return property; } String columnDescription = getColumnDescription(schemaEnumAnnotation, property.getDescription()); property.setDescription(columnDescription); return property; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/swagger/SchemaEnum.java ================================================ package com.minimalist.basic.config.swagger; import java.lang.annotation.*; /** * swagger 实体中枚举值处理注解 */ @Target({ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface SchemaEnum { /** 枚举中取key值的方法名 */ String keyMethodName() default "getCode"; /** 枚举中取value值的方法名 */ String valueMethodName() default "getDesc"; /** 枚举 */ Class implementation(); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/swagger/SchemaEnumHandler.java ================================================ package com.minimalist.basic.config.swagger; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.AnnotationUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Optional; import java.util.StringJoiner; @Slf4j public class SchemaEnumHandler { /** * 查找注解 * @param annotations 注解数组 * @return SchemaEnum注解 */ protected SchemaEnum getSchemaEnumAnnotation(Annotation[] annotations) { if (ArrayUtil.isEmpty(annotations)) { return null; } for (Annotation annotation : annotations) { SchemaEnum anno = AnnotationUtils.getAnnotation(annotation, SchemaEnum.class); if (ObjectUtil.isNotNull(anno)) { return anno; } } return null; } /** * 获取枚举里的方法,并执行取值 * @param enumClass 枚举 * @param method 方法名 * @return 值 */ protected Object getEnumMethodValue(Enum enumClass, String method) { try { Method m = enumClass.getClass().getMethod(method); return m.invoke(enumClass); } catch (Exception e) { log.warn("swagger自定义处理,获取枚举中 {} 方法异常,", method, e); } return null; } /** * 根据注解获取描述 * @param schemaEnumAnnotation swagger自定义枚举处理注解 * @param sourceDescription 字段swagger原始描述 * @return 文字描述 */ protected String getColumnDescription(SchemaEnum schemaEnumAnnotation, String sourceDescription) { //枚举 Class enumClass = schemaEnumAnnotation.implementation(); //将枚举转为文字描述 StringJoiner sj = new StringJoiner(", "); for (Enum enumConstant : enumClass.getEnumConstants()) { Object key = getEnumMethodValue(enumConstant, schemaEnumAnnotation.keyMethodName()); Object value = getEnumMethodValue(enumConstant, schemaEnumAnnotation.valueMethodName()); sj.add(key + ": " + value); } return Optional.ofNullable(sourceDescription) .map(s -> s + " -> ") .orElse("") + sj; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/swagger/SwaggerConfig.java ================================================ package com.minimalist.basic.config.swagger; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SwaggerConfig { /** 标题 */ @Value("${springdoc.title}") private String title; /** 作者 */ @Value("${springdoc.authorName}") private String authorName; /** 作者主页 */ @Value("${springdoc.authorUrl}") private String authorUrl; /** 作者Email */ @Value("${springdoc.authorEmail}") private String authorEmail; @Bean public OpenAPI openApi() { return new OpenAPI().info(new Info() //文档页面标题 .title(title) //描述 .description(title + "接口文档") //版本号 .version("1.0.0-SNAPSHOT") //作者信息 .contact(new Contact().name(authorName).email(authorEmail).url(authorUrl))); } @Bean @ConditionalOnMissingBean public PropertyHandler propertyHandler() { return new PropertyHandler(); } @Bean @ConditionalOnMissingBean public ParameterHandler parameterHandler() { return new ParameterHandler(); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/tenant/TenantDatasourceInterceptor.java ================================================ package com.minimalist.basic.config.tenant; import cn.hutool.core.util.ObjectUtil; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import com.minimalist.basic.entity.enums.TenantEnum; import com.minimalist.basic.entity.vo.tenant.TenantVO; import com.minimalist.basic.utils.CommonConstant; import com.minimalist.basic.utils.TenantUtil; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.web.servlet.HandlerInterceptor; /** * 租户数据源切换拦截器 */ @Slf4j public class TenantDatasourceInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //校验系统多租户是否开启 if (!TenantUtil.checkTenantOnOff()) { //未打开,忽略多租户,继续使用主数据源 return HandlerInterceptor.super.preHandle(request, response, handler); } String requestURI = request.getRequestURI(); log.info("切换数据源,访问非/basic接口,经过多数据源拦截器, 当前路径是:{}", requestURI); //获取要操作的租户ID long tenantId = TenantUtil.getTenantId(); //如果是系统租户,使用主数据源 if (CommonConstant.ZERO == tenantId) { log.info("切换数据源,[系统租户] => 继续使用主数据源,租户ID:{}", tenantId); } else { //如果非系统租户,检查是否需要切换到租户数据源 TenantVO tenantVO = CommonConstant.tenantMap.get(tenantId); //该租户数据隔离方式 != master,表示需要切换到租户自己的数据源 if (ObjectUtil.isNotNull(tenantVO) && !TenantEnum.MASTER.equals(tenantVO.getDatasource())) { log.info("切换数据源,[其他租户] => 切换到租户数据源,租户ID:{}", tenantId); DynamicDataSourceContextHolder.push(String.valueOf(tenantId)); } } return HandlerInterceptor.super.preHandle(request, response, handler); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { //清空线程内数据源信息 DynamicDataSourceContextHolder.clear(); log.info("切换数据源,清空数据源"); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/tenant/TenantIgnore.java ================================================ package com.minimalist.basic.config.tenant; import java.lang.annotation.*; /** * 注解加到方法上,标识此方法忽略多租户(异步方法无效) */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface TenantIgnore { /** 多租户字段 */ String TENANT_ID = "tenant_id"; /** 租户切换,多租户字段 */ String CHANGE_TENANT_ID = "change_tenant_id"; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/tenant/TenantIgnoreAspect.java ================================================ package com.minimalist.basic.config.tenant; import cn.hutool.core.util.ObjectUtil; import com.mybatisflex.core.tenant.TenantManager; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 忽略多租户处理 */ @Slf4j @Aspect @Component public class TenantIgnoreAspect { @Around("@annotation(tenantIgnore)") public Object around(ProceedingJoinPoint joinPoint, TenantIgnore tenantIgnore) throws Throwable { Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); TenantIgnore it = method.getAnnotation(TenantIgnore.class); if (ObjectUtil.isNull(it)) { return joinPoint.proceed(); } try { //忽略多租户 TenantManager.ignoreTenantCondition(); //执行目标方法 return joinPoint.proceed(); } finally { //恢复多租户 TenantManager.restoreTenantCondition(); } } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/tenant/TenantInit.java ================================================ package com.minimalist.basic.config.tenant; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.ObjectUtil; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.po.MConfig; import com.minimalist.basic.entity.po.MStorage; import com.minimalist.basic.entity.po.MTenant; import com.minimalist.basic.entity.po.MTenantDatasource; import com.minimalist.basic.entity.vo.storage.StorageVO; import com.minimalist.basic.entity.vo.tenant.TenantDatasourceVO; import com.minimalist.basic.entity.vo.tenant.TenantVO; import com.minimalist.basic.manager.TenantManager; import com.minimalist.basic.mapper.MConfigMapper; import com.minimalist.basic.mapper.MStorageMapper; import com.minimalist.basic.mapper.MTenantDatasourceMapper; import com.minimalist.basic.mapper.MTenantMapper; import com.minimalist.basic.utils.CommonConstant; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; @Component public class TenantInit implements ApplicationRunner { @Autowired private MTenantMapper tenantMapper; @Autowired private MTenantDatasourceMapper tenantDatasourceMapper; @Autowired private TenantManager tenantManager; @Autowired private MStorageMapper storageMapper; @Autowired private MConfigMapper configMapper; @Override public void run(ApplicationArguments args) throws Exception { //查询系统多租户开关 MConfig mConfig = configMapper.selectConfigByConfigKey(CommonConstant.SYSTEM_CONFIG_TENANT, StatusEnum.STATUS_1.getCode()); if (ObjectUtil.isNotNull(mConfig)) { boolean tenantOnOff = Boolean.parseBoolean(mConfig.getConfigValue()); if (!tenantOnOff) { //未打开多租户开关,忽略多租户 return; } } List mTenants = tenantMapper.selectListByQuery(QueryWrapper.create() .eq(MTenant::getStatus, StatusEnum.STATUS_1.getCode())); //租户数据库隔离数据源 List tenantDatasourceList = tenantDatasourceMapper.selectAll(); Map tenantDatasourceMap = tenantDatasourceList.stream().collect(Collectors.toMap(MTenantDatasource::getTenantId, Function.identity())); //租户文件存储 List mStorages = storageMapper.selectListByQuery(QueryWrapper.create() .eq(MStorage::getStatus, StatusEnum.STATUS_1.getCode())); Map storageMap = mStorages.stream().collect(Collectors.toMap(MStorage::getStorageId, Function.identity())); for (MTenant tenant : mTenants) { TenantVO tenantVO = BeanUtil.copyProperties(tenant, TenantVO.class); //查询租户数据源 if (tenantDatasourceMap.containsKey(tenant.getTenantId())) { //动态添加数据源 MTenantDatasource tenantDatasource = tenantDatasourceMap.get(tenant.getTenantId()); TenantDatasourceVO tenantDatasourceVO = BeanUtil.copyProperties(tenantDatasource, TenantDatasourceVO.class); tenantManager.dynamicAddDatasource(tenant.getTenantId().toString(), tenantDatasourceVO); //租户数据源信息 tenantVO.setTenantDatasource(tenantDatasourceVO); } //租户文件存储 MStorage storage = storageMap.get(tenant.getStorageId()); tenantVO.setStorage(BeanUtil.copyProperties(storage, StorageVO.class)); //缓存租户信息 CommonConstant.tenantMap.put(tenant.getTenantId(), tenantVO); } } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/tenant/TenantWebMvcConfig.java ================================================ package com.minimalist.basic.config.tenant; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class TenantWebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new TenantDatasourceInterceptor()) //排除/basic接口对数据源的限制,/basic只能使用master数据源 .excludePathPatterns("/basic/**") .addPathPatterns("/**"); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/trace/TraceIdInterceptor.java ================================================ package com.minimalist.basic.config.trace; import cn.hutool.core.util.IdUtil; import com.minimalist.basic.utils.CommonConstant; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.slf4j.MDC; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; /** * 链路追踪拦截器 * 请求前添加traceId并放到响应头中,请求后将清除 */ @Component public class TraceIdInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String traceId = IdUtil.randomUUID(); MDC.put(CommonConstant.TRACE_ID, traceId); response.setHeader(CommonConstant.TRACE_ID, traceId); return HandlerInterceptor.super.preHandle(request, response, handler); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { MDC.clear(); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/config/trace/WebMvcConfig.java ================================================ package com.minimalist.basic.config.trace; import jakarta.annotation.Resource; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Resource private TraceIdInterceptor traceIdInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { WebMvcConfigurer.super.addInterceptors(registry); registry.addInterceptor(traceIdInterceptor); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/ConfigController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.entity.vo.config.ConfigQueryVO; import com.minimalist.basic.entity.vo.config.ConfigVO; import com.minimalist.basic.service.ConfigService; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @Validated @RestController @Tag(name = "参数配置管理") @RequestMapping("/basic/config") public class ConfigController { @Autowired private ConfigService configService; @PostMapping("/addConfig") @SaCheckPermission("basic:config:add") @Operation(summary = "添加参数") public ResponseEntity addConfig(@RequestBody @Validated(Add.class) ConfigVO configVO) { configService.addConfig(configVO); return ResponseEntity.ok().build(); } @DeleteMapping("/deleteConfigByConfigId") @SaCheckPermission("basic:config:delete") @Operation(summary = "删除参数 -> 根据参数ID删除") public ResponseEntity deleteConfigByConfigId(@RequestParam("configId") @NotNull(message = "参数ID不能为空") @Parameter(name = "configId", required = true, description = "参数ID") Long configId) { configService.deleteConfigByConfigId(configId); return ResponseEntity.ok().build(); } @PutMapping("/updateConfigByConfigId") @SaCheckPermission("basic:config:update") @Operation(summary = "修改参数") public ResponseEntity updateConfigByConfigId(@RequestBody @Validated(Update.class) ConfigVO configVO) { configService.updateConfigByConfigId(configVO); return ResponseEntity.ok().build(); } @GetMapping("/getPageConfigList") @SaCheckPermission("basic:config:get") @Operation(summary = "查询参数配置列表(分页)") public ResponseEntity> getPageConfigList(ConfigQueryVO queryVO) { return ResponseEntity.ok(configService.getPageConfigList(queryVO)); } @GetMapping("/getConfigByConfigId/{configId}") @SaCheckPermission("basic:config:get") @Operation(summary = "根据参数ID查询参数") public ResponseEntity getConfigByConfigId(@PathVariable(value = "configId") @NotNull(message = "参数ID不能为空") @Parameter(name = "configId", description = "参数ID", required = true) Long configId) { return ResponseEntity.ok(configService.getConfigByConfigId(configId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/DeptController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.entity.vo.dept.DeptQueryVO; import com.minimalist.basic.entity.vo.dept.DeptVO; import com.minimalist.basic.service.DeptService; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.List; @Validated @RestController @RequestMapping("/basic/dept") @Tag(name = "部门管理") public class DeptController { @Autowired private DeptService deptService; @PostMapping("/addDept") @SaCheckPermission("basic:dept:add") @Operation(summary = "添加部门") public ResponseEntity addDept(@RequestBody @Validated(Add.class) DeptVO deptVO) { deptService.addDept(deptVO); return ResponseEntity.ok().build(); } @DeleteMapping("/deleteDeptByDeptId") @SaCheckPermission("basic:dept:delete") @Operation(summary = "删除部门 -> 根据部门ID删除") public ResponseEntity deleteDeptByDeptId(@RequestParam("deptId") @NotNull(message = "部门ID不能为空") @Parameter(name = "deptId", required = true, description = "部门ID") Long deptId) { deptService.deleteDeptByDeptId(deptId); return ResponseEntity.ok().build(); } @PutMapping("/updateDeptByDeptId") @SaCheckPermission("basic:dept:update") @Operation(summary = "修改部门 -> 根据部门ID修改") public ResponseEntity updateDeptByDeptId(@RequestBody @Validated(Update.class) DeptVO deptVO) { deptService.updateDeptByDeptId(deptVO); return ResponseEntity.ok().build(); } @GetMapping("/getDeptList") @SaCheckPermission("basic:dept:get") @Operation(summary = "查询部门列表(不分页,获取全部数据) -> 部门管理使用") public ResponseEntity> getDeptList(DeptQueryVO queryVO) { return ResponseEntity.ok(deptService.getDeptList(queryVO)); } @GetMapping("/getEnableDeptList") @SaCheckPermission("basic:dept:get") @Operation(summary = "查询部门树 -> 只获取正常状态的部门") public ResponseEntity> getEnableDeptList() { return ResponseEntity.ok(deptService.getEnableDeptList()); } @GetMapping("/getDeptByDeptId/{deptId}") @SaCheckPermission("basic:dept:get") @Operation(summary = "根据部门ID查询部门") public ResponseEntity getDeptByDeptId(@PathVariable(value = "deptId") @NotNull(message = "部门ID不能为空") @Parameter(name = "deptId", description = "部门ID", required = true) Long deptId) { return ResponseEntity.ok(deptService.getDeptByDeptId(deptId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/DictController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.entity.vo.dict.*; import com.minimalist.basic.service.DictService; import com.minimalist.basic.config.mybatis.bo.PageResp; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.List; @Validated @RestController @Tag(name = "字典管理") @RequestMapping("/basic/dict") public class DictController { @Autowired private DictService dictService; @PostMapping("/addDict") @SaCheckPermission("basic:dict:add") @Operation(summary = "添加字典") public ResponseEntity addDict(@RequestBody @Validated DictInfoVO dictInfoVO) { dictService.addDict(dictInfoVO); return ResponseEntity.ok().build(); } @DeleteMapping("/deleteDictByDictId") @SaCheckPermission("basic:dict:delete") @Operation(summary = "删除字典 -> 根据字典ID删除") public ResponseEntity deleteDictByDictId(@RequestParam("dictId") @NotNull(message = "字典ID不能为空") @Parameter(name = "dictId", required = true, description = "字典ID") Long dictId) { dictService.deleteDictByDictId(dictId); return ResponseEntity.ok().build(); } @DeleteMapping("/deleteDictByDictType") @SaCheckPermission("basic:dict:delete") @Operation(summary = "删除字典 -> 根据字典类型删除") public ResponseEntity deleteDictByDictType(@RequestParam("dictType") @NotNull(message = "字典类型不能为空") @Parameter(name = "dictType", required = true, description = "字典类型") String dictType) { dictService.deleteDictByDictType(dictType); return ResponseEntity.ok().build(); } @PutMapping("/updateDictByDictId") @SaCheckPermission("basic:dict:update") @Operation(summary = "修改字典") public ResponseEntity updateDictByDictId(@RequestBody @Validated DictInfoVO dictInfoVO) { dictService.updateDictByDictId(dictInfoVO); return ResponseEntity.ok().build(); } @GetMapping("/getPageDictList") @SaCheckPermission("basic:dict:get") @Operation(summary = "查询字典列表(分页)") public ResponseEntity> getPageDictList(DictQueryVO queryVO) { return ResponseEntity.ok(dictService.getPageDictList(queryVO)); } @GetMapping("/getDictByDictType/{dictType}") @SaCheckPermission("basic:dict:get") @Operation(summary = "根据字典类型查询字典 -> 用于字典管理页面") public ResponseEntity getDictByDictType(@PathVariable(value = "dictType") @Parameter(name = "dictType", description = "字典类型", required = true) String dictType) { return ResponseEntity.ok(dictService.getDictByDictType(dictType)); } @GetMapping("/getDictList/{dictTypes}") @Operation(summary = "根据字典类型查询字典 -> 用于下拉框数据展示或编码转换") public ResponseEntity> getDictList(@PathVariable(value = "dictTypes") @NotEmpty(message = "字典类型不能为空") @Parameter(name = "dictTypes", description = "字典类型列表,为空则查询所有字典数据") List dictType) { return ResponseEntity.ok(dictService.getDictList(dictType)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/FileController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.entity.vo.file.*; import com.minimalist.basic.service.FileService; import com.minimalist.basic.config.mybatis.bo.PageResp; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.List; @Validated @RestController @Tag(name = "文件管理") @RequestMapping("/basic/file") public class FileController { @Autowired private FileService fileService; @PostMapping("/uploadFile") @SaCheckPermission("basic:file:upload") @Operation(summary = "单文件上传") public ResponseEntity uploadFile(@Validated FileUploadVO fileUploadVO) { return ResponseEntity.ok(fileService.uploadFile(fileUploadVO)); } @PostMapping("/uploadFileBatch") @SaCheckPermission("basic:file:upload") @Operation(summary = "批量文件上传") public ResponseEntity> uploadFileBatch(@Validated FileUploadBatchVO uploadBatchVO) { return ResponseEntity.ok(fileService.uploadFileBatch(uploadBatchVO)); } @DeleteMapping("/deleteFile") @SaCheckPermission("basic:file:delete") @Operation(summary = "单文件删除") public ResponseEntity deleteFile(@RequestParam("fileId") @NotNull(message = "文件ID不能为空") @Parameter(name = "fileId", required = true, description = "fileId") Long fileId) { fileService.deleteFile(fileId); return ResponseEntity.ok().build(); } @GetMapping("/getPageFileList") @SaCheckPermission("basic:file:get") @Operation(summary = "查询文件列表(分页)") public ResponseEntity> getPageFileList(FileQueryVO queryVO) { return ResponseEntity.ok(fileService.getPageFileList(queryVO)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/NoticeController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.entity.vo.notice.NoticeQueryVO; import com.minimalist.basic.entity.vo.notice.NoticeVO; import com.minimalist.basic.service.NoticeService; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import net.dreamlu.mica.xss.core.XssCleanIgnore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @Validated @RestController @Tag(name = "通知、公告管理") @RequestMapping("/basic/notice") public class NoticeController { @Autowired private NoticeService noticeService; @XssCleanIgnore @PostMapping("/addNotice") @SaCheckPermission("basic:notice:add") @Operation(summary = "添加公告") public ResponseEntity addNotice(@RequestBody @Validated(Add.class) NoticeVO noticeVO) { noticeService.addNotice(noticeVO); return ResponseEntity.ok().build(); } @DeleteMapping("/deleteNoticeByNoticeId") @SaCheckPermission("basic:notice:delete") @Operation(summary = "删除公告 -> 根据公告ID删除") public ResponseEntity deleteNoticeByNoticeId(@RequestParam("noticeId") @NotNull(message = "公告ID不能为空") @Parameter(name = "noticeId", required = true, description = "公告ID") Long noticeId) { noticeService.deleteNoticeByNoticeId(noticeId); return ResponseEntity.ok().build(); } @XssCleanIgnore @PutMapping("/updateNoticeByNoticeId") @SaCheckPermission("basic:notice:update") @Operation(summary = "修改公告 -> 根据公告ID修改") public ResponseEntity updateNoticeByNoticeId(@RequestBody @Validated(Update.class) NoticeVO noticeVO) { noticeService.updateNoticeByNoticeId(noticeVO); return ResponseEntity.ok().build(); } @GetMapping("/getPageNoticeList") @SaCheckPermission("basic:notice:get") @Operation(summary = "查询公告列表(分页) -> 公告管理使用") public ResponseEntity> getPageNoticeList(NoticeQueryVO queryVO) { return ResponseEntity.ok(noticeService.getPageNoticeList(queryVO)); } @GetMapping("/getNoticeByNoticeId/{noticeId}") @Operation(summary = "根据公告ID查询公告") public ResponseEntity getNoticeByNoticeId(@PathVariable(value = "noticeId") @NotNull(message = "公告ID不能为空") @Parameter(name = "noticeId", description = "公告ID", required = true) Long noticeId) { return ResponseEntity.ok(noticeService.getNoticeByNoticeId(noticeId)); } @GetMapping("/getPageHomeNoticeList") @Operation(summary = "查询公告列表(分页) -> 首页使用") public ResponseEntity> getPageHomeNoticeList(PageReq pageReq) { return ResponseEntity.ok(noticeService.getPageHomeNoticeList(pageReq)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/PermController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.entity.vo.perm.PermQueryVO; import com.minimalist.basic.entity.vo.perm.PermVO; import com.minimalist.basic.service.PermService; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.List; @Validated @RestController @RequestMapping("/basic/permission") @Tag(name = "权限管理") public class PermController { @Autowired private PermService permService; @PostMapping("/addPerm") @SaCheckPermission("basic:perm:add") @Operation(summary = "添加权限") public ResponseEntity addPerm(@RequestBody @Validated(Add.class) PermVO permVO) { permService.addPerm(permVO); return ResponseEntity.ok().build(); } @DeleteMapping("/deletePermByPermId") @SaCheckPermission("basic:perm:delete") @Operation(summary = "删除权限 -> 根据权限ID删除") public ResponseEntity deletePermByPermId(@RequestParam("permId") @NotNull(message = "权限ID不能为空") @Parameter(name = "permId", required = true, description = "权限ID") Long permId) { permService.deletePermByPermId(permId); return ResponseEntity.ok().build(); } @PutMapping("/updatePermByPermId") @SaCheckPermission("basic:perm:update") @Operation(summary = "修改权限 -> 根据权限ID修改") public ResponseEntity updatePermByPermId(@RequestBody @Validated(Update.class) PermVO permVO) { permService.updatePermByPermId(permVO); return ResponseEntity.ok().build(); } @GetMapping("/getPermList") @SaCheckPermission("basic:perm:get") @Operation(summary = "查询权限列表(不分页,获取全部数据) -> 权限管理使用") public ResponseEntity> getPermList(PermQueryVO queryVO) { return ResponseEntity.ok(permService.getPermList(queryVO)); } @GetMapping("/getEnablePermList") @Operation(summary = "查询系统租户权限列表 -> 只获取正常状态的权限") public ResponseEntity> getEnablePermList() { return ResponseEntity.ok(permService.getEnablePermList()); } @GetMapping("/getTenantEnablePermList") @Operation(summary = "查询租户权限列表 -> 只获取正常状态的权限") public ResponseEntity> getTenantEnablePermList() { return ResponseEntity.ok(permService.getTenantEnablePermList()); } @GetMapping("/getPermByPermId/{permId}") @SaCheckPermission("basic:perm:get") @Operation(summary = "根据权限ID查询权限") public ResponseEntity getPermByPermId(@PathVariable(value = "permId") @NotNull(message = "权限ID不能为空") @Parameter(name = "permId", description = "权限ID", required = true) Long permId) { return ResponseEntity.ok(permService.getPermByPermId(permId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/PostController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.entity.vo.post.PostQueryVO; import com.minimalist.basic.entity.vo.post.PostVO; import com.minimalist.basic.service.PostService; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @Validated @RestController @RequestMapping("/basic/post") @Tag(name = "岗位管理") public class PostController { @Autowired private PostService postService; @PostMapping("/addPost") @SaCheckPermission("basic:post:add") @Operation(summary = "添加岗位") public ResponseEntity addPost(@RequestBody @Validated(Add.class) PostVO postVO) { postService.addPost(postVO); return ResponseEntity.ok().build(); } @DeleteMapping("/deletePostByPostId") @SaCheckPermission("basic:post:delete") @Operation(summary = "删除岗位 -> 根据岗位ID删除") public ResponseEntity deletePostByPostId(@RequestParam("postId") @NotNull(message = "岗位ID不能为空") @Parameter(name = "postId", required = true, description = "岗位ID") Long postId) { postService.deletePostByPostId(postId); return ResponseEntity.ok().build(); } @PutMapping("/updatePostByPostId") @SaCheckPermission("basic:post:update") @Operation(summary = "修改岗位 -> 根据岗位ID修改") public ResponseEntity updatePostByPostId(@RequestBody @Validated(Update.class) PostVO postVO) { postService.updatePostByPostId(postVO); return ResponseEntity.ok().build(); } @GetMapping("/getPagePostList") @SaCheckPermission("basic:post:get") @Operation(summary = "查询岗位列表(分页)") public ResponseEntity> getPagePostList(PostQueryVO queryVO) { return ResponseEntity.ok(postService.getPagePostList(queryVO)); } @GetMapping("/getPostByPostId/{postId}") @SaCheckPermission("basic:post:get") @Operation(summary = "根据岗位ID查询岗位") public ResponseEntity getPostByPostId(@PathVariable(value = "postId") @NotNull(message = "岗位ID不能为空") @Parameter(name = "postId", description = "岗位ID", required = true) Long postId) { return ResponseEntity.ok(postService.getPostByPostId(postId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/RoleController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.entity.vo.role.RoleQueryVO; import com.minimalist.basic.entity.vo.role.RoleVO; import com.minimalist.basic.service.RoleService; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @Validated @RestController @RequestMapping("/basic/role") @Tag(name = "角色管理") public class RoleController { @Autowired private RoleService roleService; @PostMapping("/addRole") @SaCheckPermission("basic:role:add") @Operation(summary = "添加角色") public ResponseEntity addRole(@RequestBody @Validated(Add.class) RoleVO roleVO) { roleService.addRole(roleVO); return ResponseEntity.ok().build(); } @DeleteMapping("/deleteRoleByRoleId") @SaCheckPermission("basic:role:delete") @Operation(summary = "删除角色 -> 根据角色ID删除角色") public ResponseEntity deleteRoleByRoleId(@RequestParam("roleId") @NotNull(message = "角色ID不能为空") @Parameter(name = "roleId", required = true, description = "角色ID") Long roleId) { roleService.deleteRoleByRoleId(roleId); return ResponseEntity.ok().build(); } @PutMapping("/updateRoleByRoleId") @SaCheckPermission("basic:role:update") @Operation(summary = "修改角色 -> 根据角色ID修改") public ResponseEntity updateRoleByRoleId(@RequestBody @Validated(Update.class) RoleVO roleVO) { roleService.updateRoleByRoleId(roleVO); return ResponseEntity.ok().build(); } @GetMapping("/getPageRoleList") @SaCheckPermission("basic:role:get") @Operation(summary = "查询角色(分页) -> 角色管理使用") public ResponseEntity> getPageRoleList(RoleQueryVO queryVO) { return ResponseEntity.ok(roleService.getPageRoleList(queryVO)); } @GetMapping("/getRoleByRoleId/{roleId}") @SaCheckPermission("basic:role:get") @Operation(summary = "根据角色ID查询角色") public ResponseEntity getRoleByRoleId(@PathVariable(value = "roleId") @NotNull(message = "角色ID不能为空") @Parameter(name = "roleId", description = "角色ID", required = true) Long roleId) { return ResponseEntity.ok(roleService.getRoleByRoleId(roleId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/StorageController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.entity.vo.storage.StorageQueryVO; import com.minimalist.basic.entity.vo.storage.StorageVO; import com.minimalist.basic.service.StorageService; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @Validated @RestController @RequestMapping("/basic/storage") @Tag(name = "存储管理") public class StorageController { @Autowired private StorageService storageService; @PostMapping("/addStorage") @SaCheckPermission("basic:storage:add") @Operation(summary = "添加存储") public ResponseEntity addStorage(@RequestBody @Validated(Add.class) StorageVO storageVO) { storageService.addStorage(storageVO); return ResponseEntity.ok().build(); } @DeleteMapping("/deleteStorageByStorageId") @SaCheckPermission("basic:storage:delete") @Operation(summary = "删除存储 -> 根据存储ID删除") public ResponseEntity deleteStorageByStorageId(@RequestParam("storageId") @NotNull(message = "存储ID不能为空") @Parameter(name = "storageId", required = true, description = "存储ID") Long storageId) { storageService.deleteStorageByStorageId(storageId); return ResponseEntity.ok().build(); } @PutMapping("/updateStorageByStorageId") @SaCheckPermission("basic:storage:update") @Operation(summary = "修改存储 -> 根据存储ID修改") public ResponseEntity updateStorageByStorageId(@RequestBody @Validated(Update.class) StorageVO storageVO) { storageService.updateStorageByStorageId(storageVO); return ResponseEntity.ok().build(); } @GetMapping("/getPageStorageList") @SaCheckPermission("basic:storage:get") @Operation(summary = "查询存储列表(分页)") public ResponseEntity> getPageStorageList(StorageQueryVO queryVO) { return ResponseEntity.ok(storageService.getPageStorageList(queryVO)); } @GetMapping("/getStorageByStorageId/{storageId}") @SaCheckPermission("basic:storage:get") @Operation(summary = "根据存储ID查询存储信息") public ResponseEntity getStorageByStorageId(@PathVariable(value = "storageId") @NotNull(message = "存储ID不能为空") @Parameter(name = "storageId", description = "存储ID", required = true) Long storageId) { return ResponseEntity.ok(storageService.getStorageByStorageId(storageId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/TenantController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.entity.vo.tenant.TenantQueryVO; import com.minimalist.basic.entity.vo.tenant.TenantVO; import com.minimalist.basic.service.TenantService; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.config.tenant.TenantIgnore; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @Validated @RestController @RequestMapping("/basic/tenant") @Tag(name = "租户管理") public class TenantController { @Autowired private TenantService tenantService; @TenantIgnore @PostMapping("/addTenant") @SaCheckPermission("basic:tenant:add") @Operation(summary = "添加租户") public ResponseEntity addTenant(@RequestBody @Validated(Add.class) TenantVO tenantVO) { tenantService.addTenant(tenantVO); return ResponseEntity.ok().build(); } @TenantIgnore @DeleteMapping("/deleteTenantByTenantId") @SaCheckPermission("basic:tenant:delete") @Operation(summary = "删除租户 -> 根据租户ID删除租户") public ResponseEntity deleteTenantByTenantId(@RequestParam("tenantId") @NotNull(message = "租户ID不能为空") @Parameter(name = "tenantId", required = true, description = "租户ID") Long tenantId) { tenantService.deleteTenantByTenantId(tenantId); return ResponseEntity.ok().build(); } @TenantIgnore @PutMapping("/updateTenantByTenantId") @SaCheckPermission("basic:tenant:update") @Operation(summary = "修改租户 -> 根据租户ID修改") public ResponseEntity updateTenantByTenantId(@RequestBody @Validated(Update.class) TenantVO tenantVO) { tenantService.updateTenantByTenantId(tenantVO); return ResponseEntity.ok().build(); } @TenantIgnore @GetMapping("/getPageTenantList") @SaCheckPermission("basic:tenant:get") @Operation(summary = "查询租户(分页)") public ResponseEntity> getPageTenantList(TenantQueryVO queryVO) { return ResponseEntity.ok(tenantService.getPageTenantList(queryVO)); } @TenantIgnore @GetMapping("/getTenantByTenantId/{tenantId}") @SaCheckPermission("basic:tenant:get") @Operation(summary = "根据租户ID查询租户") public ResponseEntity getTenantByTenantId(@PathVariable(value = "tenantId") @NotNull(message = "租户ID不能为空") @Parameter(name = "tenantId", description = "租户ID", required = true) Long tenantId) { return ResponseEntity.ok(tenantService.getTenantByTenantId(tenantId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/TenantPackageController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import com.minimalist.basic.entity.vo.tenant.TenantPackageQueryVO; import com.minimalist.basic.entity.vo.tenant.TenantPackageVO; import com.minimalist.basic.service.TenantPackageService; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.config.tenant.TenantIgnore; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @Validated @RestController @RequestMapping("/basic/tenantPackage") @Tag(name = "租户管理") public class TenantPackageController { @Autowired private TenantPackageService tenantPackageService; @TenantIgnore @PostMapping("/addTenantPackage") @SaCheckPermission("basic:tenantPackage:add") @Operation(summary = "添加租户套餐") public ResponseEntity addTenantPackage(@RequestBody @Validated(Add.class) TenantPackageVO tenantPackageVO) { tenantPackageService.addTenantPackage(tenantPackageVO); return ResponseEntity.ok().build(); } @TenantIgnore @DeleteMapping("/deleteTenantPackageByTenantPackageId") @SaCheckPermission("basic:tenantPackage:delete") @Operation(summary = "删除租户套餐 -> 根据租户套餐ID删除租户套餐") public ResponseEntity deleteTenantPackageByTenantPackageId(@RequestParam("tenantPackageId") @NotNull(message = "租户套餐ID不能为空") @Parameter(name = "tenantPackageId", required = true, description = "租户套餐ID") Long tenantPackageId) { tenantPackageService.deleteTenantPackageByTenantPackageId(tenantPackageId); return ResponseEntity.ok().build(); } @TenantIgnore @PutMapping("/updateTenantPackageByTenantPackageId") @SaCheckPermission("basic:tenantPackage:update") @Operation(summary = "修改租户套餐 -> 根据租户套餐ID修改") public ResponseEntity updateTenantPackageByTenantPackageId(@RequestBody @Validated(Update.class) TenantPackageVO tenantPackageVO) { tenantPackageService.updateTenantPackageByTenantPackageId(tenantPackageVO); return ResponseEntity.ok().build(); } @TenantIgnore @GetMapping("/getPageTenantPackageList") @SaCheckPermission("basic:tenantPackage:get") @Operation(summary = "查询租户套餐(分页)") public ResponseEntity> getPageTenantPackageList(TenantPackageQueryVO queryVO) { return ResponseEntity.ok(tenantPackageService.getPageTenantPackageList(queryVO)); } @TenantIgnore @GetMapping("/getTenantPackageByTenantPackageId/{tenantPackageId}") @SaCheckPermission("basic:tenantPackage:get") @Operation(summary = "根据租户套餐ID查询租户套餐") public ResponseEntity getTenantPackageByTenantPackageId(@PathVariable(value = "tenantPackageId") @NotNull(message = "租户套餐ID不能为空") @Parameter(name = "tenantPackageId", description = "租户套餐ID", required = true) Long tenantPackageId) { return ResponseEntity.ok(tenantPackageService.getTenantPackageByTenantPackageId(tenantPackageId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/controller/UserController.java ================================================ package com.minimalist.basic.controller; import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpUtil; import com.minimalist.basic.entity.vo.user.*; import com.minimalist.basic.service.UserService; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.config.tenant.TenantIgnore; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @Validated @RestController @RequestMapping("/basic/user") @Tag(name = "用户管理") public class UserController { @Autowired private UserService userService; @PostMapping("/addUser") @SaCheckPermission("basic:user:add") @Operation(summary = "添加用户") public ResponseEntity addUser(@RequestBody @Validated(Add.class) UserVO userVO) { userService.addUser(userVO); return ResponseEntity.ok().build(); } @DeleteMapping("/deleteUserByUserId") @SaCheckPermission("basic:user:delete") @Operation(summary = "删除用户 -> 根据用户ID删除") public ResponseEntity deleteUserByUserId(@RequestParam("userId") @NotNull(message = "用户ID不能为空") @Parameter(name = "userId", required = true, description = "用户ID") Long userId) { userService.deleteUserByUserId(userId); return ResponseEntity.ok().build(); } @PutMapping("/updateUserByUserId") @SaCheckPermission("basic:user:update") @Operation(summary = "修改用户") public ResponseEntity updateUserByUserId(@RequestBody @Validated(Update.class) UserVO userVO) { userService.updateUserByUserId(userVO); return ResponseEntity.ok().build(); } @GetMapping("/getPageUserList") @SaCheckPermission("basic:user:get") @Operation(summary = "查询用户(分页)") public ResponseEntity> getPageUserList(UserQueryVO queryVO) { return ResponseEntity.ok(userService.getPageUserList(queryVO)); } @GetMapping("/getUserByUserId/{userId}") @SaCheckPermission("basic:user:get") @Operation(summary = "根据用户ID查询用户 -> 用户管理页使用") public ResponseEntity getUserByUserId(@PathVariable(value = "userId") @NotNull(message = "用户ID不能为空") @Parameter(name = "userId", description = "用户ID", required = true) Long userId) { return ResponseEntity.ok(userService.getUserByUserId(userId)); } //@TenantIgnore @GetMapping("/getUserInfo") @Operation(summary = "获取用户信息(登录后获取,含角色、权限、菜单、部门等)") public ResponseEntity getUserInfo() { return ResponseEntity.ok(userService.getUserInfo()); } @SaIgnore @GetMapping("/getImageCaptcha") @Operation(summary = "获取图形验证码") public ResponseEntity getImageCaptcha() { return ResponseEntity.ok(userService.getImageCaptcha()); } @SaIgnore @TenantIgnore @PostMapping("/login") @Operation(summary = "用户登录,返回token") public ResponseEntity login(@RequestBody @Valid UserLoginReqVO reqVO) { return ResponseEntity.ok(userService.userLogin(reqVO)); } @PostMapping("/logout") @Operation(summary = "退出登录") public ResponseEntity logout() { StpUtil.logout(); return ResponseEntity.ok().build(); } @SaCheckLogin @PostMapping("/resetPassword") @Operation(summary = "重置密码") public ResponseEntity resetPassword(@RequestBody @Valid RePasswordVO passwordVO) { userService.resetPassword(passwordVO); return ResponseEntity.ok().build(); } @SaCheckLogin @PostMapping("/updateUserAvatar") @Operation(summary = "修改用户头像") public ResponseEntity updateUserAvatar(@RequestParam("userAvatar") @NotBlank(message = "用户头像不能为空") @Parameter(name = "userAvatar", description = "用户头像base64编码", required = true) String userAvatar) { userService.updateUserAvatar(userAvatar); return ResponseEntity.ok().build(); } @SaCheckLogin @PostMapping("/updateUserInfo") @Operation(summary = "修改用户基本信息") public ResponseEntity updateUserInfo(@RequestBody @Valid UserSettingVO settingVO) { userService.updateUserInfo(settingVO); return ResponseEntity.ok().build(); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/ConfigEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class ConfigEnum { /** 字典处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { NONENTITY_CONFIG("参数配置不存在"), CONTAIN_CONFIG_KEY("参数键名已存在"), CANNOT_DEL_SYSTEM_CONFIG("不能删除系统参数"), ; private final String desc; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/DeptEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class DeptEnum { /** 部门处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { NONENTITY_DEPT("部门不存在"), CONTAIN_CHILDREN("该权限下包含子项,请先删除子项"), USER_DEPT_CHILDREN("有用户在该部门,请先调整该用户部门"), ; private final String desc; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/DictEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class DictEnum { /** 字典处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { NONENTITY_DICT("字典不存在"), ; private final String desc; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/FileEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class FileEnum { /** 文件处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { NONENTITY_FILE("文件不存在"), FILE_USED("文件已被使用"), FILE_UPLOAD_FAIL("文件上传失败,请重试"), FILE_THUMBNAILS_UPLOAD_FAIL("文件缩略图上传失败,请重试"), FILE_DOWNLOAD_FAIL("文件下载失败,请重试"), FILE_MOVE_FAIL("文件移动失败,请重试"), FILE_DELETE_FAIL("文件删除失败,请重试"), ; private final String desc; } /** 文件来源 */ @Getter @AllArgsConstructor public enum FileSource { NOTICE_COVER_IMG(1, "系统公告封面图片"), NOTICE_CONTENT_IMG(2, "系统公告内容图片"), ; private final Integer code; private final String desc; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/NoticeEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class NoticeEnum { /** 公告处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { NONENTITY_NOTICE("公告不存在"), ; private final String desc; } /** 公告类型 */ @Getter @AllArgsConstructor public enum NoticeType { NOTICE(1, "公告"), NEWS(2, "新闻"), ; private final Integer code; private final String desc; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/PermEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class PermEnum { /** 权限处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { NONENTITY_PERM("权限不存在"), CONTAIN_CHILDREN("该权限下包含子项,请先删除子项"), ; private final String desc; } /** 权限类型 */ @Getter @AllArgsConstructor public enum PermType { MENU("M", "菜单"), BUTTON("B", "按钮"), ; private final String code; private final String desc; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/PostEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class PostEnum { /** 岗位处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { NONENTITY_POST("岗位不存在"), EXISTS_POST("岗位编码已存在"), ; private final String desc; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/RespEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; @Getter @AllArgsConstructor public enum RespEnum { /** 操作成功 */ SUCCESS(200, "操作成功"), /** 系统异常,请稍后再试 */ FAILED(500, "系统异常,请稍后再试"), /** 参数错误 */ PARAM_ERROR(400, "参数错误"), /** 用户认证失败,请重新登录 */ REQUEST_UNAUTH(401, "用户认证失败,请重新登录"), /** 无操作权限 */ NO_OPERATION_PERMISSION(403, "暂无操作权限"), /** 无操作权限 */ TAMPER_WITH_DATA(400, "请勿篡改数据"), /** 重复提交 */ RESUBMIT_ERROR(503, "请求已提交,请稍后重试"), /** 参数存在XSS敏感字符 */ PARAM_XSS_ERROR(400, "存在敏感数据,不能提交"), ; private final Integer code; private final String desc; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/RoleEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class RoleEnum { /** 角色 */ @Getter @AllArgsConstructor public enum Role { /** 系统管理员,权限最高 */ SYSTEM_ADMIN("system_admin", "系统管理员"), /** 租户管理员,租户权限范围内权限最高 */ ADMIN("admin", "管理员"), ; private final String code; private final String name; } /** 角色处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { EXISTS_ROLE("角色编码已存在"), NONENTITY_ROLE("角色不存在"), ; private final String desc; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/StatusEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; /** * 公共的状态枚举 * 对应每张表中的status字段 */ @Getter @AllArgsConstructor public enum StatusEnum { STATUS_0(0, "禁用"), STATUS_1(1, "正常"), ; private final Integer code; private final String desc; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/StorageEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class StorageEnum { /** 存储处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { NONENTITY_STORAGE("存储信息不存在"), ; private final String desc; } /** 存储类型 */ @Getter @AllArgsConstructor public enum StorageType { LOCAL("local", "本地"), MINIO("minio", "MinIO"), QINIU("qiniu", "七牛云"), ; private final String code; private final String desc; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/TenantEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class TenantEnum { /** 租户处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { NONENTITY_TENANT("租户不存在"), EXISTS_TENANT("租户已存在,请检查租户名"), NONENTITY_TENANT_PACKAGE("租户套餐不存在"), USE_TENANT_PACKAGE("有租户正在使用该套餐,不能删除"), STATUS_TENANT_PACKAGE("选择的租户套餐已被禁用"), TENANT_USER_COUNT_LIMIT("租户下可创建的用户数已达上限"), EX_TENANT("租户已过期,请联系管理员"), DISABLED_TENANT("租户已被禁用,请联系管理员"), QUERY_NULL_TENANT("未查询到租户,请联系管理员"), SYSTEM_TENANT("系统租户,不可删除"), SYSTEM_TENANT_PACKAGE("系统租户套餐,不可删除"), ADD_TENANT_USER_NULL("添加租户时用户信息不能为空"), ADD_TENANT_USERNAME_NULL("添加租户时用户账号不能为空"), ADD_TENANT_PASSWORD_NULL("添加租户时用户密码不能为空"), ADD_TENANT_NICKNAME_NULL("添加租户时用户昵称不能为空"), ADD_TENANT_REALNAME_NULL("添加租户时用户真实姓名不能为空"), ADD_TENANT_PHONE_NULL("添加租户时用户手机号不能为空"), ADD_TENANT_USERSEX_NULL("添加租户时用户性别不能为空"), ; private final String desc; } /** 租户数据隔离方式 */ @Getter @AllArgsConstructor public enum DataIsolation { COLUMN("column", "字段隔离"), DB("db", "数据库隔离"); private final String code; private final String desc; } /** 主数据源名称 */ public static final String MASTER = "master"; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/enums/UserEnum.java ================================================ package com.minimalist.basic.entity.enums; import lombok.AllArgsConstructor; import lombok.Getter; public class UserEnum { /** 用户处理异常信息 */ @Getter @AllArgsConstructor public enum ErrorMsg { CAPTCHA_ID_EMPTY("验证码ID为空"), CAPTCHA_CONTENT_EMPTY("验证码为空"), CAPTCHA_INCORRECT("验证码输入错误"), U_OR_P_INCORRECT("用户名或密码错误"), USER_FROZEN("账户已被冻结"), AUTH_EXPIRED("登录信息过期,请重新登录"), ACCOUNT_EXPIRED("账户已过期"), BAD_INVALID("凭证无效,请重新登录"), EXISTS_ACCOUNT("用户名已存在"), PHONE_ACCOUNT("用户手机已存在"), EMAIL_ACCOUNT("用户邮箱已存在"), NONENTITY_ACCOUNT("用户不存在"), NONENTITY_OPT_ACCOUNT("操作的用户不存在"), OLD_PASSWORD_INCORRECT("旧密码输入错误"), USER_AVATAR_SIZE("头像大小需小于100kb"), LOGIN_USER_INCONSISTENT("获取的用户信息与当前登陆用户不一致"), USER_UNBOUND_TENANT("该账户未绑定租户"), ; private final String desc; } /** 用户性别 */ @Getter @AllArgsConstructor public enum UserSex { USER_SEX_0(0, "未知"), USER_SEX_1(1, "男"), USER_SEX_2(2, "女"), ; private final Integer code; private final String desc; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MConfig.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 参数配置表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_config", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MConfig extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 参数ID */ private Long configId; /** * 参数名称 */ private String configName; /** * 参数键名 */ private String configKey; /** * 参数键值 */ private String configValue; /** * 说明 */ private String description; /** * 状态 0禁用 1正常 */ private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MDept.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Column; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 部门表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_dept", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MDept extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 部门id */ private Long deptId; /** * 父部门id */ private Long parentDeptId; /** * 祖级列表 */ private String ancestors; /** * 部门名称 */ private String deptName; /** * 部门负责人 */ private Long deptLeader; /** * 显示顺序 */ private Integer deptSort; /** * 联系电话 */ private String phone; /** * 邮箱 */ private String email; /** * 状态 0禁用 1正常 */ private Integer status; /** * 租户编号 */ @Column(tenantId = true) private Long tenantId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MDict.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 字典表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_dict", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MDict extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 字典ID */ private Long dictId; /** * 字典类型 */ private String dictType; /** * 字典key */ private String dictKey; /** * 字典value */ private String dictValue; /** * 字典名称 */ private String dictName; /** * 字典描述 */ private String dictDesc; /** * 字典排序值 */ private Integer dictOrder; /** * 字典样式,对应前端Tag组件的type */ private String dictClass; /** * 状态 0禁用 1正常 */ private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MFile.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Column; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 文件表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_file", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MFile extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 文件ID */ private Long fileId; /** * 原文件名 */ private String fileName; /** * 现文件名 */ private String newFileName; /** * 文件大小 */ private Long fileSize; /** * 文件类型 */ private String fileType; /** * 文件基础路径 */ private String fileBasePath; /** * 文件相对路径 */ private String filePath; /** * 文件url */ private String fileUrl; /** * 文件来源 */ private Integer fileSource; /** * 存储ID */ private Long storageId; /** * 文件缩略图url */ private String fileThUrl; /** * 文件缩略图文件名 */ private String fileThFilename; /** * 缩略图文件大小 */ private Long fileThSize; /** * 备注 */ private String remark; /** * 状态 0未使用 1已使用,默认未使用,代码中控制修改为已使用,可以定期清理未使用的文件 */ private Integer status; /** * 租户ID */ @Column(tenantId = true) private Long tenantId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MNotice.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import java.time.LocalDateTime; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 通知公告表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_notice", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MNotice extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 公告ID */ private Long noticeId; /** * 公告标题 */ private String noticeTitle; /** * 公告类型(1公告) */ private Integer noticeType; /** * 公告内容 */ private String noticeContent; /** * 封面图文件ID,多个使用 , 分割 */ private String noticePicFileId; /** * 是否置顶 0否 1是 */ private Boolean noticeTop; /** * 延时发布的时间 */ private LocalDateTime noticeTimeInterval; /** * 排序 */ private Integer noticeSort; /** * 是否外链 0否 1是 */ private Boolean noticeOutChain; /** * 外部跳转链接 */ private String noticeLink; /** * 发布部门 */ private Long publishDeptId; /** * 发布人 */ private Long publishAuthorId; /** * 发布时间 */ private LocalDateTime publishTime; /** * 状态 0禁用 1正常 */ private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MPerms.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 权限表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_perms", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MPerms extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 权限ID */ private Long permId; /** * 权限标识 */ private String permCode; /** * 权限名称 */ private String permName; /** * 父权限ID */ private Long parentPermId; /** * 显示顺序 */ private Integer permSort; /** * 路由地址 */ private String permPath; /** * 权限图标 菜单或目录时可传图标 */ private String permIcon; /** * 权限类型 M菜单 B按钮 */ private String permType; /** * 组件路径 */ private String component; /** * 是否为外部链接 0否 1是 */ private Boolean externalLink; /** * 是否可见 0隐藏 1显示) */ private Boolean visible; /** * 备注 */ private String remark; /** * 状态 0禁用 1正常 */ private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MPost.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Column; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 岗位表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_post", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MPost extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 岗位ID */ private Long postId; /** * 岗位编码 */ private String postCode; /** * 岗位名称 */ private String postName; /** * 显示顺序 */ private Integer postSort; /** * 备注 */ private String remark; /** * 状态 0禁用 1正常 */ private Integer status; /** * 租户编号 */ @Column(tenantId = true) private Long tenantId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MRole.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Column; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 角色表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_role", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MRole extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 角色ID */ private Long roleId; /** * 角色名称 */ private String roleName; /** * 角色编码 */ private String roleCode; /** * 显示顺序 */ private Integer roleSort; /** * 状态 0禁用 1正常 */ private Integer status; /** * 备注 */ private String remark; /** * 租户编号 */ @Column(tenantId = true) private Long tenantId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MRoleDept.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 角色与部门关联表 1角色-N部门 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode @Table(value = "m_role_dept") public class MRoleDept implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 角色ID */ private Long roleId; /** * 部门ID */ private Long deptId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MRolePerm.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 角色与权限关联表 1角色-N权限 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode @Table(value = "m_role_perm") public class MRolePerm implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 角色ID */ private Long roleId; /** * 权限ID */ private Long permId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MStorage.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 存储管理表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_storage", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MStorage extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; private Long storageId; /** * 名称 */ private String storageName; /** * 存储类型,用于标识存储平台,如本地、阿里云oss、七牛云oss等 */ private String storageType; /** * 说明 */ private String description; /** * 存储配置,JSON数据 */ private String storageConfig; /** * 状态 */ private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MTenant.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import java.time.LocalDateTime; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 租户表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_tenant", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MTenant extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 租户ID */ private Long tenantId; /** * 用户ID */ private Long userId; /** * 租户套餐ID */ private Long packageId; /** * 租户名 */ private String tenantName; /** * 租户过期时间 */ private LocalDateTime expireTime; /** * 可创建账号数量 */ private Integer accountCount; /** * 数据隔离方式 column字段隔离(默认) db数据库隔离 */ private String dataIsolation; /** * 数据源名称 master默认使用主库 */ private String datasource; /** * 存储ID 表示该租户使用哪个文件存储 */ private Long storageId; /** * 状态 0禁用 1正常 */ private Integer status; /** * 备注 */ private String remark; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MTenantDatasource.java ================================================ package com.minimalist.basic.entity.po; import com.mybatisflex.annotation.Id; import com.mybatisflex.annotation.KeyType; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 租户数据源表 实体类。 * * @author asus * @since 2025-02-14 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode @Table(value = "m_tenant_datasource") public class MTenantDatasource implements Serializable { @Serial private static final long serialVersionUID = 1L; /** ID自增 */ @Id(keyType = KeyType.Auto) private Long id; /** * 数据源ID */ private Long datasourceId; /** * 租户ID */ private Long tenantId; /** * 数据源名称 */ private String datasourceName; /** * 数据源连接 */ private String datasourceUrl; /** * 数据源用户名 */ private String username; /** * 数据源密码 */ private String password; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MTenantPackage.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 租户套餐表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_tenant_package", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MTenantPackage extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 套餐ID */ private Long packageId; /** * 套餐名称 */ private String packageName; /** * 状态 0禁用 1正常 */ private Integer status; /** * 备注 */ private String remark; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MTenantPackagePerm.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 租户套餐与权限关联表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode @Table(value = "m_tenant_package_perm") public class MTenantPackagePerm implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 租户套餐ID */ private Long packageId; /** * 权限ID */ private Long permId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MUser.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Column; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 用户表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Table(value = "m_user", onInsert = InsertFullColumnHandler.class, onUpdate = UpdateFullColumnHandler.class) public class MUser extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 用户ID */ private Long userId; /** * 用户账号 */ private String username; /** * 密码 */ private String password; /** * 盐值 */ private String salt; /** * 用户昵称 */ private String nickname; /** * 用户真实姓名 */ private String userRealName; /** * 用户邮箱 */ private String email; /** * 手机号码 */ private String phone; /** * 用户性别 0未知 1男 2女 */ private Integer userSex; /** * 头像base64编码 */ private String userAvatar; /** * 备注 */ private String remark; /** * 状态 0禁用 1正常 */ private Integer status; /** * 租户编号 */ @Column(tenantId = true) private Long tenantId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MUserDept.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 用户与岗位关联表 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode @Table(value = "m_user_dept") public class MUserDept implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 用户ID */ private Long userId; /** * 部门ID */ private Long deptId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MUserPost.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 用户与岗位关联表 1用户-N岗位 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode @Table(value = "m_user_post") public class MUserPost implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 用户ID */ private Long userId; /** * 岗位ID */ private Long postId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/po/MUserRole.java ================================================ package com.minimalist.basic.entity.po; import com.minimalist.basic.config.mybatis.InsertFullColumnHandler; import com.minimalist.basic.config.mybatis.UpdateFullColumnHandler; import com.minimalist.basic.config.mybatis.bo.BaseEntity; import com.mybatisflex.annotation.Table; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.EqualsAndHashCode; import java.io.Serial; /** * 用户与角色关联表 1用户-N角色 实体类。 * * @author 小太阳 * @since 2024-10-18 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode @Table(value = "m_user_role") public class MUserRole implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 用户ID */ private Long userId; /** * 角色ID */ private Long roleId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/config/ConfigQueryVO.java ================================================ package com.minimalist.basic.entity.vo.config; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "参数配置查询实体") public class ConfigQueryVO extends PageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "configName", description = "参数名称", type = "string") private String configName; @Schema(name = "configKey", description = "参数键名", type = "string") private String configKey; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "参数配置状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/config/ConfigVO.java ================================================ package com.minimalist.basic.entity.vo.config; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "参数配置实体") public class ConfigVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotNull(message = "参数ID不能为空", groups = {Update.class}) @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "configId", description = "参数ID", type = "string") private Long configId; @NotBlank(message = "参数名称不能为空", groups = {Add.class, Update.class}) @Schema(name = "configName", description = "参数名称", type = "string") private String configName; @NotBlank(message = "参数键名不能为空", groups = {Add.class, Update.class}) @Schema(name = "configKey", description = "参数键名", type = "string") private String configKey; @NotBlank(message = "参数键值不能为空", groups = {Add.class, Update.class}) @Schema(name = "configValue", description = "参数键值", type = "string") private String configValue; @Schema(name = "description", description = "说明", type = "string") private String description; @SchemaEnum(implementation = StatusEnum.class) @NotNull(message = "参数配置状态不能为空", groups = {Update.class}) @Schema(name = "status", description = "参数配置状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/dept/DeptQueryVO.java ================================================ package com.minimalist.basic.entity.vo.dept; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "部门查询实体") public class DeptQueryVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "deptName", description = "部门名称", type = "string") private String deptName; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "部门状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/dept/DeptVO.java ================================================ package com.minimalist.basic.entity.vo.dept; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.util.List; @Data @Schema(name = "部门实体") public class DeptVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotNull(message = "部门ID不能为空", groups = {Update.class}) @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "deptId", description = "部门id", type = "string") private Long deptId; @NotNull(message = "上级部门ID不能为空", groups = {Add.class, Update.class}) @Schema(name = "parentDeptId", description = "父部门ID", type = "string") @JsonSerialize(using = ToStringSerializer.class) private Long parentDeptId; @Schema(name = "ancestors", description = "祖级列表", type = "string") private String ancestors; @NotBlank(message = "部门名称不能为空", groups = {Add.class, Update.class}) @Schema(name = "deptName", description = "部门名称", type = "string") private String deptName; @NotNull(message = "排序值不能为空", groups = {Add.class, Update.class}) @Schema(name = "deptSort", description = "排序值", type = "integer") private Integer deptSort; @NotNull(message = "部门负责人不能为空", groups = {Add.class, Update.class}) @Schema(name = "deptLeader", description = "部门负责人", type = "string") @JsonSerialize(using = ToStringSerializer.class) private Long deptLeader; @NotBlank(message = "部门电话不能为空", groups = {Add.class, Update.class}) @Schema(name = "phone", description = "部门电话", type = "string") private String phone; @NotBlank(message = "部门邮箱不能为空", groups = {Add.class, Update.class}) @Schema(name = "email", description = "部门邮箱", type = "string") private String email; @SchemaEnum(implementation = StatusEnum.class) @NotNull(message = "部门状态不能为空", groups = {Update.class}) @Schema(name = "status", description = "部门状态", type = "integer") private Integer status; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "tenantId", description = "租户ID", type = "string") private Long tenantId; @Schema(name = "children", description = "部门子集", type = "array") private List children; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/dict/DictCacheVO.java ================================================ package com.minimalist.basic.entity.vo.dict; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.util.List; @Data @Schema(name = "字典数据实体 - 一般用于下拉框的数据展示或编码转换使用") public class DictCacheVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @Data @Schema(name = "字典key和value实体") public static class DictKV { @Schema(name = "dictKey", description = "字典key,字典编码", type = "string") private String dictKey; @Schema(name = "dictValue", description = "字典value,字典编码对应的中文", type = "string") private String dictValue; @Schema(name = "dictType", description = "字典类型", type = "string") private String dictType; @Schema(name = "dictClass", description = "字典样式,对应前端Tag组件的type", type = "string") private String dictClass; } @Schema(name = "dictType", description = "字典类型", type = "string") private String dictType; @Schema(name = "dictList", description = "字典列表", type = "array") private List dictList; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/dict/DictDataVO.java ================================================ package com.minimalist.basic.entity.vo.dict; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "字典数据实体") public class DictDataVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "dictId", description = "字典ID", type = "string") private Long dictId; @NotBlank(message = "字典key不能为空") @Schema(name = "dictKey", description = "字典key", type = "string") private String dictKey; @NotBlank(message = "字典value不能为空") @Schema(name = "dictValue", description = "字典value", type = "string") private String dictValue; @NotNull(message = "字典排序值不能为空") @Schema(name = "dictOrder", description = "字典排序值", type = "integer") private Integer dictOrder; @Schema(name = "dictClass", description = "字典样式,对应前端Tag组件的type", type = "string") private String dictClass; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "字典状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/dict/DictInfoVO.java ================================================ package com.minimalist.basic.entity.vo.dict; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.util.List; @Data @Schema(name = "字典基础信息实体") public class DictInfoVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotBlank(message = "字典类型不能为空") @Schema(name = "dictType", description = "字典类型", type = "string") private String dictType; @NotBlank(message = "字典名称不能为空") @Schema(name = "dictName", description = "字典名称", type = "string") private String dictName; @NotBlank(message = "字典描述不能为空") @Schema(name = "dictDesc", description = "字典描述", type = "string") private String dictDesc; @NotEmpty(message = "字典数据不能为空") @Schema(name = "dictDataList", description = "字典数据列表", type = "array") private List dictDataList; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/dict/DictListVO.java ================================================ package com.minimalist.basic.entity.vo.dict; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.util.List; @Data @Schema(name = "字典列表实体") public class DictListVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "dictType", description = "字典类型", type = "string") private String dictType; @Schema(name = "dictList", description = "字典列表", type = "array") private List dictList; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/dict/DictQueryVO.java ================================================ package com.minimalist.basic.entity.vo.dict; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.entity.enums.StatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "字典查询实体") public class DictQueryVO extends PageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "dictName", description = "字典名称", type = "string") private String dictName; @Schema(name = "dictType", description = "字典类型", type = "string") private String dictType; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "字典状态", type = "int") private Byte status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/dict/DictVO.java ================================================ package com.minimalist.basic.entity.vo.dict; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "字典管理实体") public class DictVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "dictId", description = "字典ID", type = "string") private Long dictId; @Schema(name = "dictType", description = "字典类型", type = "string") private String dictType; @Schema(name = "dictKey", description = "字典key", type = "string") private String dictKey; @Schema(name = "dictValue", description = "字典value", type = "string") private String dictValue; @Schema(name = "dictName", description = "字典名称", type = "string") private String dictName; @Schema(name = "dictDesc", description = "字典描述", type = "string") private String dictDesc; @Schema(name = "dictOrder", description = "字典排序值", type = "integer") private Integer dictOrder; @Schema(name = "dictClass", description = "字典样式,对应前端Tag组件的type", type = "string") private String dictClass; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "字典状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/file/FileQueryVO.java ================================================ package com.minimalist.basic.entity.vo.file; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "文件查询实体") public class FileQueryVO extends PageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "fileName", description = "文件名", type = "string") private String fileName; @Schema(name = "fileSource", description = "文件来源", type = "string") private Integer fileSource; @Schema(name = "fileType", description = "文件类型,由字典配置,与file表file_type字段对应", type = "string") private String fileType; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "文件状态", type = "int") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/file/FileUploadBatchVO.java ================================================ package com.minimalist.basic.entity.vo.file; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; import org.springframework.web.multipart.MultipartFile; import java.io.Serial; import java.io.Serializable; import java.util.List; @Data @Schema(name = "文件上传实体") public class FileUploadBatchVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotEmpty(message = "上传的文件不能为空") @Schema(name = "files", description = "文件列表(支持多个文件)", type = "array") private List files; @NotNull(message = "文件来源不能为空") @Schema(name = "fileSource", description = "文件来源,字典:file-source-path", type = "int") private Integer fileSource; @Schema(name = "storageId", description = "存储ID,可为空。为空则取默认使用的存储", type = "int") private Long storageId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/file/FileUploadRespVO.java ================================================ package com.minimalist.basic.entity.vo.file; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.config.convert.FileSizeSerializer; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "文件上传响应实体") public class FileUploadRespVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "fileId", description = "文件ID", type = "string") private Long fileId; @Schema(name = "fileName", description = "文件名称", type = "string") private String fileName; @Schema(name = "filePath", description = "文件路径", type = "string") private String filePath; @Schema(name = "fileUrl", description = "文件URL", type = "string") private String fileUrl; @Schema(name = "fileType", description = "文件类型", type = "string") private String fileType; @Schema(name = "fileSuffix", description = "文件后缀", type = "string") private String fileSuffix; @JsonSerialize(using = FileSizeSerializer.class) @Schema(name = "fileSize", description = "文件大小", type = "string") private Long fileSize; @Schema(name = "fileSource", description = "文件来源", type = "string") private Integer fileSource; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/file/FileUploadVO.java ================================================ package com.minimalist.basic.entity.vo.file; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; import org.springframework.web.multipart.MultipartFile; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "文件上传实体") public class FileUploadVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotNull(message = "上传的文件不能为空") @Schema(name = "file", description = "文件(单个文件)", type = "file") private MultipartFile file; @Schema(name = "fileSource", description = "文件来源,字典:file-source-path", type = "int") private Integer fileSource = -1; @Schema(name = "storageId", description = "存储ID,可为空。为空则取默认使用的存储", type = "int") private Long storageId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/file/FileVO.java ================================================ package com.minimalist.basic.entity.vo.file; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.config.convert.FileSizeDeserializer; import com.minimalist.basic.config.convert.FileSizeSerializer; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "文件实体") public class FileVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "fileId", description = "文件ID", type = "string") private Long fileId; @Schema(name = "fileName", description = "文件名", type = "string") private String fileName; @JsonSerialize(using = FileSizeSerializer.class) @JsonDeserialize(using = FileSizeDeserializer.class) @Schema(name = "fileSize", description = "文件大小", type = "string") private Long fileSize; @Schema(name = "fileType", description = "文件类型", type = "string") private String fileType; @Schema(name = "fileType", description = "文件类型后缀", type = "string") private String fileTypeSuffix; @Schema(name = "fileUrl", description = "文件URL", type = "string") private String fileUrl; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "fileSource", description = "文件来源", type = "int") private Integer fileSource; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "storageId", description = "存储ID", type = "string") private Long storageId; @Schema(name = "fileThUrl", description = "文件缩略图URL", type = "string") private String fileThUrl; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "文件状态", type = "int") private Integer status; @Schema(name = "remark", description = "备注", type = "string") private String remark; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/notice/NoticeQueryVO.java ================================================ package com.minimalist.basic.entity.vo.notice; import com.minimalist.basic.entity.enums.NoticeEnum; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "公告查询实体") public class NoticeQueryVO extends PageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "noticeTitle", description = "公告标题", type = "string") private String noticeTitle; @SchemaEnum(implementation = NoticeEnum.NoticeType.class) @Schema(name = "noticeType", description = "公告类型", type = "string") private Integer noticeType; @NotNull(message = "公告状态不能为空", groups = {Add.class, Update.class}) @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "公告状态", type = "string") private Byte status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/notice/NoticeVO.java ================================================ package com.minimalist.basic.entity.vo.notice; import cn.hutool.core.date.DatePattern; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.entity.enums.NoticeEnum; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.entity.vo.file.FileVO; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serial; import java.io.Serializable; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @Data @Schema(name = "公告管理实体") public class NoticeVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotNull(message = "公告ID不能为空", groups = {Update.class}) @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "noticeId", description = "公告ID", type = "string") private Long noticeId; @NotBlank(message = "公告标题不能为空", groups = {Add.class, Update.class}) @Schema(name = "noticeTitle", description = "公告标题", type = "string") private String noticeTitle; @NotNull(message = "公告类型不能为空", groups = {Add.class, Update.class}) @SchemaEnum(implementation = NoticeEnum.NoticeType.class) @Schema(name = "noticeType", description = "公告类型", type = "string") private Integer noticeType; @NotBlank(message = "公告内容不能为空", groups = {Add.class, Update.class}) @Schema(name = "noticeContent", description = "公告内容", type = "string") private String noticeContent; @Schema(name = "noticePicFileId", description = "公告封面图文件ID,多张 , 分割", type = "string") private String noticePicFileId; @Schema(name = "noticePicFile", description = "公告封面图文件信息,新增和修改时直接传入文件信息", type = "array") private List noticePicFile = new ArrayList<>(); @Schema(name = "noticeTop", description = "是否置顶", type = "string") private Boolean noticeTop; @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @Schema(name = "noticeTimeInterval", description = "延期发布时间", type = "string") private LocalDateTime noticeTimeInterval; @Schema(name = "noticeSort", description = "排序值", type = "string") private Integer noticeSort; @Schema(name = "noticeOutChain", description = "是否外链", type = "string") private Boolean noticeOutChain; @Schema(name = "noticeLink", description = "外部链接", type = "string") private String noticeLink; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "publishDeptId", description = "发布部门ID", type = "string") private Long publishDeptId; @JsonSerialize(using = ToStringSerializer.class) @NotNull(message = "发布人不能为空", groups = {Add.class, Update.class}) @Schema(name = "publishAuthorId", description = "发布人ID", type = "string") private Long publishAuthorId; @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @Schema(name = "publishTime", description = "发布时间", type = "string") private LocalDateTime publishTime; @NotNull(message = "公告状态不能为空", groups = {Add.class, Update.class}) @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "公告状态", type = "string") private Byte status; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "createId", description = "创建人ID", type = "string") private Long createId; @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @Schema(name = "createTime", description = "创建时间", type = "string") private LocalDateTime createTime; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/perm/PermQueryVO.java ================================================ package com.minimalist.basic.entity.vo.perm; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "权限查询实体") public class PermQueryVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "permName", description = "权限名称", type = "string") private String permName; @Schema(name = "permType", description = "权限类型", type = "string") private String permType; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/perm/PermVO.java ================================================ package com.minimalist.basic.entity.vo.perm; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.entity.enums.PermEnum; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.util.List; import java.io.Serializable; @Data @Schema(name = "权限实体") public class PermVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotNull(message = "权限ID不能为空", groups = {Update.class}) @Schema(name = "permId", description = "权限ID", type = "string") @JsonSerialize(using = ToStringSerializer.class) private Long permId; @Schema(name = "permCode", description = "权限编码", type = "string") private String permCode; @NotBlank(message = "权限名称不能为空", groups = {Add.class, Update.class}) @Schema(name = "permName", description = "权限名称", type = "string") private String permName; @NotNull(message = "上级权限ID不能为空", groups = {Add.class, Update.class}) @Schema(name = "parentPermId", description = "父权限ID", type = "string") @JsonSerialize(using = ToStringSerializer.class) private Long parentPermId; @NotNull(message = "排序值不能为空", groups = {Add.class, Update.class}) @Schema(name = "permSort", description = "排序值", type = "integer") private Integer permSort; @Schema(name = "permPath", description = "路由地址", type = "string") private String permPath; @Schema(name = "permIcon", description = "权限图标,菜单可传图标", type = "string") private String permIcon; @SchemaEnum(implementation = PermEnum.PermType.class) @Schema(name = "permType", description = "权限类型", type = "string") private String permType; @Schema(name = "component", description = "组件路径", type = "string") private String component; @NotNull(message = "是否可见不能为空", groups = {Add.class, Update.class}) @Schema(name = "visible", description = "是否可见", type = "boolean") private Boolean visible; @SchemaEnum(implementation = StatusEnum.class) @NotNull(message = "权限状态不能为空", groups = {Update.class}) @Schema(name = "status", description = "权限状态", type = "integer") private Integer status; @Schema(name = "remark", description = "备注", type = "string") private String remark; @Schema(name = "children", description = "权限子集", type = "array") private List children; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/post/PostQueryVO.java ================================================ package com.minimalist.basic.entity.vo.post; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "岗位查询实体") public class PostQueryVO extends PageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "postName", description = "岗位名称", type = "string") private String postName; @Schema(name = "postCode", description = "岗位编码", type = "string") private String postCode; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "岗位状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/post/PostVO.java ================================================ package com.minimalist.basic.entity.vo.post; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "岗位实体") public class PostVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotNull(message = "岗位ID不能为空", groups = {Update.class}) @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "postId", description = "岗位ID", type = "string") private Long postId; @NotBlank(message = "岗位编码不能为空", groups = {Add.class, Update.class}) @Schema(name = "postCode", description = "岗位编码", type = "string") private String postCode; @NotBlank(message = "岗位名称不能为空", groups = {Add.class, Update.class}) @Schema(name = "postName", description = "岗位名称", type = "string") private String postName; @NotNull(message = "排序值不能为空", groups = {Add.class, Update.class}) @Schema(name = "postSort", description = "排序", type = "integer") private Integer postSort; @Schema(name = "remark", description = "备注", type = "string") private String remark; @NotNull(message = "岗位状态不能为空", groups = {Update.class}) @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "岗位状态", type = "integer") private Integer status; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "tenantId", description = "租户ID", type = "string") private Long tenantId; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/role/RoleQueryVO.java ================================================ package com.minimalist.basic.entity.vo.role; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "角色查询实体") public class RoleQueryVO extends PageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "roleName", description = "角色名称", type = "string") private String roleName; @Schema(name = "roleCode", description = "角色编码", type = "string") private String roleCode; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "角色状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/role/RoleVO.java ================================================ package com.minimalist.basic.entity.vo.role; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.config.convert.LongArrJsonSerializer; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.util.List; @Data @Schema(name = "角色实体") public class RoleVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @JsonSerialize(using = ToStringSerializer.class) @NotNull(message = "角色ID不能为空", groups = {Update.class}) @Schema(name = "roleId", description = "角色ID", type = "string") private Long roleId; @NotBlank(message = "角色名称不能为空", groups = {Add.class, Update.class}) @Schema(name = "roleName", description = "角色名称", type = "string") private String roleName; @NotBlank(message = "角色编码不能为空", groups = {Add.class, Update.class}) @Schema(name = "roleCode", description = "角色编码", type = "string") private String roleCode; @NotNull(message = "排序值不能为空", groups = {Add.class, Update.class}) @Schema(name = "roleSort", description = "排序", type = "integer") private Integer roleSort; @NotNull(message = "角色状态不能为空", groups = {Update.class}) @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "角色状态", type = "integer") private Integer status; @Schema(name = "remark", description = "备注", type = "string") private String remark; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "tenantId", description = "租户ID", type = "string") private Long tenantId; @Schema(name = "checkedPermIds", description = "角色权限编码集合,用于回显", type = "array") private List checkedPermIds; @JsonSerialize(using = LongArrJsonSerializer.class) @NotEmpty(message = "角色权限不能为空", groups = {Add.class, Update.class}) @Schema(name = "permissionsIds", description = "角色权限编码集合,全勾选+半勾选的节点", type = "array") private List permissionsIds; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/storage/StorageQueryVO.java ================================================ package com.minimalist.basic.entity.vo.storage; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "存储信息查询实体") public class StorageQueryVO extends PageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "storageName", description = "存储名称", type = "string") private String storageName; @Schema(name = "storageType", description = "存储类型", type = "string") private String storageType; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "存储状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/storage/StorageVO.java ================================================ package com.minimalist.basic.entity.vo.storage; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "存储信息实体") public class StorageVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @JsonSerialize(using = ToStringSerializer.class) @NotNull(message = "存储ID不能为空", groups = {Update.class}) @Schema(name = "storageId", description = "存储ID", type = "string") private Long storageId; @NotBlank(message = "存储名称不能为空", groups = {Add.class, Update.class}) @Schema(name = "storageName", description = "存储名称", type = "string") private String storageName; @NotBlank(message = "存储类型不能为空", groups = {Add.class, Update.class}) @Schema(name = "storageType", description = "存储类型", type = "string") private String storageType; @Schema(name = "description", description = "说明", type = "integer") private String description; @NotBlank(message = "存储配置不能为空", groups = {Add.class, Update.class}) @Schema(name = "storageConfig", description = "存储配置", type = "string") private String storageConfig; @NotNull(message = "存储状态不能为空", groups = {Update.class}) @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "存储状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/tenant/TenantDatasourceVO.java ================================================ package com.minimalist.basic.entity.vo.tenant; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.*; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "租户数据源实体") public class TenantDatasourceVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotBlank(message = "数据源名称不能为空", groups = {Add.class, Update.class}) @Schema(name = "datasourceName", description = "数据源连接", type = "string") private String datasourceName; @NotBlank(message = "数据源连接不能为空", groups = {Add.class, Update.class}) @Schema(name = "datasourceUrl", description = "数据源连接", type = "string") private String datasourceUrl; @NotBlank(message = "数据源用户名不能为空", groups = {Add.class, Update.class}) @Schema(name = "username", description = "数据源用户名", type = "string") private String username; @NotBlank(message = "数据源密码不能为空", groups = {Add.class, Update.class}) @Schema(name = "password", description = "数据源密码", type = "string") private String password; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/tenant/TenantPackageQueryVO.java ================================================ package com.minimalist.basic.entity.vo.tenant; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "租户套餐查询实体") public class TenantPackageQueryVO extends PageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "packageName", description = "套餐名称", type = "string") private String packageName; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "租户套餐状态", type = "integer") private Byte status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/tenant/TenantPackageVO.java ================================================ package com.minimalist.basic.entity.vo.tenant; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.config.convert.LongArrJsonSerializer; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.util.List; @Data @Schema(name = "租户套餐实体") public class TenantPackageVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @JsonSerialize(using = ToStringSerializer.class) @NotNull(message = "租户套餐ID不能为空", groups = {Update.class}) @Schema(name = "packageId", description = "租户套餐ID", type = "string") private Long packageId; @NotNull(message = "套餐名称能为空", groups = {Add.class, Update.class}) @Schema(name = "packageName", description = "套餐名称", type = "string") private String packageName; @NotNull(message = "租户套餐状态不能为空", groups = {Update.class}) @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "租户套餐状态", type = "integer") private Byte status; @Schema(name = "remark", description = "备注", type = "string") private String remark; @Schema(name = "checkedPermIds", description = "租户套餐权限编码集合,用于回显", type = "array") private List checkedPermIds; @JsonSerialize(using = LongArrJsonSerializer.class) @NotEmpty(message = "租户套餐权限不能为空", groups = {Add.class, Update.class}) @Schema(name = "permissionsIds", description = "租户套餐权限编码集合", type = "array") private List permissionsIds; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/tenant/TenantQueryVO.java ================================================ package com.minimalist.basic.entity.vo.tenant; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "租户查询实体") public class TenantQueryVO extends PageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "tenantName", description = "租户名", type = "string") private String tenantName; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "租户状态", type = "integer") private Byte status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/tenant/TenantVO.java ================================================ package com.minimalist.basic.entity.vo.tenant; import cn.hutool.core.date.DatePattern; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.entity.enums.TenantEnum; import com.minimalist.basic.entity.vo.storage.StorageVO; import com.minimalist.basic.entity.vo.user.UserVO; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serial; import java.io.Serializable; import java.time.LocalDateTime; @Data @Schema(name = "租户实体") public class TenantVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @JsonSerialize(using = ToStringSerializer.class) @NotNull(message = "租户ID不能为空", groups = {Update.class}) @Schema(name = "tenantId", description = "租户ID", type = "string") private Long tenantId; @JsonSerialize(using = ToStringSerializer.class) @NotNull(message = "租户联系人不能为空", groups = {Update.class}) @Schema(name = "userId", description = "用户ID,与租户绑定", type = "string") private Long userId; @Schema(name = "contactName", description = "联系人昵称,回显联系人使用", type = "string") private String contactName; @Schema(name = "email", description = "联系人邮箱,回显联系人使用", type = "string") private String email; @Schema(name = "phone", description = "联系人号码,回显联系人使用", type = "string") private String phone; @JsonSerialize(using = ToStringSerializer.class) @NotNull(message = "租户套餐ID不能为空", groups = {Add.class, Update.class}) @Schema(name = "packageId", description = "租户套餐ID", type = "string") private Long packageId; @NotBlank(message = "租户名不能为空", groups = {Add.class, Update.class}) @Schema(name = "tenantName", description = "租户名", type = "string") private String tenantName; @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @NotNull(message = "租户过期时间不能为空", groups = {Add.class, Update.class}) @Schema(name = "expireTime", description = "租户过期时间", type = "string") private LocalDateTime expireTime; @NotNull(message = "可创建账号数量不能为空", groups = {Add.class, Update.class}) @Schema(name = "accountCount", description = "可创建账号数量,表示这个租户下可以创建多少账号", type = "integer") private Integer accountCount; @NotBlank(message = "数据隔离方式不能为空", groups = {Add.class, Update.class}) @SchemaEnum(implementation = TenantEnum.DataIsolation.class) @Schema(name = "dataIsolation", description = "数据隔离方式", type = "string") private String dataIsolation; @Schema(name = "datasource", description = "所使用的数据源,默认使用master主库", type = "string") private String datasource; @JsonSerialize(using = ToStringSerializer.class) @NotNull(message = "存储ID不能为空", groups = {Add.class, Update.class}) @Schema(name = "storageId", description = "存储ID 表示该租户使用哪个文件存储", type = "string") private Long storageId; @NotNull(message = "租户状态不能为空", groups = {Update.class}) @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "租户状态", type = "integer") private Byte status; @Schema(name = "remark", description = "备注", type = "string") private String remark; @NotNull(message = "租户的用户信息不能为空", groups = {Add.class}) @Schema(name = "user", description = "租户的用户信息,新增时填充", type = "object") private UserVO user; @NotNull(message = "租户数据源不能为空", groups = {Add.class}) @Schema(name = "tenantDatasource", description = "租户数据源", type = "object") private TenantDatasourceVO tenantDatasource; @Schema(name = "tenantDatasource", description = "租户文件存储", type = "object") private StorageVO storage; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/user/ImageCaptchaVO.java ================================================ package com.minimalist.basic.entity.vo.user; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "图形验证码响应实体") public class ImageCaptchaVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "enable", description = "是否启用验证码", type = "boolean") private boolean enable; @Schema(name = "captchaId", description = "验证码ID", type = "string") private String captchaId; @Schema(name = "captchaImg", description = "验证码图片Base64编码", type = "string") private String captchaImg; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/user/RePasswordVO.java ================================================ package com.minimalist.basic.entity.vo.user; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "用户重置密码实体") public class RePasswordVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotBlank(message = "旧密码不能为空") @Schema(name = "oldPassword", description = "旧密码", type = "string") private String oldPassword; @NotBlank(message = "新密码不能为空") @Schema(name = "newPassword", description = "新密码", type = "string") private String newPassword; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/user/UserInfoVO.java ================================================ package com.minimalist.basic.entity.vo.user; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.entity.vo.dept.DeptVO; import com.minimalist.basic.entity.vo.perm.PermVO; import com.minimalist.basic.entity.vo.post.PostVO; import com.minimalist.basic.entity.enums.UserEnum; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.util.List; import java.util.Set; @Data @Schema(name = "用户实体") public class UserInfoVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "userId", description = "用户ID", type = "string") @JsonSerialize(using = ToStringSerializer.class) private Long userId; @Schema(name = "username", description = "用户账号", type = "string") private String username; /** 用户密码 */ @JsonIgnore private String password; @Schema(name = "nickname", description = "用户昵称", type = "string") private String nickname; @Schema(name = "userRealName", description = "用户真实姓名", type = "string") private String userRealName; @Schema(name = "email", description = "用户邮箱", type = "string") private String email; @Schema(name = "phone", description = "手机号码", type = "string") private String phone; @SchemaEnum(implementation = UserEnum.UserSex.class) @Schema(name = "userSex", description = "用户性别", type = "integer") private Integer userSex; @Schema(name = "userAvatar", description = "用户头像base64编码", type = "string") private String userAvatar; @Schema(name = "remark", description = "备注", type = "string") private String remark; @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "用户状态", type = "integer") private Integer status; @Schema(name = "tenantId", description = "租户编号", type = "string") @JsonSerialize(using = ToStringSerializer.class) private Long tenantId; @Schema(name = "perms", description = "用户权限标识符", type = "array") private Set perms; @Schema(name = "roles", description = "用户角色标识符", type = "array") private Set roles; @Schema(name = "deptList", description = "用户所属部门信息", type = "array") private List deptList; @Schema(name = "postList", description = "用户岗位信息", type = "array") private List postList; @Schema(name = "menus", description = "用户菜单") private List menus; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/user/UserLoginReqVO.java ================================================ package com.minimalist.basic.entity.vo.user; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "用户登录请求实体") public class UserLoginReqVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotBlank(message = "用户名不能为空") @Schema(name = "username", description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, type = "string") private String username; @NotBlank(message = "密码不能为空") @Schema(name = "password", description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, type = "string") private String password; @Schema(name = "captchaId", description = "验证码ID,与验证码一一对应", type = "string") private String captchaId; @Schema(name = "captcha", description = "验证码", type = "string") private String captcha; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/user/UserQueryVO.java ================================================ package com.minimalist.basic.entity.vo.user; import com.minimalist.basic.config.mybatis.bo.PageReq; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "用户查询实体") public class UserQueryVO extends PageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; @Schema(name = "userRealName", description = "用户真实姓名", type = "string") private String userRealName; @Schema(name = "phone", description = "手机号码", type = "string") private String phone; @Schema(name = "dept", description = "选择的部门", type = "string") private Long deptId; @Schema(name = "status", description = "用户状态", type = "integer") private Integer status; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/user/UserSettingVO.java ================================================ package com.minimalist.basic.entity.vo.user; import com.minimalist.basic.entity.enums.UserEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.io.Serializable; @Data @Schema(name = "用户设置实体") public class UserSettingVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @NotBlank(message = "用户昵称不能为空") @Schema(name = "nickname", description = "用户昵称", type = "string") private String nickname; @NotBlank(message = "用户真实姓名不能为空") @Schema(name = "userRealName", description = "用户真实姓名", type = "string") private String userRealName; @NotBlank(message = "手机号不能为空") @Schema(name = "phone", description = "手机号码", type = "string") private String phone; @Schema(name = "email", description = "用户邮箱,可为空", type = "string") private String email; @NotNull(message = "用户性别不能为空") @SchemaEnum(implementation = UserEnum.UserSex.class) @Schema(name = "userSex", description = "用户性别", type = "integer") private Integer userSex; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/entity/vo/user/UserVO.java ================================================ package com.minimalist.basic.entity.vo.user; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.NullSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.minimalist.basic.config.convert.LongArrJsonSerializer; import com.minimalist.basic.entity.enums.UserEnum; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.swagger.SchemaEnum; import com.minimalist.basic.utils.Add; import com.minimalist.basic.utils.Update; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.util.List; import java.util.Set; @Data @Schema(name = "用户管理实体") public class UserVO implements Serializable { @Serial private static final long serialVersionUID = 1L; @JsonSerialize(using = ToStringSerializer.class) @NotNull(message = "用户ID不能为空", groups = {Update.class}) @Schema(name = "userId", description = "用户ID", type = "string") private Long userId; @NotBlank(message = "用户账号不能为空", groups = {Add.class, Update.class}) @Schema(name = "username", description = "用户账号", type = "string") private String username; @JsonSerialize(using = NullSerializer.class) @Schema(name = "password", description = "密码", type = "string") private String password; @NotBlank(message = "用户昵称不能为空", groups = {Add.class, Update.class}) @Schema(name = "nickname", description = "用户昵称", type = "string") private String nickname; @NotBlank(message = "用户真实姓名不能为空", groups = {Add.class, Update.class}) @Schema(name = "userRealName", description = "用户真实姓名", type = "string") private String userRealName; @NotBlank(message = "手机号不能为空", groups = {Add.class, Update.class}) @Schema(name = "phone", description = "手机号码", type = "string") private String phone; @Schema(name = "email", description = "用户邮箱,可为空", type = "string") private String email; @NotNull(message = "用户性别不能为空", groups = {Add.class, Update.class}) @SchemaEnum(implementation = UserEnum.UserSex.class) @Schema(name = "userSex", description = "用户性别", type = "integer") private Integer userSex; @Schema(name = "userAvatar", description = "用户头像base64编码", type = "string") private String userAvatar; @Schema(name = "remark", description = "备注", type = "string") private String remark; @NotNull(message = "用户状态不能为空", groups = {Update.class}) @SchemaEnum(implementation = StatusEnum.class) @Schema(name = "status", description = "用户状态", type = "integer") private Integer status; @JsonSerialize(using = ToStringSerializer.class) @Schema(name = "tenantId", description = "租户编号", type = "string") private Long tenantId; @JsonSerialize(using = LongArrJsonSerializer.class) @NotEmpty(message = "角色不能为空", groups = {Add.class, Update.class}) @Schema(name = "roles", description = "角色ID集合", type = "array") private Set roleIds; @JsonSerialize(using = LongArrJsonSerializer.class) @Schema(name = "postIds", description = "岗位ID集合", type = "array") private Set postIds; @JsonSerialize(using = LongArrJsonSerializer.class) @Schema(name = "deptIds", description = "部门ID集合", type = "array") private Set deptIds; @Schema(name = "checkedPermIds", description = "用户部门编码集合,全勾选的节点", type = "array") private List checkedDeptIds; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/manager/TenantManager.java ================================================ package com.minimalist.basic.manager; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.dynamic.datasource.creator.DataSourceProperty; import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; import com.minimalist.basic.entity.enums.*; import com.minimalist.basic.entity.po.*; import com.minimalist.basic.entity.vo.tenant.TenantDatasourceVO; import com.minimalist.basic.mapper.MRolePermMapper; import com.minimalist.basic.mapper.MTenantMapper; import com.minimalist.basic.mapper.MTenantPackagePermMapper; import com.minimalist.basic.mapper.MUserMapper; import com.minimalist.basic.config.exception.BusinessException; import com.mybatisflex.core.logicdelete.LogicDeleteManager; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.time.Duration; import java.time.LocalDateTime; import java.util.List; /** * 租户相关的辅助处理 */ @Component public class TenantManager { @Autowired private MTenantMapper tenantMapper; @Autowired private MUserMapper userMapper; @Autowired private MRolePermMapper rolePermMapper; @Autowired private MTenantPackagePermMapper tenantPackagePermMapper; @Autowired private DataSource dataSource; @Autowired private DefaultDataSourceCreator dataSourceCreator; /** * 检查租户套餐 * @param tenantId 租户ID */ public void checkTenantPackage(long tenantId) { //检查租户下用户数是否满足套餐 MTenant mTenant = tenantMapper.selectTenantByTenantId(tenantId); Assert.notNull(mTenant, () -> new BusinessException(TenantEnum.ErrorMsg.NONENTITY_TENANT.getDesc())); long userCount = userMapper.selectUserCountByTenantId(tenantId); // +1是去除租户本身的用户 Assert.isFalse((userCount + 1) >= mTenant.getAccountCount(), () -> new BusinessException(TenantEnum.ErrorMsg.TENANT_USER_COUNT_LIMIT.getDesc())); //检查租户状态 Assert.isTrue(StatusEnum.STATUS_1.getCode().equals(mTenant.getStatus()), () -> new BusinessException(TenantEnum.ErrorMsg.DISABLED_TENANT.getDesc())); //检查租户是否过期 checkTenantExpireTime(mTenant.getExpireTime()); } /** * 检查租户是否过期 * @param expireTime 租户到期时间 */ public void checkTenantExpireTime(LocalDateTime expireTime) { //获取当天最晚时间,23:59:59 LocalDateTime localDateTime = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); //检查租户是否过期 Duration duration = LocalDateTimeUtil.between(localDateTime, expireTime); //如果租户到期时间 < 当天,返回负,说明已到期 long exHours = duration.toHours(); Assert.isFalse(exHours <= 0, () -> new BusinessException(TenantEnum.ErrorMsg.EX_TENANT.getDesc())); } public void updateTenantPermission(List roleList, Long packageId) { //修改后的套餐权限 List newTpp = tenantPackagePermMapper.selectTenantPackagePermByTenantPackageId(packageId); List permIds = newTpp.stream().map(MTenantPackagePerm::getPermId).toList(); for (MRole role : roleList) { //如果是租户管理员,将套餐所有权限重新分配给租户管理员 if (RoleEnum.Role.ADMIN.getCode().equals(role.getRoleCode())) { //删除旧关联数据 LogicDeleteManager.execWithoutLogicDelete(()-> rolePermMapper.deleteByQuery(QueryWrapper.create().eq(MRolePerm::getRoleId, role.getRoleId())) ); //插入新关联数据 List rolePerms = newTpp.stream().map(tpp -> { MRolePerm rolePerm = new MRolePerm(); rolePerm.setRoleId(role.getRoleId()); rolePerm.setPermId(tpp.getPermId()); return rolePerm; }).toList(); rolePermMapper.insertBatch(rolePerms); } else { //如果是其他角色,删除超出的权限 if (CollectionUtil.isNotEmpty(permIds)) { rolePermMapper.deleteByQuery(QueryWrapper.create() .eq(MRolePerm::getRoleId, role.getRoleId()) .notIn(MRolePerm::getPermId, permIds) ); } } } } /** * 动态添加数据源 * @param tenantId 租户ID * @param tenantDatasourceVO 数据源信息 */ public void dynamicAddDatasource(String tenantId, TenantDatasourceVO tenantDatasourceVO) { DataSourceProperty dataSourceProperty = new DataSourceProperty(); dataSourceProperty.setUrl(tenantDatasourceVO.getDatasourceUrl()); dataSourceProperty.setUsername(tenantDatasourceVO.getUsername()); dataSourceProperty.setPassword(tenantDatasourceVO.getPassword()); DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty); ds.addDataSource(tenantId, dataSource); } /** * 动态删除数据源 * @param tenantId 租户ID */ public void dynamicDeleteDatasource(String tenantId) { //动态删除数据源 DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; ds.removeDataSource(tenantId); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/manager/UserManager.java ================================================ package com.minimalist.basic.manager; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import com.minimalist.basic.entity.po.MUser; import com.minimalist.basic.entity.po.MUserDept; import com.minimalist.basic.entity.po.MUserPost; import com.minimalist.basic.entity.po.MUserRole; import com.minimalist.basic.mapper.MUserDeptMapper; import com.minimalist.basic.mapper.MUserMapper; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.entity.enums.UserEnum; import com.minimalist.basic.mapper.MUserPostMapper; import com.minimalist.basic.mapper.MUserRoleMapper; import com.mybatisflex.core.logicdelete.LogicDeleteManager; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; import java.util.Set; /** * 用户相关的辅助处理 */ @Component public class UserManager { @Autowired private MUserMapper userMapper; @Autowired private MUserRoleMapper userRoleMapper; @Autowired private MUserPostMapper userPostMapper; @Autowired private MUserDeptMapper userDeptMapper; /** * 用户密码加密 * @param password 密码 * @param salt 盐值 * @return 加密后的密码 */ public String passwordEncrypt(String password, String salt) { String p1 = SecureUtil.md5(password + salt); return SecureUtil.md5(p1); } /** * 用户名唯一性校验 * 整个系统中不允许重复的用户名 * @param username 用户名 * @param userId 用户ID,可以被忽略的用户ID */ public void checkUsernameUniqueness(String username, Long userId) { QueryWrapper queryWrapper = QueryWrapper.create().eq(MUser::getUsername, username); if (ObjectUtil.isNotNull(userId)) { queryWrapper.ne(MUser::getUserId, userId); } MUser user = userMapper.selectOneByQuery(queryWrapper); Assert.isNull(user, () -> new BusinessException(UserEnum.ErrorMsg.EXISTS_ACCOUNT.getDesc())); } /** * 用户邮箱唯一性校验 * 邮箱不允许重复 * @param email 用户邮箱 * @param userId 用户ID,可以被忽略的用户ID */ public void checkUserEmailUniqueness(String email, Long userId) { if (StrUtil.isBlank(email)) { return; } QueryWrapper queryWrapper = QueryWrapper.create().eq(MUser::getEmail, email); if (ObjectUtil.isNotNull(userId)) { queryWrapper.ne(MUser::getUserId, userId); } MUser user = userMapper.selectOneByQuery(queryWrapper); Assert.isNull(user, () -> new BusinessException(UserEnum.ErrorMsg.EMAIL_ACCOUNT.getDesc())); } /** * 新增用户角色、岗位、部门关联信息 * @param roleIds 角色ID列表 * @param postIds 岗位ID列表 * @param deptIds 部门ID列表 */ public void insertUserRelation(Set roleIds, Set postIds, Set deptIds, Long userId) { //用户与角色关联关系 if (CollectionUtil.isNotEmpty(roleIds)) { List userRoleList = roleIds.stream().map(r -> { MUserRole userRole = new MUserRole(); userRole.setUserId(userId); userRole.setRoleId(r); return userRole; }).toList(); userRoleMapper.insertBatch(userRoleList); } //用户与岗位关联关系 if (CollectionUtil.isNotEmpty(postIds)) { List userPostList = postIds.stream().map(p -> { MUserPost userPost = new MUserPost(); userPost.setUserId(userId); userPost.setPostId(p); return userPost; }).toList(); userPostMapper.insertBatch(userPostList); } //用户与部门关联关系 if (CollectionUtil.isNotEmpty(deptIds)) { List userDeptList = deptIds.stream().map(d -> { MUserDept userDept = new MUserDept(); userDept.setUserId(userId); userDept.setDeptId(d); return userDept; }).toList(); userDeptMapper.insertBatch(userDeptList); } } /** * 删除用户角色、岗位关联信息 * @param userId 用户ID */ public void deleteUserRelation(Long userId) { //删除用户与角色关联关系 -> 真实删除 LogicDeleteManager.execWithoutLogicDelete(()-> userRoleMapper.deleteByQuery(QueryWrapper.create().eq(MUserRole::getUserId, userId)) ); //删除用户与岗位关联关系 -> 真实删除 LogicDeleteManager.execWithoutLogicDelete(()-> userPostMapper.deleteByQuery(QueryWrapper.create().eq(MUserPost::getUserId, userId)) ); //删除用户与部门关联关系 -> 真实删除 LogicDeleteManager.execWithoutLogicDelete(()-> userDeptMapper.deleteByQuery(QueryWrapper.create().eq(MUserDept::getUserId, userId)) ); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MConfigMapper.java ================================================ package com.minimalist.basic.mapper; import com.minimalist.basic.entity.vo.config.ConfigQueryVO; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MConfig; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; /** * 参数配置表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MConfigMapper extends BaseMapper { /** * 根据参数ID查询参数 * @param configId 参数ID * @return 参数信息 */ default MConfig selectConfigByConfigId(Long configId) { return selectOneByQuery(QueryWrapper.create().eq(MConfig::getConfigId, configId)); } /** * 根据参数键名和状态查询参数 * @param configKey 参数键名 * @param status 参数状态 * @return 参数信息 */ default MConfig selectConfigByConfigKey(String configKey, Integer status) { return selectOneByQuery(QueryWrapper.create() .eq(MConfig::getConfigKey, configKey) .eq(MConfig::getStatus, status)); } /** * 根据参数ID删除参数 * @param configId 参数ID * @return 受影响行数 */ default int deleteConfigByConfigId(Long configId) { return deleteByQuery(QueryWrapper.create().eq(MConfig::getConfigId, configId)); } /** * 根据参数ID修改参数 * @param updateConfig 参数信息 */ default void updateConfigByConfigId(MConfig updateConfig) { updateByQuery(updateConfig, QueryWrapper.create().eq(MConfig::getConfigId, updateConfig.getConfigId())); } /** * 查询参数配置列表(分页) * @param queryVO 查询条件 * @return 参数配置列表 */ default Page selectPageConfigList(ConfigQueryVO queryVO) { return paginate(queryVO.getPageNum(), queryVO.getPageSize(), QueryWrapper.create() .eq(MConfig::getStatus, queryVO.getStatus()) .like(MConfig::getConfigName, queryVO.getConfigName()) .like(MConfig::getConfigKey, queryVO.getConfigKey())); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MDeptMapper.java ================================================ package com.minimalist.basic.mapper; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.vo.dept.DeptQueryVO; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MDept; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 部门表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MDeptMapper extends BaseMapper { /** * 根据部门ID查询直属下级数量 * @param deptId 部门ID * @return 下级数量 */ default long selectChildrenCountByDeptId(Long deptId) { return selectCountByQuery(QueryWrapper.create().where("FIND_IN_SET(" + deptId +", ancestors)")); } /** * 根据部门ID删除部门 * @param deptId 部门ID */ default void deleteDeptByDeptId(Long deptId) { deleteByQuery(QueryWrapper.create() .eq(MDept::getDeptId, deptId)); } /** * 根据部门ID获取部门(单条) * @param deptId 部门ID * @return 部门实体 */ default MDept selectDeptByDeptId(Long deptId) { return selectOneByQuery(QueryWrapper.create().eq(MDept::getDeptId, deptId)); } /** * 根据部门ID获取部门(批量) * @param deptIds 部门ID列表 * @return 部门实体列表 */ default List selectDeptByDeptIds(List deptIds) { return selectListByQuery(QueryWrapper.create().in(MDept::getDeptId, deptIds)); } /** * 根据部门ID修改部门 * @param mDept 部门实体 */ default void updateDeptByDeptId(MDept mDept) { updateByQuery(mDept, QueryWrapper.create().eq(MDept::getDeptId, mDept.getDeptId())); } /** * 根据条件查询部门列表 * @param queryVO 查询参数 * @return 部门列表 */ default List selectDeptList(DeptQueryVO queryVO) { return selectListByQuery(QueryWrapper.create() .eq(MDept::getStatus, queryVO.getStatus()) .like(MDept::getDeptName, queryVO.getDeptName())); } /** * 根据租户ID查询部门列表 -> 字典查询 * @return 部门列表 */ default List selectDeptDict() { return selectListByQuery(QueryWrapper.create() .eq(MDept::getStatus, StatusEnum.STATUS_1.getCode())); } /** * 根据部门ID查询所有子集部门 * @param deptId 部门ID * @return 子集部门列表 */ default List selectChildrenDeptByDeptId(Long deptId) { return selectListByQuery(QueryWrapper.create().where("FIND_IN_SET(" + deptId +", ancestors)")); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MDictMapper.java ================================================ package com.minimalist.basic.mapper; import com.minimalist.basic.entity.vo.dict.DictQueryVO; import com.minimalist.basic.entity.vo.dict.DictVO; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MDict; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 字典表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MDictMapper extends BaseMapper { /** * 根据字典ID查询字典 * @param dictId 字典ID * @return 字典数据 */ default MDict selectDictByDictId(Long dictId) { return selectOneByQuery(QueryWrapper.create().eq(MDict::getDictId, dictId)); } /** * 根据字典ID删除字典 * @param dictId 字典ID */ default void deleteDictByDictId(Long dictId) { deleteByQuery(QueryWrapper.create().eq(MDict::getDictId, dictId)); } /** * 根据字典类型删除字典 * @param dictType 字典类型 */ default void deleteDictByDictType(String dictType) { deleteByQuery(QueryWrapper.create().eq(MDict::getDictType, dictType)); } /** * 分页查询字典 * @param queryVO 查询实体 * @return 分页数据 */ default Page selectPageDictList(DictQueryVO queryVO) { return paginateAs(queryVO.getPageNum(), queryVO.getPageSize(), QueryWrapper.create().eq(MDict::getStatus, queryVO.getStatus()) .like(MDict::getDictName, queryVO.getDictName()) .like(MDict::getDictType, queryVO.getDictType()) .orderBy(MDict::getDictOrder, true) .groupBy(MDict::getDictType), DictVO.class); } /** * 根据类型查询字典数据 * @param dictTypeList 字典类型列表 * @return 字典列表 */ default List selectDictListByDictType(List dictTypeList) { return selectListByQuery(QueryWrapper.create().in(MDict::getDictType, dictTypeList).orderBy(MDict::getDictOrder, true)); } /** * 根据字典ID修改字典 * @param dict 字典实体 */ default void updateDictByDictId(MDict dict) { updateByQuery(dict, QueryWrapper.create().eq(MDict::getDictId, dict.getDictId())); } /** * 根据字典类型和字典key查询字典数据 * @param dictType 字典类型 * @param dictKey 字典key * @return 字典数据 */ default MDict selectDictByDictTypeAndKey(String dictType, String dictKey) { return selectOneByQuery(QueryWrapper.create() .eq(MDict::getDictType, dictType) .eq(MDict::getDictKey, dictKey)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MFileMapper.java ================================================ package com.minimalist.basic.mapper; import cn.hutool.core.util.ObjectUtil; import com.minimalist.basic.entity.vo.file.FileQueryVO; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MFile; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import java.time.LocalDateTime; import java.util.List; /** * 文件表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MFileMapper extends BaseMapper { /** * 根据fileUrl修改文件状态 * @param userId 用户ID * @param status 状态 * @param urlList 文件url列表 */ default void updateStatusByFileUrl(Long userId, List urlList, Integer status) { MFile file = new MFile(); file.setStatus(status); file.setUpdateId(userId); file.setUpdateTime(LocalDateTime.now()); updateByQuery(file, QueryWrapper.create().in(MFile::getFileUrl, urlList)); } /** * 查询文件列表(分页) * @param queryVO 查询条件 * @return 文件分页数据 */ default Page selectPageFileList(FileQueryVO queryVO) { return paginate(queryVO.getPageNum(), queryVO.getPageSize(), QueryWrapper.create() .eq(MFile::getStatus, queryVO.getStatus()) .eq(MFile::getFileSource, queryVO.getFileSource()) .like(MFile::getFileName, queryVO.getFileName()) .like(MFile::getFileType, queryVO.getFileType()) .orderBy(MFile::getCreateTime, false)); } /** * 根据文件ID查询文件 * @param fileId 文件ID * @return 文件实体 */ default MFile selectFileByFileId(Long fileId) { return selectOneByQuery(QueryWrapper.create().eq(MFile::getFileId, fileId)); } /** * 根据文件UID查询文件 * @param fileIdList 文件ID列表 * @return 文件列表 */ default List selectFileByFileIds(List fileIdList) { return selectListByQuery(QueryWrapper.create().in(MFile::getFileId, fileIdList)); } /** * 根据文件ID修改文件状态 * @param userId 修改人ID * @param fileIdList 文件ID列表 * @param fileStatus 文件状态 * @param fileSource 文件来源 */ default void updateFileStatusByFileIds(Long userId, List fileIdList, Integer fileStatus, Integer fileSource) { MFile file = new MFile(); file.setStatus(fileStatus); if (ObjectUtil.isNotNull(userId)) { file.setUpdateId(userId); } if (ObjectUtil.isNotNull(fileSource)) { file.setFileSource(fileSource); } file.setUpdateTime(LocalDateTime.now()); updateByQuery(file, QueryWrapper.create().in(MFile::getFileId, fileIdList)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MNoticeMapper.java ================================================ package com.minimalist.basic.mapper; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.entity.enums.NoticeEnum; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.vo.notice.NoticeQueryVO; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MNotice; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import java.time.LocalDateTime; /** * 通知公告表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MNoticeMapper extends BaseMapper { /** * 根据公告ID删除公告 * @param noticeId 公告ID */ default void deleteNoticeByNoticeId(Long noticeId) { deleteByQuery(QueryWrapper.create().eq(MNotice::getNoticeId, noticeId)); } /** * 根据公告ID修改公告 * @param notice 公告数据 */ default void updateNoticeByNoticeId(MNotice notice) { updateByQuery(notice, QueryWrapper.create().eq(MNotice::getNoticeId, notice.getNoticeId())); } /** * 查询公告列表(分页) -> 公告管理使用 * @param queryVO 查询条件 * @return 公告分页数据 */ default Page selectPageNoticeList(NoticeQueryVO queryVO) { return paginate(queryVO.getPageNum(), queryVO.getPageSize(), QueryWrapper.create() .eq(MNotice::getStatus, queryVO.getStatus()) .eq(MNotice::getNoticeType, queryVO.getNoticeType()) .like(MNotice::getNoticeTitle, queryVO.getNoticeTitle()) .orderBy(MNotice::getNoticeTop, false) .orderBy(MNotice::getNoticeSort, true)); } /** * 根据公告ID查询公告 * @param noticeId 公告ID * @return 公告实体 */ default MNotice selectNoticeByNoticeId(Long noticeId) { return selectOneByQuery(QueryWrapper.create().eq(MNotice::getNoticeId, noticeId)); } /** * 查询公告列表(分页) -> 首页使用 * @return 公告列表 */ default Page selectHomePageNoticeList(PageReq pageReq) { return paginate(pageReq.getPageNum(), pageReq.getPageSize(), QueryWrapper.create() .eq(MNotice::getStatus, StatusEnum.STATUS_1.getCode()) .eq(MNotice::getNoticeType, NoticeEnum.NoticeType.NOTICE.getCode()) .le(MNotice::getPublishTime, LocalDateTime.now()) .orderBy(MNotice::getNoticeTop, false) .orderBy(MNotice::getNoticeSort, true) ); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MPermsMapper.java ================================================ package com.minimalist.basic.mapper; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.vo.perm.PermQueryVO; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MPerms; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 权限表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MPermsMapper extends BaseMapper { /** * 根据权限ID获取权限(多条) * @param permsIds 权限ID集合 * @return 权限集合 */ default List selectPermsByPermsIds(List permsIds) { return selectListByQuery(QueryWrapper.create().in(MPerms::getPermId, permsIds)); } /** * 根据权限ID获取权限(单条) * @param permId 权限ID * @return 权限实体 */ default MPerms selectPermsByPermId(Long permId) { return selectOneByQuery(QueryWrapper.create().eq(MPerms::getPermId, permId)); } /** * 根据权限ID修改权限 * @param perms 权限实体 */ default void updatePermsByPermId(MPerms perms) { updateByQuery(perms, QueryWrapper.create().eq(MPerms::getPermId, perms.getPermId())); } /** * 根据权限ID查询直属下级数量 * @param permId 权限ID * @return 下级数量 */ default long selectChildrenCountByPermId(Long permId) { return selectCountByQuery(QueryWrapper.create().eq(MPerms::getParentPermId, permId)); } /** * 根据权限ID删除权限 * @param permId 权限ID */ default void deletePermsByPermId(Long permId) { deleteByQuery(QueryWrapper.create().eq(MPerms::getPermId, permId)); } /** * 根据条件查询权限列表 * @param queryVO 查询参数 * @return 权限列表 */ default List selectPermList(PermQueryVO queryVO) { return selectListByQuery(QueryWrapper.create() .eq(MPerms::getStatus, queryVO.getStatus()) .like(MPerms::getPermName, queryVO.getPermName()) .like(MPerms::getPermType, queryVO.getPermType()) ); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MPostMapper.java ================================================ package com.minimalist.basic.mapper; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.vo.post.PostQueryVO; import com.minimalist.basic.entity.vo.post.PostVO; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MPost; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 岗位表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MPostMapper extends BaseMapper { /** * 根据岗位编码查询岗位 * @param postCode 岗位编码 * @return 岗位实体 */ default MPost selectPostByPostCode(String postCode) { return selectOneByQuery(QueryWrapper.create().eq(MPost::getPostCode, postCode)); } /** * 根据岗位ID删除岗位 * @param postId 岗位ID */ default void deletePostByPostId(Long postId) { deleteByQuery(QueryWrapper.create().eq(MPost::getPostId, postId)); } /** * 根据岗位ID查询岗位(单条) * @param postId 岗位ID * @return 岗位实体 */ default MPost selectPostByPostId(Long postId) { return selectOneByQuery(QueryWrapper.create().eq(MPost::getPostId, postId)); } /** * 根据岗位ID查询岗位(批量) * @param postIds 岗位ID列表 * @return 岗位实体列表 */ default List selectPostByPostIds(List postIds) { return selectListByQueryAs(QueryWrapper.create().in(MPost::getPostId, postIds), PostVO.class); } /** * 根据岗位ID修改岗位 * @param mPost 岗位数据 */ default void updatePostByPostId(MPost mPost) { updateByQuery(mPost, QueryWrapper.create().eq(MPost::getPostId, mPost.getPostId())); } /** * 查询岗位列表(分页) * @param queryVO 查询条件 * @return 岗位分页数据 */ default Page selectPagePostList(PostQueryVO queryVO) { return paginateAs(queryVO.getPageNum(), queryVO.getPageSize(), QueryWrapper.create() .eq(MPost::getStatus, queryVO.getStatus()) .like(MPost::getPostName, queryVO.getPostName()) .like(MPost::getPostCode, queryVO.getPostCode()) .orderBy(MPost::getPostSort, true), PostVO.class ); } /** * 根据租户ID查询岗位列表 -> 字典查询 * @return 部门列表 */ default List selectPostDict() { return selectListByQuery(QueryWrapper.create().eq(MPost::getStatus, StatusEnum.STATUS_1.getCode())); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MRoleDeptMapper.java ================================================ package com.minimalist.basic.mapper; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MRoleDept; /** * 角色与部门关联表 1角色-N部门 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MRoleDeptMapper extends BaseMapper { } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MRoleMapper.java ================================================ package com.minimalist.basic.mapper; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.vo.role.RoleQueryVO; import com.minimalist.basic.entity.vo.role.RoleVO; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MRole; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 角色表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MRoleMapper extends BaseMapper { /** * 根据角色编码查询角色 * @param roleCode 角色编码 * @return 角色实体 */ default MRole selectRoleByRoleCode(String roleCode) { return selectOneByQuery(QueryWrapper.create().eq(MRole::getRoleCode, roleCode)); } /** * 根据角色ID查询角色 * @param roleId 角色ID * @return 角色实体 */ default MRole selectRoleByRoleId(Long roleId) { return selectOneByQuery(QueryWrapper.create().eq(MRole::getRoleId, roleId)); } /** * 根据角色ID查询角色 * @param roleId 角色ID * @return 角色实体 */ default List selectRoleByRoleIds(List roleId) { return selectListByQueryAs(QueryWrapper.create().in(MRole::getRoleId, roleId), RoleVO.class); } /** * 根据角色ID删除角色 * @param roleId 角色ID */ default void deleteRoleByRoleId(Long roleId) { deleteByQuery(QueryWrapper.create().eq(MRole::getRoleId, roleId)); } /** * 根据角色ID修改角色 * @param role 角色实体 */ default void updateRoleByRoleId(MRole role) { updateByQuery(role, QueryWrapper.create().eq(MRole::getRoleId, role.getRoleId())); } /** * 查询角色列表(分页) * @param queryVO 查询条件 * @return 角色分页数据 */ default Page selectPageRoleList(RoleQueryVO queryVO) { return paginateAs(queryVO.getPageNum(), queryVO.getPageSize(), QueryWrapper.create() .eq(MRole::getStatus, queryVO.getStatus()) .like(MRole::getRoleCode, queryVO.getRoleCode()) .like(MRole::getRoleName, queryVO.getRoleName()), RoleVO.class ); } /** * 根据租户ID查询角色列表 -> 字典查询 * @return 部门列表 */ default List selectRoleDict() { return selectListByQuery(QueryWrapper.create().eq(MRole::getStatus, StatusEnum.STATUS_1.getCode())); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MRolePermMapper.java ================================================ package com.minimalist.basic.mapper; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MRolePerm; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 角色与权限关联表 1角色-N权限 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MRolePermMapper extends BaseMapper { /** * 根据角色ID获取角色与权限关联关系 * @param roleIds 角色ID集合(多条) * @return 角色与权限关联数据 */ default List selectRolePermByRoleIds(List roleIds) { return selectListByQuery(QueryWrapper.create().in(MRolePerm::getRoleId, roleIds)); } /** * 根据角色ID获取角色与权限关联关系 * @param roleId 角色ID(单条) * @return 角色与权限关联数据 */ default List selectRolePermByRoleId(Long roleId) { return selectListByQuery(QueryWrapper.create().eq(MRolePerm::getRoleId, roleId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MStorageMapper.java ================================================ package com.minimalist.basic.mapper; import com.minimalist.basic.entity.vo.storage.StorageQueryVO; import com.minimalist.basic.entity.vo.storage.StorageVO; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MStorage; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; /** * 存储管理表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MStorageMapper extends BaseMapper { /** * 根据存储ID查询存储信息 * @param storageId 存储ID * @return 存储信息 */ default MStorage selectStorageByStorageId(Long storageId) { return selectOneByQuery(QueryWrapper.create().eq(MStorage::getStorageId, storageId)); } /** * 根据存储ID删除存储 * @param storageId 存储ID */ default void deleteStorageByStorageId(Long storageId) { deleteByQuery(QueryWrapper.create().eq(MStorage::getStorageId, storageId)); } /** * 根据存储ID修改存储信息 * @param storage 存储信息 */ default void updateStorageByStorageId(MStorage storage) { updateByQuery(storage, QueryWrapper.create().eq(MStorage::getStorageId, storage.getStorageId())); } /** * 根据条件查询存储信息列表(分页) * @param queryVO 查询条件 * @return 存储信息列表 */ default Page selectPageStorageList(StorageQueryVO queryVO) { return paginateAs(queryVO.getPageNum(), queryVO.getPageSize(), QueryWrapper.create() .eq(MStorage::getStorageType, queryVO.getStorageType()) .eq(MStorage::getStatus, queryVO.getStatus()) .like(MStorage::getStorageName, queryVO.getStorageName()), StorageVO.class ); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MTenantDatasourceMapper.java ================================================ package com.minimalist.basic.mapper; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MTenantDatasource; import com.mybatisflex.core.query.QueryWrapper; /** * 租户数据源表 映射层。 * * @author asus * @since 2025-02-14 */ public interface MTenantDatasourceMapper extends BaseMapper { /** * 根据租户ID删除数据源信息 * @param tenantId 租户ID */ default void deleteTenantDatasourceByTenantId(Long tenantId) { deleteByQuery(QueryWrapper.create().eq(MTenantDatasource::getTenantId, tenantId)); } /** * 根据租户ID查询数据源信息 * @param tenantId 租户ID * @return 数据源信息 */ default MTenantDatasource selectTenantDatasourceByTenantId(Long tenantId) { return selectOneByQuery(QueryWrapper.create().eq(MTenantDatasource::getTenantId, tenantId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MTenantMapper.java ================================================ package com.minimalist.basic.mapper; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.vo.tenant.TenantQueryVO; import com.minimalist.basic.entity.vo.tenant.TenantVO; import com.minimalist.basic.utils.CommonConstant; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MTenant; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 租户表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MTenantMapper extends BaseMapper { /** * 根据租户套餐ID查询租户数量 * @param tenantPackageId 租户套餐ID * @return 租户数量 */ default long selectTenantCountByTenantPackageId(Long tenantPackageId) { return selectCountByQuery(QueryWrapper.create().eq(MTenant::getPackageId, tenantPackageId)); } /** * 根据租户套餐ID查询租户 * @param tenantPackageId 租户套餐ID * @return 租户数量 */ default List selectTenantByTenantPackageId(Long tenantPackageId) { return selectListByQuery(QueryWrapper.create().eq(MTenant::getPackageId, tenantPackageId)); } /** * 根据租户名查询租户 * @param tenantName 租户名 * @return 租户实体 */ default MTenant selectTenantByTenantName(String tenantName) { return selectOneByQuery(QueryWrapper.create().eq(MTenant::getTenantName, tenantName)); } /** * 根据租户ID查询租户 * @param tenantId 租户ID * @return 租户实体 */ default MTenant selectTenantByTenantId(Long tenantId) { return selectOneByQuery(QueryWrapper.create().eq(MTenant::getTenantId, tenantId)); } /** * 根据租户ID删除租户 * @param tenantId 租户ID */ default void deleteTenantByTenantId(Long tenantId) { deleteByQuery(QueryWrapper.create().eq(MTenant::getTenantId, tenantId)); } /** * 根据租户ID更新租户 * @param tenant 租户信息 */ default void updateTenantByTenantId(MTenant tenant) { updateByQuery(tenant, QueryWrapper.create().eq(MTenant::getTenantId, tenant.getTenantId())); } /** * 查询租户(分页) * @param queryVO 查询条件 * @return 租户分页数据 */ default Page selectPageTenantList(TenantQueryVO queryVO) { return paginateAs(queryVO.getPageNum(), queryVO.getPageSize(), QueryWrapper.create() .eq(MTenant::getStatus, queryVO.getStatus()) //排除系统租户 .ne(MTenant::getTenantId, CommonConstant.ZERO) .like(MTenant::getTenantName, queryVO.getTenantName()), TenantVO.class ); } /** * 租户列表 -> 字典查询 * @return 部门列表 */ default List selectTenantDict() { return selectListByQuery(QueryWrapper.create().eq(MTenant::getStatus, StatusEnum.STATUS_1.getCode())); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MTenantPackageMapper.java ================================================ package com.minimalist.basic.mapper; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.vo.tenant.TenantPackageQueryVO; import com.minimalist.basic.entity.vo.tenant.TenantPackageVO; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MTenantPackage; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 租户套餐表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MTenantPackageMapper extends BaseMapper { /** * 根据租户套餐ID查询租户套餐 * @param tenantPackageId 租户套餐ID * @return 租户套餐实体 */ default MTenantPackage selectTenantPackageByTenantPackageId(Long tenantPackageId) { return selectOneByQuery(QueryWrapper.create().eq(MTenantPackage::getPackageId, tenantPackageId)); } /** * 根据租户套餐ID删除租户套餐 * @param tenantPackageId 租户套餐ID */ default void deleteTenantPackageByTenantPackageId(Long tenantPackageId) { deleteByQuery(QueryWrapper.create().eq(MTenantPackage::getPackageId, tenantPackageId)); } /** * 根据租户套餐ID修改租户套餐 * @param tenantPackage 租户套餐实体 */ default void updateTenantPackageByTenantPackageId(MTenantPackage tenantPackage) { updateByQuery(tenantPackage, QueryWrapper.create().eq(MTenantPackage::getPackageId, tenantPackage.getPackageId())); } /** * 查询租户套餐(分页) * @param queryVO 查询条件 * @return 租户套餐分页数据 */ default Page selectPageTenantPackageList(TenantPackageQueryVO queryVO) { return paginateAs(queryVO.getPageNum(), queryVO.getPageSize(), QueryWrapper.create() .eq(MTenantPackage::getStatus, queryVO.getStatus()) .like(MTenantPackage::getPackageName, queryVO.getPackageName()), TenantPackageVO.class ); } /** * 查询全部租户套餐 -> 字典查询 * @return 用户列表 */ default List selectTenantPackageDict() { return selectListByQuery(QueryWrapper.create().eq(MTenantPackage::getStatus, StatusEnum.STATUS_1.getCode())); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MTenantPackagePermMapper.java ================================================ package com.minimalist.basic.mapper; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MTenantPackagePerm; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 租户套餐与权限关联表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MTenantPackagePermMapper extends BaseMapper { /** * 根据租户套餐ID查询租户套餐与权限关联数据 * @param tenantPackageId 租户套餐ID * @return 租户套餐与权限关联数据 */ default List selectTenantPackagePermByTenantPackageId(Long tenantPackageId) { return selectListByQuery(QueryWrapper.create().eq(MTenantPackagePerm::getPackageId, tenantPackageId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MUserDeptMapper.java ================================================ package com.minimalist.basic.mapper; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MUserDept; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 用户与岗位关联表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MUserDeptMapper extends BaseMapper { /** * 根据用户ID查询用户与部门关联数据 * @param userId 用户ID * @return 用户与部门关联数据 */ default List selectUserDeptRelation(Long userId) { return selectListByQuery(QueryWrapper.create().eq(MUserDept::getUserId, userId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MUserMapper.java ================================================ package com.minimalist.basic.mapper; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.po.table.MDeptTableDef; import com.minimalist.basic.entity.po.table.MUserDeptTableDef; import com.minimalist.basic.entity.po.table.MUserTableDef; import com.minimalist.basic.entity.vo.user.UserQueryVO; import com.minimalist.basic.entity.vo.user.UserVO; import com.minimalist.basic.utils.CommonConstant; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MUser; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryColumn; import com.mybatisflex.core.query.QueryMethods; import com.mybatisflex.core.query.QueryWrapper; import org.apache.ibatis.annotations.Param; import java.util.List; /** * 用户表 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MUserMapper extends BaseMapper { /** * 根据用户名查询用户 * @param username 用户名 * @return 用户PO */ default MUser selectUserByUsername(String username) { return selectOneByQuery(QueryWrapper.create().eq(MUser::getUsername, username)); } /** * 根据用户ID查询用户 * @param userId 用户ID * @return 用户PO */ default MUser selectUserByUserId(Long userId) { return selectOneByQuery(QueryWrapper.create().eq(MUser::getUserId, userId)); } /** * 根据用户ID查询用户 * @param userIdList 用户ID列表 * @return 用户PO */ default List selectUserByUserIds(List userIdList) { return selectListByQuery(QueryWrapper.create().in(MUser::getUserId, userIdList)); } /** * 根据租户ID查询用户 -> 字典查询(区分租户和管理员) * @return 用户列表 */ default List selectUserDict() { return selectListByQuery(QueryWrapper.create().eq(MUser::getStatus, StatusEnum.STATUS_1.getCode())); } /** * 根据租户ID查询该租户下的用户数量 * @param tenantId 租户ID * @return 该租户下的用户数量 */ default long selectUserCountByTenantId(Long tenantId) { return selectCountByQuery(QueryWrapper.create().eq(MUser::getTenantId, tenantId)); } /** * 根据手机号查询用户 * @param phone 手机号 * @return 用户实体 */ default MUser selectUserByPhone(String phone) { return selectOneByQuery(QueryWrapper.create().eq(MUser::getPhone, phone)); } /** * 根据用户ID删除用户 * @param userId 用户ID */ default void deleteUserByUserId(Long userId) { deleteByQuery(QueryWrapper.create().eq(MUser::getUserId, userId)); } /** * 根据用户ID修改用户 * @param user 用户数据 */ default void updateUserByUserId(MUser user) { updateByQuery(user, QueryWrapper.create().eq(MUser::getUserId, user.getUserId())); } /** * 根据部门ID列表,查询用户数 * @param deptIds 部门ID * @return 用户数 */ default long selectUserCountByDeptIds(List deptIds) { long result = 0; for (Long deptId : deptIds) { result += selectCountByQuery(QueryWrapper.create().where("FIND_IN_SET(" + deptId +", ancestors)")); } return result; } /** * 查询用户列表(分页) * @param query 查询条件 * @return 用户分页数据 */ default Page selectPageUserList(UserQueryVO query) { /* select u.* FROM m_user u * inner join m_user_dept ud on u.user_id = ud.user_id * inner join m_dept d on d.dept_id = ud.dept_id * WHERE ( * d.dept_id = 1677964029214371840 or d.dept_id in (select t.dept_id from m_dept t where find_in_set(1677964029214371840, ancestors)) * ) * group by u.user_id; */ QueryWrapper queryWrapper = QueryWrapper.create() .select(MUserTableDef.MUSER.ALL_COLUMNS) .from(MUserTableDef.MUSER) .leftJoin(MUserDeptTableDef.MUSER_DEPT).on(MUserDeptTableDef.MUSER_DEPT.USER_ID.eq(MUserTableDef.MUSER.USER_ID)) .leftJoin(MDeptTableDef.MDEPT).on(MDeptTableDef.MDEPT.DEPT_ID.eq(MUserDeptTableDef.MUSER_DEPT.DEPT_ID)) .where(MUserTableDef.MUSER.STATUS.eq(query.getStatus())) .and(MUserTableDef.MUSER.PHONE.like(query.getPhone())) .and(MUserTableDef.MUSER.USER_REAL_NAME.like(query.getUserRealName())); //deptId=0表示全部,需要忽略 if (ObjectUtil.isNotNull(query.getDeptId()) && CommonConstant.ZERO != query.getDeptId()) { queryWrapper.and( MDeptTableDef.MDEPT.DEPT_ID.eq(query.getDeptId()) .or(MDeptTableDef.MDEPT.DEPT_ID.in( QueryWrapper.create() .select(MDeptTableDef.MDEPT.DEPT_ID) .from(MDeptTableDef.MDEPT) .where("FIND_IN_SET(" + query.getDeptId() + ", ancestors)") )) ); } queryWrapper.groupBy(MUserTableDef.MUSER.USER_ID); return paginateAs(query.getPageNum(), query.getPageSize(), queryWrapper, UserVO.class); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MUserPostMapper.java ================================================ package com.minimalist.basic.mapper; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MUserPost; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 用户与岗位关联表 1用户-N岗位 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MUserPostMapper extends BaseMapper { /** * 根据用户ID查询用户与岗位关联数据 * @param userId 用户ID * @return 用户与岗位关联数据 */ default List selectUserPostRelation(Long userId) { return selectListByQuery(QueryWrapper.create().eq(MUserPost::getUserId, userId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mapper/MUserRoleMapper.java ================================================ package com.minimalist.basic.mapper; import com.mybatisflex.core.BaseMapper; import com.minimalist.basic.entity.po.MUserRole; import com.mybatisflex.core.query.QueryWrapper; import java.util.List; /** * 用户与角色关联表 1用户-N角色 映射层。 * * @author 小太阳 * @since 2024-10-18 */ public interface MUserRoleMapper extends BaseMapper { /** * 根据userId查询用户与角色关联关系 * @param userId 用户ID * @return 用户与角色关联关系 */ default List selectUserRoleRelation(Long userId) { return selectListByQuery(QueryWrapper.create().eq(MUserRole::getUserId, userId)); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mq/SystemConfigSyncConsumer.java ================================================ package com.minimalist.basic.mq; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.minimalist.basic.entity.vo.config.ConfigVO; import com.minimalist.basic.utils.CommonConstant; import com.minimalist.basic.utils.RedisKeyConstant; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RPatternTopic; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; /** * 系统配置同步消费者 * 主要是防止部署多个节点,修改后不同步问题 * 因为数据会缓存在一个Map中,在页面上修改后,需要让所有节点在内存中的Map同时更新 */ @Slf4j @Component public class SystemConfigSyncConsumer implements ApplicationRunner { @Autowired private RedissonClient redissonClient; @Override public void run(ApplicationArguments args) throws Exception { RPatternTopic topic = redissonClient.getPatternTopic(RedisKeyConstant.SYSTEM_CONFIG_TOPIC_KEY + ".*"); topic.addListener(String.class, (pattern, channel, msg) -> { log.info("系统配置同步处理,参数:{}", msg); try { //区分新增、修改、删除 String opt = StrUtil.subAfter(channel, ".", true); if (CommonConstant.ADD.equals(opt) || CommonConstant.UPDATE.equals(opt)) { ConfigVO configVO = JSONUtil.toBean(msg, ConfigVO.class); CommonConstant.systemConfigMap.put(configVO.getConfigKey(), configVO); } if (CommonConstant.DELETE.equals(opt)) { CommonConstant.systemConfigMap.remove(msg); } log.info("系统配置同步处理,完毕!"); } catch (Exception e) { log.error("系统配置同步处理异常:", e); } }); System.out.println("-------------------- 系统配置同步消费者监听启动完毕 --------------------"); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/mq/TenantDatasourceSyncConsumer.java ================================================ package com.minimalist.basic.mq; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.minimalist.basic.entity.enums.TenantEnum; import com.minimalist.basic.entity.vo.tenant.TenantVO; import com.minimalist.basic.manager.TenantManager; import com.minimalist.basic.utils.CommonConstant; import com.minimalist.basic.utils.RedisKeyConstant; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RPatternTopic; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; /** * 租户数据源信息同步消费者 * 主要是防止部署多个节点,修改后不同步问题 * 因为数据会缓存在一个Map中,在页面上修改后,需要让所有节点在内存中的Map同时更新 */ @Slf4j @Component public class TenantDatasourceSyncConsumer implements ApplicationRunner { @Autowired private RedissonClient redissonClient; @Autowired private TenantManager tenantManager; @Override public void run(ApplicationArguments args) throws Exception { RPatternTopic topic = redissonClient.getPatternTopic(RedisKeyConstant.TENANT_DATA_TOPIC_KEY + ".*"); topic.addListener(String.class, (pattern, channel, msg) -> { log.info("租户数据源信息同步处理,参数:{}", msg); try { //区分新增、修改、删除 String opt = StrUtil.subAfter(channel, ".", true); if (CommonConstant.ADD.equals(opt) || CommonConstant.UPDATE.equals(opt)) { TenantVO tenantVO = JSONUtil.toBean(msg, TenantVO.class); CommonConstant.tenantMap.put(tenantVO.getTenantId(), tenantVO); //动态加载数据源 if (TenantEnum.DataIsolation.DB.getCode().equals(tenantVO.getDataIsolation()) && ObjectUtil.isNotNull(tenantVO.getTenantDatasource())) { String tenantId = tenantVO.getTenantId().toString(); //删除旧数据源 tenantManager.dynamicDeleteDatasource(tenantId); //动态添加数据源 tenantManager.dynamicAddDatasource(tenantId, tenantVO.getTenantDatasource()); } else { //不需要数据库隔离,删除数据源 tenantManager.dynamicDeleteDatasource(tenantVO.getTenantId().toString()); } } if (CommonConstant.DELETE.equals(opt)) { CommonConstant.tenantMap.remove(Long.parseLong(msg)); //动态删除数据源 tenantManager.dynamicDeleteDatasource(msg); } log.info("租户数据源信息同步处理,完毕!"); } catch (Exception e) { log.error("租户数据源信息同步处理异常:", e); } }); System.out.println("-------------------- 租户数据源信息同步消费者监听启动完毕 --------------------"); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/ConfigService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.entity.vo.config.ConfigQueryVO; import com.minimalist.basic.entity.vo.config.ConfigVO; public interface ConfigService { /** * 添加参数 * @param configVO 参数配置信息 */ void addConfig(ConfigVO configVO); /** * 删除参数 -> 根据参数ID删除 * @param configId 参数ID */ void deleteConfigByConfigId(Long configId); /** * 修改参数 * @param configVO 参数配置信息 */ void updateConfigByConfigId(ConfigVO configVO); /** * 查询参数配置列表(分页) * @param queryVO 查询条件 * @return 参数配置列表 */ PageResp getPageConfigList(ConfigQueryVO queryVO); /** * 根据参数ID查询参数 * @param configId 参数ID * @return 参数信息 */ ConfigVO getConfigByConfigId(Long configId); /** * 根据参数Key查询参数 - 状态为正常 * @param configKey 参数Key * @return 参数信息 */ ConfigVO getConfigByConfigKey(String configKey); /** * 刷新配置缓存 */ void refreshConfigCache(); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/DeptService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.entity.vo.dept.DeptQueryVO; import com.minimalist.basic.entity.vo.dept.DeptVO; import java.util.List; public interface DeptService { /** * 添加部门 * @param deptVO 部门数据 */ void addDept(DeptVO deptVO); /** * 删除部门 -> 根据部门ID删除 * @param deptId 部门ID */ void deleteDeptByDeptId(Long deptId); /** * 修改部门 -> 根据部门ID修改 * @param deptVO 部门数据 */ void updateDeptByDeptId(DeptVO deptVO); /** * 查询部门列表(全部不分页) -> 部门管理使用 * @param queryVO 查询参数 * @return 部门树 */ List getDeptList(DeptQueryVO queryVO); /** * 根据部门ID查询部门 * @param deptId 部门ID * @return 部门数据 */ DeptVO getDeptByDeptId(Long deptId); /** * 查询部门列表 -> 其他地方使用(只获取正常状态的部门) * @return 部门树 */ List getEnableDeptList(); /** * 根据部门ID查询部门 * @param deptIds 部门ID列表 * @return 用户所属部门列表 */ List getDeptByDeptIds(List deptIds); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/DictService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.entity.vo.dict.*; import com.minimalist.basic.config.mybatis.bo.PageResp; import java.util.List; public interface DictService { /** * 新增字典 * @param dictInfoVO 字典实体 */ void addDict(DictInfoVO dictInfoVO); /** * 删除字典 -> 根据字典ID删除 * @param dictId 字典ID */ void deleteDictByDictId(Long dictId); /** * 删除字典 -> 根据字典类型删除 * @param dictType 字典类型 */ void deleteDictByDictType(String dictType); /** * 修改字典 * @param dictInfoVO 字典实体 */ void updateDictByDictId(DictInfoVO dictInfoVO); /** * 查询字典列表(分页) * @param queryVO 查询实体 * @return 分页字典数据列表 */ PageResp getPageDictList(DictQueryVO queryVO); /** * 根据字典类型查询字典 * @param dictType 字典类型 * @return 字典数据 */ DictInfoVO getDictByDictType(String dictType); /** * 根据字典类型查询字典 * @param dictTypes 字典类型,为空查询所有字典数据 * @return 字典数据列表 */ List getDictList(List dictTypes); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/EDictService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.entity.vo.dict.DictCacheVO; /** * 额外的字典数据,这些数据不会出现在字典管理表中,因为这些数据是来源于其他表 */ public interface EDictService { /** * 获取部门字典数据(额外字典数据) * @return 字典数据列表 */ DictCacheVO getDeptDictData(); /** * 获取用户字典数据(额外字典数据) * @return 字典数据列表 */ DictCacheVO getUserDictData(); /** * 获取租户套餐字典数据(额外字典数据) * @return 字典数据列表 */ DictCacheVO getTenantPackageDictData(); /** * 获取角色字典数据(额外字典数据) * @return 字典数据列表 */ DictCacheVO getRoleDictData(); /** * 获取岗位字典数据(额外字典数据) * @return 字典数据列表 */ DictCacheVO getPostDictData(); /** * 获取租户字典数据(额外字典数据) * @return 字典数据列表 */ DictCacheVO getTenantDictData(); /** * 获取存储方式数据(额外字典数据) * @return 字典数据列表 */ DictCacheVO getStorageDictData(); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/FileService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.entity.po.MFile; import com.minimalist.basic.entity.vo.file.*; import com.minimalist.basic.config.mybatis.bo.PageResp; import java.util.List; public interface FileService { /** * 单文件上传 * @param fileUploadVO 文件及携带参数 * @return 文件信息 */ FileUploadRespVO uploadFile(FileUploadVO fileUploadVO); /** * 多上传文件 * @param uploadBatchVO 文件及携带参数 * @return 文件信息 */ List uploadFileBatch(FileUploadBatchVO uploadBatchVO); /** * 删除文件 * @param fileId 文件ID */ void deleteFile(Long fileId); /** * 移动文件 * 在前端文件选择组件上传文件时不需要指定文件来源,默认会上传到common目录, * 后端处理时可以将文件从common目录移动到对应业务的目录中 * @param fileId 文件ID * @param fileSource 文件来源 * @return 移动后的文件 */ MFile moveFile(Long fileId, Integer fileSource); /** * 查询文件列表(分页) * @param queryVO 查询条件 * @return 文件分页数据 */ PageResp getPageFileList(FileQueryVO queryVO); /** * 移动文件 * 用于将前端传递的多个FileVO文件移动,并更新文件信息,已指定fileSource的只更新文件状态 * @param files 文件信息 * @param fileSource 文件来源 * @return 文件ID,逗号分隔 */ String moveFile(List files, Integer fileSource); /** * 移动文件 * 用于根据文件url将文件移动,并更新文件信息,已指定fileSource的只更新文件状态 * @param fileUrl 文件url * @param fileSource 文件来源 * @return 移动后的文件 */ MFile moveFile(String fileUrl, Integer fileSource); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/NoticeService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.entity.vo.notice.NoticeQueryVO; import com.minimalist.basic.entity.vo.notice.NoticeVO; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.config.mybatis.bo.PageReq; public interface NoticeService { /** * 添加公告 * @param noticeVO 公告信息 */ void addNotice(NoticeVO noticeVO); /** * 删除公告 -> 根据公告ID删除 * @param noticeId 公告ID */ void deleteNoticeByNoticeId(Long noticeId); /** * 修改公告 -> 根据公告ID修改 * @param noticeVO 公告信息 */ void updateNoticeByNoticeId(NoticeVO noticeVO); /** * 查询公告列表(分页) -> 公告管理使用 * @param queryVO 查询条件 * @return 公告分页数据 */ PageResp getPageNoticeList(NoticeQueryVO queryVO); /** * 根据公告ID查询公告 * @param noticeId 公告ID * @return 公告信息 */ NoticeVO getNoticeByNoticeId(Long noticeId); /** * 查询公告列表(分页) -> 首页使用 * @return 公告分页数据 */ PageResp getPageHomeNoticeList(PageReq pageReq); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/PermService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.entity.po.MPerms; import com.minimalist.basic.entity.vo.perm.PermQueryVO; import com.minimalist.basic.entity.vo.perm.PermVO; import java.util.List; public interface PermService { /** * 根据角色ID获取权限 * @param roleIds 角色ID集合 * @return 权限平铺数据 */ List getPermsByRoleId(List roleIds); /** * 转换权限树 * @param permsList 权限数据集合 * @return 权限VO数据集合 */ List permsToTree(List permsList); /** * 添加权限 * @param permVO 权限数据 */ void addPerm(PermVO permVO); /** * 根据权限ID删除权限 * @param permId 权限ID */ void deletePermByPermId(Long permId); /** * 根据权限ID修改权限 * @param permVO 权限数据 */ void updatePermByPermId(PermVO permVO); /** * 查询权限列表(全部不分页) * @param queryVO 查询参数 * @return 权限树 */ List getPermList(PermQueryVO queryVO); /** * 查询系统租户权限列表 -> (只获取正常状态的权限) * @return 权限树 */ List getEnablePermList(); /** * 查询租户权限列表 -> (只获取正常状态的权限) * @return 权限树 */ List getTenantEnablePermList(); /** * 根据权限ID查询权限 * @param permId 权限ID * @return 权限数据 */ PermVO getPermByPermId(Long permId); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/PostService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.entity.vo.post.PostQueryVO; import com.minimalist.basic.entity.vo.post.PostVO; import com.minimalist.basic.config.mybatis.bo.PageResp; import java.util.List; public interface PostService { /** * 添加岗位 * @param postVO 岗位数据 */ void addPost(PostVO postVO); /** * 删除岗位 -> 根据岗位ID删除 * @param postId 岗位ID */ void deletePostByPostId(Long postId); /** * 修改岗位 -> 根据岗位ID修改 * @param postVO 岗位数据 */ void updatePostByPostId(PostVO postVO); /** * 查询岗位列表(分页) * @param queryVO 查询参数 * @return 岗位列表 */ PageResp getPagePostList(PostQueryVO queryVO); /** * 根据岗位ID查询岗位 * @param postId 岗位ID * @return 岗位数据 */ PostVO getPostByPostId(Long postId); /** * 根据用户ID查询用户岗位 * @param userId 用户ID * @return 岗位列表 */ List getPostByUserId(Long userId); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/RoleService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.entity.po.MRole; import com.minimalist.basic.entity.vo.role.RoleQueryVO; import com.minimalist.basic.entity.vo.role.RoleVO; import com.minimalist.basic.config.mybatis.bo.PageResp; import java.util.List; public interface RoleService { /** * 根据用户ID查询角色 * @param userId 用户ID * @return 角色集合 */ List getRolesByUserId(Long userId); /** * 添加角色 * @param roleVO 角色数据 */ void addRole(RoleVO roleVO); /** * 根据角色ID删除角色 * @param roleId 角色ID */ void deleteRoleByRoleId(Long roleId); /** * 根据角色ID修改角色 * @param roleVO 角色数据 */ void updateRoleByRoleId(RoleVO roleVO); /** * 查询角色(分页) -> 角色管理使用 * @param queryVO 查询条件 * @return 角色分页数据 */ PageResp getPageRoleList(RoleQueryVO queryVO); /** * 根据角色ID查询角色 * @param roleId 角色ID * @return 角色信息 */ RoleVO getRoleByRoleId(Long roleId); /** * 根据租户ID查询角色列表 * @param tenantId 租户ID * @return 角色列表 */ List getRoleByTenantId(Long tenantId); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/StorageService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.entity.vo.storage.StorageQueryVO; import com.minimalist.basic.entity.vo.storage.StorageVO; public interface StorageService { /** * 添加存储 * @param storageVO 存储信息 */ void addStorage(StorageVO storageVO); /** * 删除存储 -> 根据存储ID删除 * @param storageId 存储ID */ void deleteStorageByStorageId(Long storageId); /** * 修改存储 -> 根据存储ID修改 * @param storageVO 存储信息 */ void updateStorageByStorageId(StorageVO storageVO); /** * 查询存储列表(分页) * @param queryVO 查询条件 * @return 存储列表 */ PageResp getPageStorageList(StorageQueryVO queryVO); /** * 根据存储ID查询存储信息 * @param storageId 存储ID * @return 存储信息 */ StorageVO getStorageByStorageId(Long storageId); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/TenantPackageService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.entity.po.MPerms; import com.minimalist.basic.entity.vo.tenant.TenantPackageQueryVO; import com.minimalist.basic.entity.vo.tenant.TenantPackageVO; import com.minimalist.basic.config.mybatis.bo.PageResp; import java.util.List; public interface TenantPackageService { /** * 添加租户套餐 * @param tenantPackageVO 租户套餐信息 */ void addTenantPackage(TenantPackageVO tenantPackageVO); /** * 删除租户套餐 -> 根据租户套餐ID删除租户套餐 * @param tenantPackageId 租户套餐ID */ void deleteTenantPackageByTenantPackageId(Long tenantPackageId); /** * 修改租户套餐 -> 根据租户套餐ID修改 * @param tenantPackageVO 租户套餐信息 */ void updateTenantPackageByTenantPackageId(TenantPackageVO tenantPackageVO); /** * 查询租户套餐(分页) * @param queryVO 查询条件 * @return 租户套餐分页数据 */ PageResp getPageTenantPackageList(TenantPackageQueryVO queryVO); /** * 根据租户套餐ID查询租户套餐 * @param tenantPackageId 租户套餐ID * @return 租户套餐数据 */ TenantPackageVO getTenantPackageByTenantPackageId(Long tenantPackageId); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/TenantService.java ================================================ package com.minimalist.basic.service; import com.minimalist.basic.entity.vo.tenant.TenantQueryVO; import com.minimalist.basic.entity.vo.tenant.TenantVO; import com.minimalist.basic.config.mybatis.bo.PageResp; public interface TenantService { /** * 添加租户 * @param tenantVO 租户信息 */ void addTenant(TenantVO tenantVO); /** * 删除租户 -> 根据租户ID删除 * @param tenantId 租户ID */ void deleteTenantByTenantId(Long tenantId); /** * 修改租户 -> 根据租户ID修改 * @param tenantVO 租户信息 */ void updateTenantByTenantId(TenantVO tenantVO); /** * 查询租户(分页) * @param queryVO 查询条件 * @return 租户分页数据 */ PageResp getPageTenantList(TenantQueryVO queryVO); /** * 根据租户ID查询租户 * @param tenantId 租户ID * @return 租户数据 */ TenantVO getTenantByTenantId(Long tenantId); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/UserService.java ================================================ package com.minimalist.basic.service; import cn.dev33.satoken.stp.SaTokenInfo; import com.minimalist.basic.entity.po.MUser; import com.minimalist.basic.entity.vo.user.*; import com.minimalist.basic.config.mybatis.bo.PageResp; import org.springframework.stereotype.Service; @Service public interface UserService { /** * 新增用户 * @param userVO 用户实体 */ void addUser(UserVO userVO); /** * 删除用户 * @param userId 用户ID */ void deleteUserByUserId(Long userId); /** * 修改用户 * @param userVO 用户数据 */ void updateUserByUserId(UserVO userVO); /** * 查询用户(分页) * @param queryVO 查询条件 * @return 用户分页数据 */ PageResp getPageUserList(UserQueryVO queryVO); /** * 根据用户ID查询用户 * @param userId 用户ID * @return 用户信息 */ UserVO getUserByUserId(Long userId); /** * 获取用户信息 * @return 用户VO */ UserInfoVO getUserInfo(); /** * 获取图形验证码 * @return 图形验证码 */ ImageCaptchaVO getImageCaptcha(); /** * 校验图形验证码 * @param captcha 验证码 * @param captchaId 验证码ID * @return true通过校验 false未通过校验 */ boolean checkImageCaptcha(String captcha, String captchaId); /** * 用户登录 * @param reqVO 用户登录信息 * @return token */ SaTokenInfo userLogin(UserLoginReqVO reqVO); /** * 重置密码 * @param passwordVO 重置密码实体 */ void resetPassword(RePasswordVO passwordVO); /** * 用户设置 -> 修改用户信息 * @param settingVO 用户信息 */ void updateUserInfo(UserSettingVO settingVO); /** * 修改用户头像 * @param userAvatar 用户头像base64编码 */ void updateUserAvatar(String userAvatar); } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/ConfigServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.json.JSONUtil; import com.minimalist.basic.entity.enums.ConfigEnum; import com.minimalist.basic.entity.enums.RespEnum; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.config.redis.RedisManager; import com.minimalist.basic.entity.po.MConfig; import com.minimalist.basic.entity.vo.config.ConfigQueryVO; import com.minimalist.basic.entity.vo.config.ConfigVO; import com.minimalist.basic.mapper.MConfigMapper; import com.minimalist.basic.service.ConfigService; import com.minimalist.basic.utils.CommonConstant; import com.minimalist.basic.utils.RedisKeyConstant; import com.minimalist.basic.utils.UnqIdUtil; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service public class ConfigServiceImpl implements ConfigService { @Autowired private MConfigMapper configMapper; @Autowired private RedisManager redisManager; /** * 添加参数 * @param configVO 参数配置信息 */ @Override @Transactional(rollbackFor = Exception.class) public void addConfig(ConfigVO configVO) { //检查键名唯一性 MConfig config = configMapper.selectConfigByConfigKey(configVO.getConfigKey(), null); Assert.isNull(config, () -> new BusinessException(ConfigEnum.ErrorMsg.CONTAIN_CONFIG_KEY.getDesc())); MConfig insertConfig = BeanUtil.copyProperties(configVO, MConfig.class); insertConfig.setConfigId(UnqIdUtil.uniqueId()); configMapper.insert(insertConfig, true); //发布消息 - 新增 redisManager.publishMessage(RedisKeyConstant.SYSTEM_CONFIG_TOPIC_KEY + "." + CommonConstant.ADD, JSONUtil.toJsonStr(configVO)); } /** * 删除参数 -> 根据参数ID删除 * @param configId 参数ID */ @Override public void deleteConfigByConfigId(Long configId) { MConfig config = configMapper.selectConfigByConfigId(configId); Assert.notNull(config, () -> new BusinessException(ConfigEnum.ErrorMsg.NONENTITY_CONFIG.getDesc())); Assert.isFalse(config.getConfigKey().startsWith("system."), () -> new BusinessException(ConfigEnum.ErrorMsg.CANNOT_DEL_SYSTEM_CONFIG.getDesc())); int deleteCount = configMapper.deleteConfigByConfigId(configId); Assert.isTrue(deleteCount == 1, () -> new BusinessException(RespEnum.FAILED.getDesc())); //发布消息 - 删除 redisManager.publishMessage(RedisKeyConstant.SYSTEM_CONFIG_TOPIC_KEY + "." + CommonConstant.DELETE, config.getConfigKey()); } /** * 修改参数 * @param configVO 参数配置信息 */ @Override public void updateConfigByConfigId(ConfigVO configVO) { //检查键名唯一性 MConfig config = configMapper.selectConfigByConfigKey(configVO.getConfigKey(), null); if (ObjectUtil.isNotNull(config) && !configVO.getConfigId().equals(config.getConfigId())) { throw new BusinessException(ConfigEnum.ErrorMsg.CONTAIN_CONFIG_KEY.getDesc()); } MConfig updateConfig = BeanUtil.copyProperties(configVO, MConfig.class); configMapper.updateConfigByConfigId(updateConfig); //发布消息 - 修改 redisManager.publishMessage(RedisKeyConstant.SYSTEM_CONFIG_TOPIC_KEY + "." + CommonConstant.UPDATE, JSONUtil.toJsonStr(configVO)); } /** * 查询参数配置列表(分页) * @param queryVO 查询条件 * @return 参数配置列表 */ @Override public PageResp getPageConfigList(ConfigQueryVO queryVO) { Page configPage = configMapper.selectPageConfigList(queryVO); List configVOList = BeanUtil.copyToList(configPage.getRecords(), ConfigVO.class); return new PageResp<>(configVOList, configPage.getTotalRow()); } /** * 根据参数ID查询参数 * @param configId 参数ID * @return 参数信息 */ @Override public ConfigVO getConfigByConfigId(Long configId) { return BeanUtil.copyProperties(configMapper.selectConfigByConfigId(configId), ConfigVO.class); } /** * 根据参数Key查询参数 - 状态为正常 * @param configKey 参数Key * @return 参数信息 */ @Override public ConfigVO getConfigByConfigKey(String configKey) { ConfigVO configVO = CommonConstant.systemConfigMap.get(configKey); if (ObjectUtil.isNull(configVO)) { MConfig mConfig = configMapper.selectConfigByConfigKey(configKey, StatusEnum.STATUS_1.getCode()); configVO = BeanUtil.copyProperties(mConfig, ConfigVO.class); //重新放入缓存 CommonConstant.systemConfigMap.put(configKey, configVO); } return configVO; } /** * 刷新配置缓存 */ @Override public void refreshConfigCache() { List configList = configMapper.selectListByQuery( QueryWrapper.create().eq(MConfig::getStatus, StatusEnum.STATUS_1.getCode())); for (MConfig config : configList) { ConfigVO configVO = BeanUtil.copyProperties(config, ConfigVO.class); //缓存系统配置到Map CommonConstant.systemConfigMap.put(configVO.getConfigKey(), configVO); } } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/DeptServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.minimalist.basic.entity.enums.DeptEnum; import com.minimalist.basic.entity.po.MDept; import com.minimalist.basic.entity.po.MUserDept; import com.minimalist.basic.entity.vo.dept.DeptQueryVO; import com.minimalist.basic.entity.vo.dept.DeptVO; import com.minimalist.basic.entity.vo.user.UserQueryVO; import com.minimalist.basic.entity.vo.user.UserVO; import com.minimalist.basic.mapper.MDeptMapper; import com.minimalist.basic.mapper.MUserDeptMapper; import com.minimalist.basic.mapper.MUserMapper; import com.minimalist.basic.service.DeptService; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.utils.CommonConstant; import com.minimalist.basic.utils.UnqIdUtil; import com.mybatisflex.core.logicdelete.LogicDeleteManager; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Comparator; import java.util.List; import java.util.Optional; @Service public class DeptServiceImpl implements DeptService { @Autowired private MUserMapper userMapper; @Autowired private MDeptMapper deptMapper; @Autowired private MUserDeptMapper userDeptMapper; /** * 添加部门 * @param deptVO 部门数据 */ @Override public void addDept(DeptVO deptVO) { MDept mDept = BeanUtil.copyProperties(deptVO, MDept.class); mDept.setDeptId(UnqIdUtil.uniqueId()); mDept.setStatus(StatusEnum.STATUS_1.getCode()); //如果不是顶级 if (CommonConstant.ZERO != deptVO.getParentDeptId()) { MDept parentDept = deptMapper.selectDeptByDeptId(deptVO.getParentDeptId()); //祖级列表 String ancestors = Optional.ofNullable(parentDept.getAncestors()) .map(a -> a + ",") .orElse("") + parentDept.getDeptId(); mDept.setAncestors(ancestors); } //新增 deptMapper.insert(mDept, true); } /** * 删除部门 -> 根据部门ID删除 * @param deptId 部门ID */ @Override @Transactional(rollbackFor = Exception.class) public void deleteDeptByDeptId(Long deptId) { //检查是否包含下级,包含下级不允许删除 long childrenCount = deptMapper.selectChildrenCountByDeptId(deptId); Assert.isFalse(childrenCount > 0, () -> new BusinessException(DeptEnum.ErrorMsg.CONTAIN_CHILDREN.getDesc())); //检查是否有用户在该部门,有用户在该部门不允许删除 UserQueryVO query = new UserQueryVO(); query.setPageNum(1L); query.setPageSize(1L); query.setDeptId(deptId); Page userVOPage = userMapper.selectPageUserList(query); Assert.isFalse(userVOPage.getTotalRow() > 0, () -> new BusinessException(DeptEnum.ErrorMsg.USER_DEPT_CHILDREN.getDesc())); //删除部门 deptMapper.deleteDeptByDeptId(deptId); //删除部门和用户关联关系 LogicDeleteManager.execWithoutLogicDelete(()-> userDeptMapper.deleteByQuery(QueryWrapper.create().eq(MUserDept::getDeptId, deptId)) ); } /** * 修改部门 -> 根据部门ID修改 * @param deptVO 部门数据 */ @Override @Transactional(rollbackFor = Exception.class) public void updateDeptByDeptId(DeptVO deptVO) { //查询本级部门 MDept currentDept = deptMapper.selectDeptByDeptId(deptVO.getDeptId()); Assert.notNull(currentDept, () -> new BusinessException(DeptEnum.ErrorMsg.NONENTITY_DEPT.getDesc())); MDept updateDept = BeanUtil.copyProperties(deptVO, MDept.class); //如果不是顶级部门,查询上级部门 if (CommonConstant.ZERO != deptVO.getParentDeptId()) { MDept parentDept = deptMapper.selectDeptByDeptId(deptVO.getParentDeptId()); //祖级列表 String ancestors = Optional.ofNullable(parentDept.getAncestors()) .map(a -> a + ",") .orElse("") + parentDept.getDeptId(); updateDept.setAncestors(ancestors); //修改当前部门所有下级 updateChildrenDeptAncestors(deptVO.getDeptId(), currentDept.getAncestors(), ancestors); } else { //修改当前部门所有下级 updateChildrenDeptAncestors(deptVO.getDeptId(), currentDept.getAncestors(), ""); } deptMapper.updateDeptByDeptId(updateDept); } /** * 根据部门ID修改下级部门的祖级 * @param deptId 部门ID * @param oldAncestors 旧的祖级 * @param newAncestors 新的祖级 */ private void updateChildrenDeptAncestors(Long deptId, String oldAncestors, String newAncestors) { //修改当前部门所有下级 List children = deptMapper.selectChildrenDeptByDeptId(deptId); for (MDept child : children) { if (StrUtil.isBlank(oldAncestors)) { if (StrUtil.isNotBlank(newAncestors)) { child.setAncestors(newAncestors); } } else { child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); } deptMapper.updateDeptByDeptId(child); } } /** * 查询部门列表(全部不分页) -> 部门管理使用 * @param queryVO 查询参数 * @return 部门树 */ @Override public List getDeptList(DeptQueryVO queryVO) { return deptToTree(deptMapper.selectDeptList(queryVO)); } /** * 根据部门ID查询部门 * @param deptId 部门ID * @return 部门数据 */ @Override public DeptVO getDeptByDeptId(Long deptId) { return BeanUtil.copyProperties(deptMapper.selectDeptByDeptId(deptId), DeptVO.class); } /** * 查询部门列表 -> 其他地方使用(只获取正常状态的部门) * @return 部门树 */ @Override public List getEnableDeptList() { //部门树 return deptToTree(deptMapper.selectDeptDict()); } /** * 根据部门ID查询部门 * @param deptIds 部门ID列表 * @return 用户所属部门列表 */ @Override public List getDeptByDeptIds(List deptIds) { List deptList = deptMapper.selectDeptByDeptIds(deptIds); return BeanUtil.copyToList(deptList, DeptVO.class); } /** * 转换部门树 * @param deptList 部门数据集合 * @return 部门数据集合 */ private List deptToTree(List deptList) { if (CollectionUtil.isEmpty(deptList)) { return CollectionUtil.list(false); } //查找顶级节点 List rootNodeList = deptList.stream() .filter(p -> ObjectUtil.isNotNull(p.getParentDeptId())) .filter(p -> CommonConstant.ZERO == p.getParentDeptId()) .map(p -> BeanUtil.copyProperties(p, DeptVO.class)) .sorted(Comparator.comparing(DeptVO::getDeptSort)) .toList(); //查找子节点 findChildren(deptList, rootNodeList); return rootNodeList; } /** * 查找子节点 * @param deptList 部门数据集合 * @param rootNodeList 部门顶级节点数据集合 */ private void findChildren(List deptList, List rootNodeList) { //遍历顶级节点 rootNodeList.forEach(node -> { //存储子节点 List childrenNodes = CollectionUtil.list(false); //从部门数据集合中查找子节点 deptList.forEach(p -> { //节点是否关联 if (node.getDeptId().equals(p.getParentDeptId())) { childrenNodes.add(BeanUtil.copyProperties(p, DeptVO.class)); } //显示排序 childrenNodes.sort(Comparator.comparing(DeptVO::getDeptSort)); }); //如果有关联的子节点 if (CollectionUtil.isNotEmpty(childrenNodes)) { //将查询到的子节点挂在顶级节点上 node.setChildren(childrenNodes); //对子节点继续递归,查找子节点的下级 findChildren(deptList, childrenNodes); } }); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/DictServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import com.minimalist.basic.config.eDict.BeanMethod; import com.minimalist.basic.entity.enums.DictEnum; import com.minimalist.basic.entity.po.MDict; import com.minimalist.basic.entity.vo.dict.*; import com.minimalist.basic.mapper.MDictMapper; import com.minimalist.basic.service.DictService; import com.minimalist.basic.service.EDictService; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.eDict.EDictConstant; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.config.redis.RedisManager; import com.minimalist.basic.utils.RedisKeyConstant; import com.minimalist.basic.utils.UnqIdUtil; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import org.redisson.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Service public class DictServiceImpl implements DictService { @Autowired private MDictMapper dictMapper; @Autowired private RedisManager redisManager; @Autowired private RedissonClient redissonClient; /** * 新增字典 * @param dictInfoVO 字典实体 */ @Override public void addDict(DictInfoVO dictInfoVO) { //状态默认正常 dictInfoVO.getDictDataList().forEach(d -> d.setStatus(StatusEnum.STATUS_1.getCode())); //数据转换,构建字典实体数据 List dictList = buildDictData(dictInfoVO, true); //批量新增 dictMapper.insertBatch(dictList); //缓存处理 setDictCacheHandler(CollectionUtil.list(false, dictInfoVO.getDictType())); } /** * 删除字典 -> 根据字典ID删除 * @param dictId 字典ID */ @Override public void deleteDictByDictId(Long dictId) { //查询字典 MDict mDict = dictMapper.selectDictByDictId(dictId); Assert.notNull(mDict, () -> new BusinessException(DictEnum.ErrorMsg.NONENTITY_DICT.getDesc())); //删除字典 dictMapper.deleteDictByDictId(dictId); //删除缓存 String dictCacheKey = StrUtil.indexedFormat(RedisKeyConstant.DICT_CACHE_KEY, mDict.getDictType()); redisManager.delete(dictCacheKey); } /** * 删除字典 -> 根据字典类型删除 * @param dictType 字典类型 */ @Override public void deleteDictByDictType(String dictType) { //删除字典 dictMapper.deleteDictByDictType(dictType); //删除缓存 String dictCacheKey = StrUtil.indexedFormat(RedisKeyConstant.DICT_CACHE_KEY, dictType); redisManager.delete(dictCacheKey); } /** * 修改字典 * @param dictInfoVO 字典实体 */ @Override @Transactional(rollbackFor = Exception.class) public void updateDictByDictId(DictInfoVO dictInfoVO) { //需要新增的数据 -> 没有dictId的数据 List dueInsertData = CollectionUtil.list(false); Iterator dictDataVOIterator = dictInfoVO.getDictDataList().iterator(); while (dictDataVOIterator.hasNext()) { DictDataVO dictDataVO = dictDataVOIterator.next(); if (ObjectUtil.isNull(dictDataVO.getDictId())) { dueInsertData.add(dictDataVO); dictDataVOIterator.remove(); } } //处理新增的数据 if (CollectionUtil.isNotEmpty(dueInsertData)) { List dictList = dueInsertData.stream().map(dict -> { MDict mDict = new MDict(); mDict.setDictId(UnqIdUtil.uniqueId()); mDict.setDictKey(dict.getDictKey()); mDict.setDictValue(dict.getDictValue()); mDict.setDictOrder(dict.getDictOrder()); mDict.setStatus(dict.getStatus()); mDict.setDictType(dictInfoVO.getDictType()); mDict.setDictName(dictInfoVO.getDictName()); mDict.setDictDesc(dictInfoVO.getDictDesc()); mDict.setCreateId(StpUtil.getLoginIdAsLong()); mDict.setCreateTime(LocalDateTime.now()); mDict.setUpdateId(StpUtil.getLoginIdAsLong()); mDict.setUpdateTime(LocalDateTime.now()); return mDict; }).toList(); //批量新增 dictMapper.insertBatch(dictList); } //处理修改的数据 if (CollectionUtil.isNotEmpty(dictInfoVO.getDictDataList())) { List dictList = buildDictData(dictInfoVO, false); for (MDict mDict : dictList) { dictMapper.updateDictByDictId(mDict); } } //缓存处理 setDictCacheHandler(CollectionUtil.list(false, dictInfoVO.getDictType())); } /** * 查询字典列表(分页) * @param queryVO 查询实体 * @return 分页字典数据列表 */ @Override public PageResp getPageDictList(DictQueryVO queryVO) { Page dictVOPage = dictMapper.selectPageDictList(queryVO); return new PageResp<>(dictVOPage.getRecords(), dictVOPage.getTotalRow()); } /** * 根据字典类型查询字典 * @param dictType 字典类型 * @return 字典数据 */ @Override public DictInfoVO getDictByDictType(String dictType) { //查询字典 List dictList = dictMapper.selectDictListByDictType(CollectionUtil.list(false, dictType)); Assert.notEmpty(dictList, () -> new BusinessException(DictEnum.ErrorMsg.NONENTITY_DICT.getDesc())); //构建返回数据 DictInfoVO dictInfoVO = new DictInfoVO(); dictInfoVO.setDictName(dictList.get(0).getDictName()); dictInfoVO.setDictDesc(dictList.get(0).getDictDesc()); dictInfoVO.setDictType(dictList.get(0).getDictType()); List dictDataVOList = dictList.stream().map(dict -> { DictDataVO dictDataVO = new DictDataVO(); dictDataVO.setDictId(dict.getDictId()); dictDataVO.setDictKey(dict.getDictKey()); dictDataVO.setDictValue(dict.getDictValue()); dictDataVO.setDictOrder(dict.getDictOrder()); dictDataVO.setDictClass(dict.getDictClass()); dictDataVO.setStatus(dict.getStatus()); return dictDataVO; }).collect(Collectors.toList()); dictInfoVO.setDictDataList(dictDataVOList); return dictInfoVO; } /** * 根据字典类型查询字典 * @param dictTypes 字典类型,为空查询所有字典数据 * @return 字典数据列表 */ @Override public List getDictList(List dictTypes) { //区分是否要获取额外字典数据 Iterator dictTypeIter = dictTypes.iterator(); //获取额外字典 List extraDictTypeList = CollectionUtil.list(false); while (dictTypeIter.hasNext()) { String dictType = dictTypeIter.next(); //如果该字典为额外字典数据 if (EDictConstant.dictMethodMap.containsKey(dictType)) { extraDictTypeList.add(dictType); dictTypeIter.remove(); } } //返回结果 List result = CollectionUtil.list(false); //额外字典获取 if (CollectionUtil.isNotEmpty(extraDictTypeList)) { extraDictTypeList.forEach(ed -> { BeanMethod beanMethod = (BeanMethod) EDictConstant.dictMethodMap.get(ed); DictCacheVO dictCacheVO = ReflectUtil.invoke(beanMethod.getBean(), beanMethod.getMethod(), ed); result.add(dictCacheVO); }); } //常规字典获取 if (CollectionUtil.isNotEmpty(dictTypes)) { //从缓存中获取字典 List dictCache = getDictCacheHandler(dictTypes); //检查从缓存获取的字典是否缺失,缺失说明redis中数据过期 if (dictTypes.size() != dictCache.size()) { //将缺失的字典type找出来 List dueDictTypeList = CollectionUtil.list(false); for (String dictType : dictTypes) { boolean c = false; for (DictCacheVO dictCacheVO : dictCache) { if (dictCacheVO.getDictType().equals(dictType)) { c = true; break; } } if (!c) { dueDictTypeList.add(dictType); } } //将未获取到的字典,重新获取 if (CollectionUtil.isNotEmpty(dueDictTypeList)) { dictCache.addAll(setDictCacheHandler(dueDictTypeList)); } } result.addAll(dictCache); } return result; } /** * 添加字典数据到缓存 */ private List setDictCacheHandler(List dictType) { //返回结果 List resultList = CollectionUtil.list(false); //查询数据库中的字典数据 List mDicts; if (CollectionUtil.isEmpty(dictType)) { //查询全部 mDicts = dictMapper.selectListByQuery(QueryWrapper.create() .eq(MDict::getStatus, StatusEnum.STATUS_1.getCode()) .orderBy(MDict::getDictOrder, true)); } else { //按字典类型查询 mDicts = dictMapper.selectDictListByDictType(dictType); } if (CollectionUtil.isNotEmpty(mDicts)) { //转Map,key:字典类型,value:字典数据集合 Map> dictMap = mDicts.stream().collect(Collectors.groupingBy(MDict::getDictType)); //批量存储到缓存 RBatch batch = redissonClient.createBatch(); dictMap.keySet().forEach(dt -> { List dictList = dictMap.get(dt); String dictCacheKey = StrUtil.indexedFormat(RedisKeyConstant.DICT_CACHE_KEY, dt); RBucketAsync> bucket = batch.getBucket(dictCacheKey); //拷贝 List dictKVList = BeanUtil.copyToList(dictList, DictCacheVO.DictKV.class); bucket.setAsync(dictKVList, RedisKeyConstant.DICT_CACHE_EX + redisManager.randomSeconds(), TimeUnit.SECONDS); //添加到返回值 DictCacheVO dictCacheVO = new DictCacheVO(); dictCacheVO.setDictType(dictList.get(0).getDictType()); dictCacheVO.setDictList(dictKVList); resultList.add(dictCacheVO); }); batch.execute(); } return resultList; } /** * 从缓存中获取字典数据 * @param dictType 字典类型,为空则获取所有字典数据 * @return 字典数据列表 */ private List getDictCacheHandler(List dictType) { List resultList = CollectionUtil.list(false); //获取部分字典数据 if (CollectionUtil.isNotEmpty(dictType)) { //批量获取字典缓存 RBatch batch = redissonClient.createBatch(); dictType.forEach(dt -> { String dictCacheKey = StrUtil.indexedFormat(RedisKeyConstant.DICT_CACHE_KEY, dt); RBucketAsync> bucket = batch.getBucket(dictCacheKey); bucket.getAsync(); }); BatchResult batchResult = batch.execute(); List responses = batchResult.getResponses(); if (CollectionUtil.isNotEmpty(responses)) { responses.forEach(resp -> { List dictVOList = (List) resp; if (CollectionUtil.isNotEmpty(dictVOList)) { DictCacheVO dictCacheVO = new DictCacheVO(); dictCacheVO.setDictType(dictVOList.get(0).getDictType()); dictCacheVO.setDictList(dictVOList); resultList.add(dictCacheVO); } }); } } else { //获取全部字典数据 RKeys keys = redissonClient.getKeys(); String keyPrefix = StrUtil.subBefore(RedisKeyConstant.DICT_CACHE_KEY, ":", false); Iterable keysByPattern = keys.getKeysByPattern(keyPrefix + ":*"); Set keySet = CollectionUtil.set(false); keysByPattern.forEach(keySet::add); RMap> cacheMap = redissonClient.getMap(keyPrefix); Map> dictCacheMap = cacheMap.getAll(keySet); if (MapUtil.isNotEmpty(dictCacheMap)) { dictCacheMap.values().forEach(dictVOList -> { DictCacheVO dictCacheVO = new DictCacheVO(); dictCacheVO.setDictType(dictVOList.get(0).getDictType()); dictCacheVO.setDictList(dictVOList); resultList.add(dictCacheVO); }); } } return resultList; } /** * 构建字典实体数据 * @param dictInfoVO 字典数据 * @return 字典实体 */ private List buildDictData(DictInfoVO dictInfoVO, boolean unqId) { return dictInfoVO.getDictDataList().stream() .map(dict -> { MDict mDict = new MDict(); if (unqId) { mDict.setDictId(UnqIdUtil.uniqueId()); mDict.setCreateId(StpUtil.getLoginIdAsLong()); mDict.setCreateTime(LocalDateTime.now()); } else { mDict.setDictId(dict.getDictId()); } mDict.setDictKey(dict.getDictKey()); mDict.setDictValue(dict.getDictValue()); mDict.setDictOrder(dict.getDictOrder()); mDict.setStatus(dict.getStatus()); mDict.setDictClass(dict.getDictClass()); mDict.setDictType(dictInfoVO.getDictType()); mDict.setDictName(dictInfoVO.getDictName()); mDict.setDictDesc(dictInfoVO.getDictDesc()); mDict.setUpdateId(StpUtil.getLoginIdAsLong()); mDict.setUpdateTime(LocalDateTime.now()); return mDict; }).toList(); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/EDictServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.hutool.core.collection.CollectionUtil; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.po.*; import com.minimalist.basic.entity.vo.dict.DictCacheVO; import com.minimalist.basic.entity.vo.tenant.TenantVO; import com.minimalist.basic.mapper.*; import com.minimalist.basic.service.EDictService; import com.minimalist.basic.config.eDict.EDict; import com.minimalist.basic.config.eDict.EDictConstant; import com.minimalist.basic.utils.CommonConstant; import com.minimalist.basic.utils.TenantUtil; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * 额外的字典数据,这些数据不会出现在字典管理表中,因为这些数据是来源于其他表 */ @Service public class EDictServiceImpl implements EDictService { @Autowired private MDeptMapper deptMapper; @Autowired private MUserMapper userMapper; @Autowired private MRoleMapper roleMapper; @Autowired private MPostMapper postMapper; @Autowired private MTenantMapper tenantMapper; @Autowired private MTenantPackageMapper tenantPackageMapper; @Autowired private MStorageMapper storageMapper; /** * 获取部门字典数据 * @return 字典数据列表 */ @Override @EDict(dictType = EDictConstant.DEPT_LIST) public DictCacheVO getDeptDictData() { DictCacheVO dictCacheVO = new DictCacheVO(); dictCacheVO.setDictType(EDictConstant.DEPT_LIST); //查询部门列表 List deptList = deptMapper.selectDeptDict(); if (CollectionUtil.isNotEmpty(deptList)) { List dictKVList = deptList.stream().map(dept -> { DictCacheVO.DictKV dictKV = new DictCacheVO.DictKV(); dictKV.setDictKey(dept.getDeptId().toString()); dictKV.setDictValue(dept.getDeptName()); dictKV.setDictType(EDictConstant.DEPT_LIST); return dictKV; }).toList(); dictCacheVO.setDictList(dictKVList); } return dictCacheVO; } /** * 获取用户字典数据 * @return 字典数据列表 */ @Override @EDict(dictType = EDictConstant.USER_LIST) public DictCacheVO getUserDictData() { return getUserDictList(EDictConstant.USER_LIST); } /** * 获取租户套餐字典数据(额外字典数据) * @return 字典数据列表 */ @Override @EDict(dictType = EDictConstant.TENANT_PACKAGE_LIST) public DictCacheVO getTenantPackageDictData() { DictCacheVO dictCacheVO = new DictCacheVO(); dictCacheVO.setDictType(EDictConstant.TENANT_PACKAGE_LIST); //查询所有租户套餐 List tenantPackageList = tenantPackageMapper.selectTenantPackageDict(); if (CollectionUtil.isNotEmpty(tenantPackageList)) { List dictKVList = tenantPackageList.stream().map(dept -> { DictCacheVO.DictKV dictKV = new DictCacheVO.DictKV(); dictKV.setDictKey(dept.getPackageId().toString()); dictKV.setDictValue(dept.getPackageName()); dictKV.setDictType(EDictConstant.TENANT_PACKAGE_LIST); return dictKV; }).toList(); dictCacheVO.setDictList(dictKVList); } return dictCacheVO; } /** * 获取角色字典数据 * @return 字典数据列表 */ @Override @EDict(dictType = EDictConstant.ROLE_LIST) public DictCacheVO getRoleDictData() { DictCacheVO dictCacheVO = new DictCacheVO(); dictCacheVO.setDictType(EDictConstant.ROLE_LIST); //查询角色列表 List roleList = roleMapper.selectRoleDict(); if (CollectionUtil.isNotEmpty(roleList)) { List dictKVList = roleList.stream().map(role -> { DictCacheVO.DictKV dictKV = new DictCacheVO.DictKV(); dictKV.setDictKey(role.getRoleId().toString()); dictKV.setDictValue(role.getRoleName()); dictKV.setDictType(EDictConstant.ROLE_LIST); return dictKV; }).toList(); dictCacheVO.setDictList(dictKVList); } return dictCacheVO; } /** * 获取岗位字典数据(额外字典数据) * @return 字典数据列表 */ @Override @EDict(dictType = EDictConstant.POST_LIST) public DictCacheVO getPostDictData() { DictCacheVO dictCacheVO = new DictCacheVO(); dictCacheVO.setDictType(EDictConstant.POST_LIST); //查询岗位列表 List postList = postMapper.selectPostDict(); if (CollectionUtil.isNotEmpty(postList)) { List dictKVList = postList.stream().map(post -> { DictCacheVO.DictKV dictKV = new DictCacheVO.DictKV(); dictKV.setDictKey(post.getPostId().toString()); dictKV.setDictValue(post.getPostName()); dictKV.setDictType(EDictConstant.POST_LIST); return dictKV; }).toList(); dictCacheVO.setDictList(dictKVList); } return dictCacheVO; } /** * 获取租户字典数据(额外字典数据) * @return 字典数据列表 */ @Override @EDict(dictType = EDictConstant.TENANT_LIST) public DictCacheVO getTenantDictData() { DictCacheVO dictCacheVO = new DictCacheVO(); dictCacheVO.setDictType(EDictConstant.TENANT_LIST); //查询租户列表 List tenantList = tenantMapper.selectTenantDict(); if (CollectionUtil.isNotEmpty(tenantList)) { List dictKVList = tenantList.stream() .map(tenant -> { DictCacheVO.DictKV dictKV = new DictCacheVO.DictKV(); dictKV.setDictKey(tenant.getTenantId().toString()); dictKV.setDictValue(tenant.getTenantName()); dictKV.setDictType(EDictConstant.TENANT_LIST); return dictKV; }).toList(); dictCacheVO.setDictList(dictKVList); } return dictCacheVO; } /** * 获取存储方式数据(额外字典数据) * @return 字典数据列表 */ @Override @EDict(dictType = EDictConstant.STORAGE_LIST) public DictCacheVO getStorageDictData() { DictCacheVO dictCacheVO = new DictCacheVO(); dictCacheVO.setDictType(EDictConstant.STORAGE_LIST); //系统租户,查询全部存储 if (TenantUtil.checkIsSystemTenant()) { List mStorages = storageMapper.selectListByQuery(QueryWrapper.create() .eq(MStorage::getStatus, StatusEnum.STATUS_1.getCode())); List dictKVList = mStorages.stream() .map(storage -> { DictCacheVO.DictKV dictKV = new DictCacheVO.DictKV(); dictKV.setDictKey(storage.getStorageId().toString()); dictKV.setDictValue(storage.getStorageName()); dictKV.setDictType(EDictConstant.STORAGE_LIST); return dictKV; }).toList(); dictCacheVO.setDictList(dictKVList); } else { //普通租户,查询租户自己的存储 TenantVO tenantVO = CommonConstant.tenantMap.get(TenantUtil.getTenantId()); MStorage storage = storageMapper.selectStorageByStorageId(tenantVO.getStorageId()); List dictKVList = CollectionUtil.list(false); DictCacheVO.DictKV dictKV = new DictCacheVO.DictKV(); dictKV.setDictKey(storage.getStorageId().toString()); dictKV.setDictValue(storage.getStorageName()); dictKV.setDictType(EDictConstant.STORAGE_LIST); dictKVList.add(dictKV); dictCacheVO.setDictList(dictKVList); } return dictCacheVO; } /** * 获取用户字典数据 * @param dictType 字典类型 * @return 字典数据 */ private DictCacheVO getUserDictList(String dictType) { //返回结果 DictCacheVO dictCacheVO = new DictCacheVO(); dictCacheVO.setDictType(dictType); //查询用户列表 List userList = userMapper.selectUserDict(); if (CollectionUtil.isNotEmpty(userList)) { List dictKVList = userList.stream().map(dept -> { DictCacheVO.DictKV dictKV = new DictCacheVO.DictKV(); dictKV.setDictKey(dept.getUserId().toString()); dictKV.setDictValue(dept.getNickname()); dictKV.setDictType(dictType); return dictKV; }).toList(); dictCacheVO.setDictList(dictKVList); } return dictCacheVO; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/FileServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.fileHandler.FileManager; import com.minimalist.basic.config.fileHandler.handler.FileHandler; import com.minimalist.basic.entity.enums.FileEnum; import com.minimalist.basic.entity.enums.StorageEnum; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.entity.enums.TenantEnum; import com.minimalist.basic.entity.po.MFile; import com.minimalist.basic.entity.po.MStorage; import com.minimalist.basic.entity.po.MTenant; import com.minimalist.basic.entity.vo.file.*; import com.minimalist.basic.mapper.MFileMapper; import com.minimalist.basic.mapper.MStorageMapper; import com.minimalist.basic.mapper.MTenantMapper; import com.minimalist.basic.service.FileService; import com.minimalist.basic.utils.TenantUtil; import com.mybatisflex.core.logicdelete.LogicDeleteManager; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.time.LocalDateTime; import java.util.List; import java.util.StringJoiner; @Service public class FileServiceImpl implements FileService { @Autowired private MFileMapper fileMapper; @Autowired private MStorageMapper storageMapper; @Autowired private FileManager fileManager; @Autowired private MTenantMapper tenantMapper; /** * 单文件上传 * @param fileUploadVO 文件及携带参数 * @return 文件信息 */ @Override public FileUploadRespVO uploadFile(FileUploadVO fileUploadVO) { MStorage storage = getStorage(fileUploadVO.getStorageId()); Assert.notNull(storage, () -> new BusinessException(StorageEnum.ErrorMsg.NONENTITY_STORAGE.getDesc())); FileHandler fileHandler = fileManager.getFileHandler(storage.getStorageType()); //上传文件 MFile mFile = fileHandler.uploadFile(fileUploadVO.getFile(), fileUploadVO.getFileSource(), storage); fileMapper.insert(mFile, true); return BeanUtil.copyProperties(mFile, FileUploadRespVO.class); } /** * 多上传文件 * @param uploadBatchVO 文件及携带参数 * @return 文件信息 */ @Override public List uploadFileBatch(FileUploadBatchVO uploadBatchVO) { MStorage storage = getStorage(uploadBatchVO.getStorageId()); Assert.notNull(storage, () -> new BusinessException(StorageEnum.ErrorMsg.NONENTITY_STORAGE.getDesc())); FileHandler fileHandler = fileManager.getFileHandler(storage.getStorageType()); //循环上传多个文件 List files = CollectionUtil.list(false); for (MultipartFile file : uploadBatchVO.getFiles()) { MFile mFile = fileHandler.uploadFile(file, uploadBatchVO.getFileSource(), storage); files.add(mFile); } //批量插入文件信息 fileMapper.insertBatch(files); return BeanUtil.copyToList(files, FileUploadRespVO.class); } /** * 删除文件 * @param fileId 文件ID */ @Override public void deleteFile(Long fileId) { //查询文件 MFile mFile = fileMapper.selectFileByFileId(fileId); Assert.notNull(mFile, () -> new BusinessException(FileEnum.ErrorMsg.NONENTITY_FILE.getDesc())); MStorage storage = getStorage(mFile.getStorageId()); FileHandler fileHandler = fileManager.getFileHandler(storage.getStorageType()); //删除文件 boolean deleteFile = fileHandler.deleteFile(mFile, storage); if (!deleteFile) { throw new BusinessException(FileEnum.ErrorMsg.FILE_DELETE_FAIL.getDesc()); } //删除数据库文件记录 LogicDeleteManager.execWithoutLogicDelete(()-> fileMapper.deleteByQuery(QueryWrapper.create().eq(MFile::getFileId, fileId)) ); } /** * 移动文件 * 在前端文件选择组件上传文件时不需要指定文件来源,默认会上传到common目录, * 后端处理时可以将文件从common目录移动到对应业务的目录中 * @param fileId 文件ID * @param fileSource 文件来源 * @return 移动后的文件 */ @Override public MFile moveFile(Long fileId, Integer fileSource) { //查询文件 MFile file = fileMapper.selectFileByFileId(fileId); Assert.notNull(file, () -> new BusinessException(FileEnum.ErrorMsg.NONENTITY_FILE.getDesc())); MStorage storage = getStorage(file.getStorageId()); //设置文件来源 - 在文件选择组件中上传的文件没有文件来源,所以这里要设置 file.setFileSource(fileSource); //修改文件信息 file.setUpdateId(StpUtil.getLoginIdAsLong()); file.setUpdateTime(LocalDateTime.now()); //移动文件 FileHandler fileHandler = fileManager.getFileHandler(storage.getStorageType()); fileHandler.moveFile(file, storage); //更新文件信息 fileMapper.updateByQuery(file, QueryWrapper.create().eq(MFile::getFileId, fileId)); return file; } /** * 查询文件列表(分页) * @param queryVO 查询条件 * @return 文件分页数据 */ @Override public PageResp getPageFileList(FileQueryVO queryVO) { Page filePage = fileMapper.selectPageFileList(queryVO); //数据转换 List fileVOList = CollectionUtil.list(false); for (MFile record : filePage.getRecords()) { FileVO fileVO = BeanUtil.copyProperties(record, FileVO.class); //文件类型后缀 if (StrUtil.isNotBlank(fileVO.getFileType())) { String ft = StrUtil.subAfter(fileVO.getFileType(), "/", true); fileVO.setFileTypeSuffix(ft); } fileVOList.add(fileVO); } return new PageResp<>(fileVOList, filePage.getTotalRow()); } /** * 移动文件 * 用于将前端传递的多个FileVO文件移动,并更新文件信息,已指定fileSource的只更新文件状态 * @param files 文件信息 * @param fileSource 文件来源 * @return 文件ID,逗号分隔 */ @Override public String moveFile(List files, Integer fileSource) { StringJoiner fileIds = new StringJoiner(","); //处理公告封面图片 if (CollectionUtil.isNotEmpty(files)) { for (FileVO fileVO : files) { //已指定文件来源 - 跳过 if (ObjectUtil.isNotNull(fileVO.getFileSource()) && fileVO.getFileSource() != -1) { //文件ID,逗号分隔 fileIds.add(fileVO.getFileId().toString()); continue; } //移动文件到对应的目录 MFile newFile = moveFile(fileVO.getFileId(), fileSource); //文件ID,逗号分隔 fileIds.add(fileVO.getFileId().toString()); } } return fileIds.toString(); } /** * 移动文件 * 用于根据文件url将文件移动,并更新文件信息,已指定fileSource的只更新文件状态 * @param fileUrl 文件url * @param fileSource 文件来源 * @return 移动后的文件 */ @Override public MFile moveFile(String fileUrl, Integer fileSource) { //从url中提取文件名 String cleanUrl = StrUtil.subBefore(fileUrl, "?", true); String fileName = StrUtil.subAfter(cleanUrl, "/", true); //根据文件名查询文件 MFile file = fileMapper.selectOneByQuery(QueryWrapper.create().eq(MFile::getNewFileName, fileName)); //未查询到文件,跳过 if (ObjectUtil.isNull(file)) { return null; } //已指定文件来源 - 跳过 if (ObjectUtil.isNotNull(file.getFileSource()) && file.getFileSource() != -1) { return null; } //移动文件到对应的目录 return moveFile(file.getFileId(), fileSource); } /** * 获取存储信息 * @param storageId 存储ID * @return 存储信息 */ private MStorage getStorage(Long storageId) { if (ObjectUtil.isNotNull(storageId)) { return storageMapper.selectStorageByStorageId(storageId); } //未指定存储,根据租户ID获取 MTenant tenant = tenantMapper.selectTenantByTenantId(TenantUtil.getTenantId()); Assert.notNull(tenant, () -> new BusinessException(TenantEnum.ErrorMsg.QUERY_NULL_TENANT.getDesc())); return storageMapper.selectStorageByStorageId(tenant.getStorageId()); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/NoticeServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.minimalist.basic.entity.enums.FileEnum; import com.minimalist.basic.entity.enums.NoticeEnum; import com.minimalist.basic.entity.po.MFile; import com.minimalist.basic.entity.po.MNotice; import com.minimalist.basic.entity.vo.file.FileVO; import com.minimalist.basic.entity.vo.notice.NoticeQueryVO; import com.minimalist.basic.entity.vo.notice.NoticeVO; import com.minimalist.basic.mapper.MFileMapper; import com.minimalist.basic.mapper.MNoticeMapper; import com.minimalist.basic.service.FileService; import com.minimalist.basic.service.NoticeService; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.config.mybatis.bo.PageReq; import com.minimalist.basic.utils.TextUtil; import com.minimalist.basic.utils.UnqIdUtil; import com.mybatisflex.core.paginate.Page; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @Slf4j @Service public class NoticeServiceImpl implements NoticeService { @Autowired private MNoticeMapper noticeMapper; @Autowired private MFileMapper fileMapper; @Autowired private FileService fileService; /** * 添加公告 * @param noticeVO 公告信息 */ @Override @DSTransactional(rollbackFor = Exception.class) public void addNotice(NoticeVO noticeVO) { MNotice mNotice = BeanUtil.copyProperties(noticeVO, MNotice.class); //公告ID long noticeId = UnqIdUtil.uniqueId(); mNotice.setNoticeId(noticeId); //延期发布处理 if (ObjectUtil.isNotNull(noticeVO.getNoticeTimeInterval())) { //延期发布 -> 发布时间置为延期发布的时间 mNotice.setPublishTime(noticeVO.getNoticeTimeInterval()); } else { //不延期 -> 发布时间置为当前时间 mNotice.setPublishTime(LocalDateTime.now()); } //公告相关文件处理 String fileIds = saveNoticeFileHandler(noticeVO); mNotice.setNoticePicFileId(fileIds); //内容处理 -> 编码 mNotice.setNoticeContent(TextUtil.encode(noticeVO.getNoticeContent())); noticeMapper.insert(mNotice, true); } /** * 删除公告 -> 根据公告ID删除 * @param noticeId 公告ID */ @Override @DSTransactional(rollbackFor = Exception.class) public void deleteNoticeByNoticeId(Long noticeId) { //查询公告 MNotice mNotice = noticeMapper.selectNoticeByNoticeId(noticeId); Assert.notNull(mNotice, () -> new BusinessException(NoticeEnum.ErrorMsg.NONENTITY_NOTICE.getDesc())); //删除公告 noticeMapper.deleteNoticeByNoticeId(noticeId); } /** * 修改公告 -> 根据公告ID修改 * @param noticeVO 公告信息 */ @Override @DSTransactional(rollbackFor = Exception.class) public void updateNoticeByNoticeId(NoticeVO noticeVO) { //查询公告 MNotice mNotice = noticeMapper.selectNoticeByNoticeId(noticeVO.getNoticeId()); Assert.notNull(mNotice, () -> new BusinessException(NoticeEnum.ErrorMsg.NONENTITY_NOTICE.getDesc())); MNotice newNotice = BeanUtil.copyProperties(noticeVO, MNotice.class); //延期发布处理 if (ObjectUtil.isNotNull(noticeVO.getNoticeTimeInterval())) { //延期发布 -> 发布时间置为延期发布的时间 newNotice.setPublishTime(noticeVO.getNoticeTimeInterval()); } else { //不延期 -> 不处理,不修改发布时间 } //公告相关文件处理 String fileIds = saveNoticeFileHandler(noticeVO); newNotice.setNoticePicFileId(fileIds); //内容处理 -> 编码 newNotice.setNoticeContent(TextUtil.encode(noticeVO.getNoticeContent())); //修改 noticeMapper.updateNoticeByNoticeId(newNotice); } /** * 查询公告列表(分页) -> 公告管理使用 * @param queryVO 查询条件 * @return 公告分页数据 */ @Override public PageResp getPageNoticeList(NoticeQueryVO queryVO) { //分页查询 Page mNoticePage = noticeMapper.selectPageNoticeList(queryVO); //数据转换 List noticeVOS = BeanUtil.copyToList(mNoticePage.getRecords(), NoticeVO.class); //汇总封面图文件ID List noticePicFileIdList = noticeVOS.stream().filter(n -> StrUtil.isNotBlank(n.getNoticePicFileId())) .flatMap(n -> { List fileIdList = TextUtil.splitAndListStrToListLong(n.getNoticePicFileId()); return Arrays.stream(fileIdList.toArray(Long[]::new)); }).toList(); if (CollectionUtil.isNotEmpty(noticePicFileIdList)) { //根据文件ID查询文件 List fileList = fileMapper.selectFileByFileIds(noticePicFileIdList); //将文件按照URL转Map,key:文件ID,value:文件实体 Map fileMap = fileList.stream().collect(Collectors.toMap(MFile::getFileId, Function.identity(), (v1, v2) -> v1)); noticeVOS.forEach(n -> { //内容清空 n.setNoticeContent(null); //封面图文件处理 if (StrUtil.isNotBlank(n.getNoticePicFileId())) { List fileIdList = TextUtil.splitAndListStrToListLong(n.getNoticePicFileId()); List fileVOList = CollectionUtil.list(false); fileIdList.forEach(fileId -> { if (fileMap.containsKey(fileId)) { MFile mFile = fileMap.get(fileId); fileVOList.add(BeanUtil.copyProperties(mFile, FileVO.class)); } }); //设置封面图文件 n.setNoticePicFile(fileVOList); } }); } else { //将内容清空,因为列表不需要展示内容 noticeVOS.forEach(n -> n.setNoticeContent(null)); } return new PageResp<>(noticeVOS, mNoticePage.getTotalRow()); } /** * 根据公告ID查询公告 * @param noticeId 公告ID * @return 公告信息 */ @Override public NoticeVO getNoticeByNoticeId(Long noticeId) { MNotice mNotice = noticeMapper.selectNoticeByNoticeId(noticeId); //内容 -> 解码 mNotice.setNoticeContent(TextUtil.decode(mNotice.getNoticeContent())); NoticeVO noticeVO = BeanUtil.copyProperties(mNotice, NoticeVO.class); //查询公告封面图 if (StrUtil.isNotBlank(mNotice.getNoticePicFileId())) { List noticePicFileIdList = TextUtil.splitAndListStrToListLong(mNotice.getNoticePicFileId()); List mFiles = fileMapper.selectFileByFileIds(noticePicFileIdList); List fileVOList = BeanUtil.copyToList(mFiles, FileVO.class); noticeVO.setNoticePicFile(fileVOList); } return noticeVO; } /** * 查询公告列表(分页) -> 首页使用 * @return 公告分页数据 */ @Override public PageResp getPageHomeNoticeList(PageReq pageReq) { //分页查询 Page mNoticePage = noticeMapper.selectHomePageNoticeList(pageReq); //数据转换 List noticeVOS = BeanUtil.copyToList(mNoticePage.getRecords(), NoticeVO.class); //将内容清空,因为列表不需要展示内容 noticeVOS.forEach(n -> n.setNoticeContent(null)); return new PageResp<>(noticeVOS, mNoticePage.getTotalRow()); } /** * 公告文件的处理 * @param newNotice 公告信息 * @return 封面图文件ID */ private String saveNoticeFileHandler(NoticeVO newNotice) { //处理富文本中的图片 - 从富文本内容中提取文件名 Set fileUrls = TextUtil.extractFileUrl(newNotice.getNoticeContent()); for (String fileUrl : fileUrls) { MFile newFile = fileService.moveFile(fileUrl, FileEnum.FileSource.NOTICE_CONTENT_IMG.getCode()); if (ObjectUtil.isNull(newFile)) { continue; } //将新的url替换富文本内容中的旧url String replace = StrUtil.replace(newNotice.getNoticeContent(), fileUrl, newFile.getFileUrl()); newNotice.setNoticeContent(replace); } //处理公告封面图片-图片文件ID,逗号分隔 String fileIds = fileService.moveFile(newNotice.getNoticePicFile(), FileEnum.FileSource.NOTICE_COVER_IMG.getCode()); newNotice.setNoticePicFileId(fileIds); return fileIds; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/PermServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import com.minimalist.basic.entity.enums.PermEnum; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.entity.po.*; import com.minimalist.basic.entity.vo.perm.PermQueryVO; import com.minimalist.basic.entity.vo.perm.PermVO; import com.minimalist.basic.mapper.*; import com.minimalist.basic.service.PermService; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.utils.CommonConstant; import com.minimalist.basic.utils.TenantUtil; import com.minimalist.basic.utils.UnqIdUtil; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Comparator; import java.util.List; @Service public class PermServiceImpl implements PermService { @Autowired private MPermsMapper permsMapper; @Autowired private MRolePermMapper rolePermMapper; @Autowired private MTenantMapper tenantMapper; @Autowired private MTenantPackagePermMapper tenantPackagePermMapper; /** * 根据角色ID获取权限 * @param roleIds 角色ID集合 * @return 权限平铺数据 */ @Override public List getPermsByRoleId(List roleIds) { //查询角色与权限关联关系 List rolePermRelation = rolePermMapper.selectRolePermByRoleIds(roleIds); if (CollectionUtil.isEmpty(rolePermRelation)) { return CollectionUtil.list(false); } //权限ids List permsIds = rolePermRelation.stream().map(MRolePerm::getPermId).distinct().toList(); //返回权限平铺数据 return permsMapper.selectPermsByPermsIds(permsIds); } /** * 转换权限树 * @param permsList 权限数据集合 * @return 权限数据集合 */ public List permsToTree(List permsList) { if (CollectionUtil.isEmpty(permsList)) { return CollectionUtil.list(false); } //查找顶级节点 List rootNodeList = permsList.stream() .filter(p -> ObjectUtil.isNotNull(p.getParentPermId())) .filter(p -> CommonConstant.ZERO == p.getParentPermId()) .map(p -> BeanUtil.copyProperties(p, PermVO.class)) .sorted(Comparator.comparing(PermVO::getPermSort)) .toList(); //查找子节点 findChildren(permsList, rootNodeList); return rootNodeList; } /** * 添加权限 * @param permVO 权限数据 */ @Override public void addPerm(PermVO permVO) { MPerms mPerms = BeanUtil.copyProperties(permVO, MPerms.class); mPerms.setPermId(UnqIdUtil.uniqueId()); permsMapper.insert(mPerms, true); } /** * 删除权限 -> 根据权限ID删除 * @param permId 权限ID */ @Override public void deletePermByPermId(Long permId) { //检查是否包含下级,包含下级不允许删除 long childrenCount = permsMapper.selectChildrenCountByPermId(permId); Assert.isFalse(childrenCount > 0, () -> new BusinessException(PermEnum.ErrorMsg.CONTAIN_CHILDREN.getDesc())); permsMapper.deletePermsByPermId(permId); } /** * 根据权限ID修改权限 * @param permVO 权限数据 */ @Override public void updatePermByPermId(PermVO permVO) { MPerms newPerms = BeanUtil.copyProperties(permVO, MPerms.class); permsMapper.updatePermsByPermId(newPerms); } /** * 查询权限列表(全部不分页) * @param queryVO 查询参数 * @return 权限树 */ @Override public List getPermList(PermQueryVO queryVO) { return permsToTree(permsMapper.selectPermList(queryVO)); } /** * 查询系统租户权限列表(只查询启用的权限) * @return 权限树 */ @Override public List getEnablePermList() { QueryWrapper queryWrapper = QueryWrapper.create().eq(MPerms::getStatus, StatusEnum.STATUS_1.getCode()); List enablePermList = permsMapper.selectListByQuery(queryWrapper); return permsToTree(enablePermList); } /** * 查询租户权限列表 -> (只获取正常状态的权限) * @return 权限树 */ @Override public List getTenantEnablePermList() { //获取要操作的租户ID long tenantId = TenantUtil.getTenantId(); //如果是系统租户,查询全部 if (CommonConstant.ZERO == tenantId) { return getEnablePermList(); } //查询租户及套餐权限 MTenant tenant = tenantMapper.selectTenantByTenantId(tenantId); List tenantPackagePerms = tenantPackagePermMapper.selectTenantPackagePermByTenantPackageId(tenant.getPackageId()); List permIds = tenantPackagePerms.stream().map(MTenantPackagePerm::getPermId).toList(); List enablePermList = permsMapper.selectPermsByPermsIds(permIds); return permsToTree(enablePermList); } /** * 根据权限ID查询权限 * @param permId 权限ID * @return 权限数据 */ @Override public PermVO getPermByPermId(Long permId) { return BeanUtil.copyProperties(permsMapper.selectPermsByPermId(permId), PermVO.class); } /** * 查找子节点 * @param permsList 权限数据集合 * @param rootNodeList 权限顶级节点数据集合 */ private void findChildren(List permsList, List rootNodeList) { //遍历顶级节点 rootNodeList.forEach(node -> { //存储子节点 List childrenNodes = CollectionUtil.list(false); //从权限数据集合中查找子节点 permsList.forEach(p -> { //节点是否关联 if (node.getPermId().equals(p.getParentPermId())) { childrenNodes.add(BeanUtil.copyProperties(p, PermVO.class)); } //显示排序 childrenNodes.sort(Comparator.comparing(PermVO::getPermSort)); }); //如果有关联的子节点 if (CollectionUtil.isNotEmpty(childrenNodes)) { //将查询到的子节点挂在顶级节点上 node.setChildren(childrenNodes); //对子节点继续递归,查找子节点的下级 findChildren(permsList, childrenNodes); } }); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/PostServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import com.minimalist.basic.entity.enums.PostEnum; import com.minimalist.basic.entity.po.MPost; import com.minimalist.basic.entity.po.MUserPost; import com.minimalist.basic.entity.vo.post.PostQueryVO; import com.minimalist.basic.entity.vo.post.PostVO; import com.minimalist.basic.mapper.MPostMapper; import com.minimalist.basic.mapper.MUserPostMapper; import com.minimalist.basic.service.PostService; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.utils.UnqIdUtil; import com.mybatisflex.core.logicdelete.LogicDeleteManager; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class PostServiceImpl implements PostService { @Autowired private MPostMapper postMapper; @Autowired private MUserPostMapper userPostMapper; /** * 添加岗位 * @param postVO 岗位数据 */ @Override public void addPost(PostVO postVO) { MPost mPost = postMapper.selectPostByPostCode(postVO.getPostCode()); Assert.isNull(mPost, () -> new BusinessException(PostEnum.ErrorMsg.EXISTS_POST.getDesc())); long postId = UnqIdUtil.uniqueId(); mPost = BeanUtil.copyProperties(postVO, MPost.class); mPost.setPostId(postId); postMapper.insert(mPost, true); } /** * 删除岗位 -> 根据岗位ID删除 * @param postId 岗位ID */ @Override public void deletePostByPostId(Long postId) { //删除岗位 postMapper.deletePostByPostId(postId); //删除岗位与用户关联关系 LogicDeleteManager.execWithoutLogicDelete(()-> userPostMapper.deleteByQuery(QueryWrapper.create().eq(MUserPost::getPostId, postId)) ); } /** * 修改岗位 -> 根据岗位ID修改 * @param postVO 岗位数据 */ @Override public void updatePostByPostId(PostVO postVO) { MPost newPost = BeanUtil.copyProperties(postVO, MPost.class); postMapper.updatePostByPostId(newPost); } /** * 查询岗位列表(分页) * @param queryVO 查询参数 * @return 岗位列表 */ @Override public PageResp getPagePostList(PostQueryVO queryVO) { Page postVOPage = postMapper.selectPagePostList(queryVO); return new PageResp<>(postVOPage.getRecords(), postVOPage.getTotalRow()); } /** * 根据岗位ID查询岗位 * @param postId 岗位ID * @return 岗位数据 */ @Override public PostVO getPostByPostId(Long postId) { return BeanUtil.copyProperties(postMapper.selectPostByPostId(postId), PostVO.class); } /** * 根据用户ID查询用户岗位 * @param userId 用户ID * @return 岗位列表 */ @Override public List getPostByUserId(Long userId) { //查询用户与岗位关联数据 List userPostList = userPostMapper.selectUserPostRelation(userId); if (CollectionUtil.isEmpty(userPostList)) { return CollectionUtil.list(false); } List postIds = userPostList.stream().map(MUserPost::getPostId).toList(); return postMapper.selectPostByPostIds(postIds); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/RoleServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import com.minimalist.basic.entity.enums.RoleEnum; import com.minimalist.basic.entity.po.MRole; import com.minimalist.basic.entity.po.MRolePerm; import com.minimalist.basic.entity.po.MUserRole; import com.minimalist.basic.entity.vo.role.RoleQueryVO; import com.minimalist.basic.entity.vo.role.RoleVO; import com.minimalist.basic.mapper.MRoleMapper; import com.minimalist.basic.mapper.MRolePermMapper; import com.minimalist.basic.mapper.MUserRoleMapper; import com.minimalist.basic.service.RoleService; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.utils.UnqIdUtil; import com.mybatisflex.core.logicdelete.LogicDeleteManager; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @Service public class RoleServiceImpl implements RoleService { @Autowired private MRoleMapper roleMapper; @Autowired private MUserRoleMapper userRoleMapper; @Autowired private MRolePermMapper rolePermMapper; /** * 根据用户ID查询角色 * @param userId 用户ID * @return 角色集合 */ @Override public List getRolesByUserId(Long userId) { //查询用户与角色关联关系 List userRoleRelation = userRoleMapper.selectUserRoleRelation(userId); if (CollectionUtil.isEmpty(userRoleRelation)) { return CollectionUtil.list(false); } List roleIds = userRoleRelation.stream().map(MUserRole::getRoleId).distinct().toList(); return roleMapper.selectRoleByRoleIds(roleIds); } /** * 添加角色 * @param roleVO 角色数据 */ @Override @Transactional(rollbackFor = Exception.class) public void addRole(RoleVO roleVO) { //根据编码查询,检查是否重复添加 MRole mRole = roleMapper.selectRoleByRoleCode(roleVO.getRoleCode()); Assert.isNull(mRole, () -> new BusinessException(RoleEnum.ErrorMsg.EXISTS_ROLE.getDesc())); //角色ID long roleId = UnqIdUtil.uniqueId(); mRole = BeanUtil.copyProperties(roleVO, MRole.class); mRole.setRoleId(roleId); roleMapper.insert(mRole, true); //插入角色和权限关联数据 List mRolePerms = permIdToRolePerm(roleVO.getPermissionsIds(), roleId); rolePermMapper.insertBatch(mRolePerms); } /** * 根据角色ID删除角色 * @param roleId 角色ID */ @Override public void deleteRoleByRoleId(Long roleId) { //删除角色 roleMapper.deleteRoleByRoleId(roleId); //删除角色与权限关联数据 LogicDeleteManager.execWithoutLogicDelete(()-> rolePermMapper.deleteByQuery(QueryWrapper.create().eq(MRolePerm::getRoleId, roleId)) ); //删除角色与用户关联数据 LogicDeleteManager.execWithoutLogicDelete(()-> userRoleMapper.deleteByQuery(QueryWrapper.create().eq(MUserRole::getRoleId, roleId)) ); } /** * 根据角色ID修改角色 * @param roleVO 角色数据 */ @Override @Transactional(rollbackFor = Exception.class) public void updateRoleByRoleId(RoleVO roleVO) { MRole newRole = BeanUtil.copyProperties(roleVO, MRole.class); roleMapper.updateRoleByRoleId(newRole); //删除原角色与权限关联信息 LogicDeleteManager.execWithoutLogicDelete(()-> rolePermMapper.deleteByQuery(QueryWrapper.create().eq(MRolePerm::getRoleId, roleVO.getRoleId())) ); //添加新角色与权限关联信息 List mRolePerms = permIdToRolePerm(roleVO.getPermissionsIds(), roleVO.getRoleId()); rolePermMapper.insertBatch(mRolePerms); } /** * 查询角色(分页) -> 角色管理使用 * @param queryVO 查询条件 * @return 角色分页数据 */ @Override public PageResp getPageRoleList(RoleQueryVO queryVO) { Page roleVOPage = roleMapper.selectPageRoleList(queryVO); return new PageResp<>(roleVOPage.getRecords(), roleVOPage.getTotalRow()); } /** * 根据角色ID查询角色 * @param roleId 角色ID * @return 角色信息 */ @Override public RoleVO getRoleByRoleId(Long roleId) { MRole mRole = roleMapper.selectRoleByRoleId(roleId); RoleVO roleVO = BeanUtil.copyProperties(mRole, RoleVO.class); //根据角色查询权限,回显数据 List rolePerms = rolePermMapper.selectRolePermByRoleId(roleId); List permIds = rolePerms.stream().map(rp -> rp.getPermId().toString()).toList(); roleVO.setCheckedPermIds(permIds); return roleVO; } /** * 根据租户ID查询角色列表 * @param tenantId 租户ID * @return 角色列表 */ @Override public List getRoleByTenantId(Long tenantId) { return roleMapper.selectListByQuery(QueryWrapper.create().eq(MRole::getTenantId, tenantId)); } /** * 权限ID集合转换角色权限关联数据 * @param permIds 权限ID集合 * @param roleId 角色ID * @return 角色与权限关联数据 */ private List permIdToRolePerm(List permIds, long roleId) { return permIds.stream().map(p -> { MRolePerm rolePerm = new MRolePerm(); rolePerm.setRoleId(roleId); rolePerm.setPermId(p); return rolePerm; }).collect(Collectors.toList()); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/StorageServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.hutool.core.bean.BeanUtil; import com.minimalist.basic.config.fileHandler.FileManager; import com.minimalist.basic.config.fileHandler.handler.FileHandler; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.entity.po.MStorage; import com.minimalist.basic.entity.vo.storage.StorageQueryVO; import com.minimalist.basic.entity.vo.storage.StorageVO; import com.minimalist.basic.mapper.MStorageMapper; import com.minimalist.basic.service.StorageService; import com.minimalist.basic.utils.UnqIdUtil; import com.mybatisflex.core.paginate.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class StorageServiceImpl implements StorageService { @Autowired private MStorageMapper storageMapper; @Autowired private FileManager fileManager; /** * 添加存储 * @param storageVO 存储信息 */ @Override @Transactional(rollbackFor = Exception.class) public void addStorage(StorageVO storageVO) { //校验存储配置 FileHandler fileHandler = fileManager.getFileHandler(storageVO.getStorageType()); String storageConfig = fileHandler.valid(storageVO.getStorageConfig()); MStorage storage = BeanUtil.copyProperties(storageVO, MStorage.class); long storageId = UnqIdUtil.uniqueId(); storage.setStorageId(storageId); storage.setStorageConfig(storageConfig); storageMapper.insert(storage, true); } /** * 删除存储 -> 根据存储ID删除 * @param storageId 存储ID */ @Override public void deleteStorageByStorageId(Long storageId) { storageMapper.deleteStorageByStorageId(storageId); } /** * 修改存储 -> 根据存储ID修改 * @param storageVO 存储信息 */ @Override public void updateStorageByStorageId(StorageVO storageVO) { //校验存储配置 FileHandler fileHandler = fileManager.getFileHandler(storageVO.getStorageType()); String storageConfig = fileHandler.valid(storageVO.getStorageConfig()); MStorage storage = BeanUtil.copyProperties(storageVO, MStorage.class); storage.setStorageConfig(storageConfig); storageMapper.updateStorageByStorageId(storage); } /** * 查询存储列表(分页) * @param queryVO 查询条件 * @return 存储列表 */ @Override public PageResp getPageStorageList(StorageQueryVO queryVO) { Page storageVOPage = storageMapper.selectPageStorageList(queryVO); return new PageResp<>(storageVOPage.getRecords(), storageVOPage.getTotalRow()); } /** * 根据存储ID查询存储信息 * @param storageId 存储ID * @return 存储信息 */ @Override public StorageVO getStorageByStorageId(Long storageId) { return BeanUtil.copyProperties(storageMapper.selectStorageByStorageId(storageId), StorageVO.class); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/TenantPackageServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import com.minimalist.basic.entity.enums.TenantEnum; import com.minimalist.basic.entity.po.*; import com.minimalist.basic.entity.vo.tenant.TenantPackageQueryVO; import com.minimalist.basic.entity.vo.tenant.TenantPackageVO; import com.minimalist.basic.manager.TenantManager; import com.minimalist.basic.mapper.*; import com.minimalist.basic.service.RoleService; import com.minimalist.basic.service.TenantPackageService; import com.minimalist.basic.entity.enums.StatusEnum; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.utils.CommonConstant; import com.minimalist.basic.utils.UnqIdUtil; import com.mybatisflex.core.logicdelete.LogicDeleteManager; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.stream.Collectors; @Service public class TenantPackageServiceImpl implements TenantPackageService { @Autowired private MTenantPackageMapper tenantPackageMapper; @Autowired private MTenantPackagePermMapper tenantPackagePermMapper; @Autowired private MTenantMapper tenantMapper; @Autowired private MPermsMapper permsMapper; @Autowired private RoleService roleService; @Autowired private TenantManager tenantManager; /** * 添加租户套餐 * @param tenantPackageVO 租户套餐信息 */ @Override @Transactional(rollbackFor = Exception.class) public void addTenantPackage(TenantPackageVO tenantPackageVO) { MTenantPackage mTenantPackage = BeanUtil.copyProperties(tenantPackageVO, MTenantPackage.class); long tenantPackageId = UnqIdUtil.uniqueId(); mTenantPackage.setPackageId(tenantPackageId); tenantPackageMapper.insert(mTenantPackage, true); //插入套餐与权限的关联数据 List mTenantPackagePerms = buildTenantPackagePerm(tenantPackageVO.getPermissionsIds(), tenantPackageId); tenantPackagePermMapper.insertBatch(mTenantPackagePerms); } /** * 删除租户套餐 -> 根据租户套餐ID删除租户套餐 * @param tenantPackageId 租户套餐ID */ @Override public void deleteTenantPackageByTenantPackageId(Long tenantPackageId) { //检查租户套餐是否被使用,被使用则不能删除 long tenantCount = tenantMapper.selectTenantCountByTenantPackageId(tenantPackageId); Assert.isTrue(tenantCount <= 0, () -> new BusinessException(TenantEnum.ErrorMsg.USE_TENANT_PACKAGE.getDesc())); //删除租户套餐 tenantPackageMapper.deleteTenantPackageByTenantPackageId(tenantPackageId); //删除套餐与权限关联数据 tenantPackagePermMapper.deleteByQuery(QueryWrapper.create().eq(MTenantPackagePerm::getPackageId, tenantPackageId)); } /** * 修改租户套餐 -> 根据租户套餐ID修改 * @param tenantPackageVO 租户套餐信息 */ @Override @Transactional(rollbackFor = Exception.class) public void updateTenantPackageByTenantPackageId(TenantPackageVO tenantPackageVO) { //修改租户套餐数据 MTenantPackage newTenantPackage = BeanUtil.copyProperties(tenantPackageVO, MTenantPackage.class); tenantPackageMapper.updateTenantPackageByTenantPackageId(newTenantPackage); //查询租户套餐的权限 - 修改前的权限 List oldPerms = tenantPackagePermMapper.selectTenantPackagePermByTenantPackageId(tenantPackageVO.getPackageId()); String op = oldPerms.stream().map(p -> p.getPermId().toString()).collect(Collectors.joining(",")); //修改后的套餐权限 String np = tenantPackageVO.getPermissionsIds().stream().map(Object::toString).collect(Collectors.joining(",")); //如果套餐的旧权限和修改后的新权限不一致,需要修改所有使用改套餐租户的权限 if (!op.equals(np)) { //套餐的权限修改 //1. 删除原套餐与权限关联数据 LogicDeleteManager.execWithoutLogicDelete(()-> tenantPackagePermMapper.deleteByQuery(QueryWrapper.create().eq(MTenantPackagePerm::getPackageId, newTenantPackage.getPackageId())) ); //2. 插入新套餐与权限关联数据 List mTenantPackagePerms = buildTenantPackagePerm(tenantPackageVO.getPermissionsIds(), newTenantPackage.getPackageId()); tenantPackagePermMapper.insertBatch(mTenantPackagePerms); //根据套餐查租户 List tenants = tenantMapper.selectTenantByTenantPackageId(tenantPackageVO.getPackageId()); for (MTenant tenant : tenants) { //查询租户下所有角色 List roleList = roleService.getRoleByTenantId(tenant.getTenantId()); //修改租户权限 tenantManager.updateTenantPermission(roleList, tenantPackageVO.getPackageId()); } } } /** * 查询租户套餐(分页) * @param queryVO 查询条件 * @return 租户套餐分页数据 */ @Override public PageResp getPageTenantPackageList(TenantPackageQueryVO queryVO) { Page tenantPackageVOPage = tenantPackageMapper.selectPageTenantPackageList(queryVO); return new PageResp<>(tenantPackageVOPage.getRecords(), tenantPackageVOPage.getTotalRow()); } /** * 根据租户套餐ID查询租户套餐 * @param tenantPackageId 租户套餐ID * @return 租户套餐数据 */ @Override public TenantPackageVO getTenantPackageByTenantPackageId(Long tenantPackageId) { //根据租户ID查询租户套餐 MTenantPackage mTenantPackage = tenantPackageMapper.selectTenantPackageByTenantPackageId(tenantPackageId); TenantPackageVO tenantPackageVO = BeanUtil.copyProperties(mTenantPackage, TenantPackageVO.class); //套餐选中权限回显 List tenantPackagePerms = tenantPackagePermMapper.selectTenantPackagePermByTenantPackageId(tenantPackageId); List permIds = tenantPackagePerms.stream().map(p -> p.getPermId().toString()).toList(); tenantPackageVO.setCheckedPermIds(permIds); return tenantPackageVO; } /** * 构建租户套餐与权限关联数据 * @param permissionsIds 权限ID集合 * @param tenantPackageId 租户ID * @return 租户套餐与权限关联数据 */ private List buildTenantPackagePerm(List permissionsIds, Long tenantPackageId) { return permissionsIds.stream().map(permId -> { MTenantPackagePerm tpp = new MTenantPackagePerm(); tpp.setPackageId(tenantPackageId); tpp.setPermId(permId); return tpp; }).toList(); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/TenantServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.json.JSONUtil; import com.minimalist.basic.config.redis.RedisManager; import com.minimalist.basic.entity.enums.RoleEnum; import com.minimalist.basic.entity.enums.TenantEnum; import com.minimalist.basic.entity.po.*; import com.minimalist.basic.entity.vo.tenant.TenantDatasourceVO; import com.minimalist.basic.entity.vo.tenant.TenantQueryVO; import com.minimalist.basic.entity.vo.tenant.TenantVO; import com.minimalist.basic.entity.vo.user.UserVO; import com.minimalist.basic.manager.TenantManager; import com.minimalist.basic.manager.UserManager; import com.minimalist.basic.mapper.*; import com.minimalist.basic.service.RoleService; import com.minimalist.basic.service.TenantService; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.utils.CommonConstant; import com.minimalist.basic.utils.RedisKeyConstant; import com.minimalist.basic.utils.UnqIdUtil; import com.mybatisflex.core.paginate.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @Service public class TenantServiceImpl implements TenantService { @Autowired private MTenantMapper tenantMapper; @Autowired private MTenantDatasourceMapper tenantDatasourceMapper; @Autowired private MUserMapper userMapper; @Autowired private MRoleMapper roleMapper; @Autowired private RoleService roleService; @Autowired private MTenantPackagePermMapper tenantPackagePermMapper; @Autowired private UserManager userManager; @Autowired private MUserRoleMapper userRoleMapper; @Autowired private TenantManager tenantManager; @Autowired private MRolePermMapper rolePermMapper; @Autowired private RedisManager redisManager; /** * 添加租户 * @param tenantVO 租户信息 */ @Override @Transactional(rollbackFor = Exception.class) public void addTenant(TenantVO tenantVO) { //根据租户名查询租户,租户名不能重复 checkTenantNameExists(tenantVO.getTenantName()); MTenant mTenant = BeanUtil.copyProperties(tenantVO, MTenant.class); long tenantId = UnqIdUtil.uniqueId(); //为租户创建用户 UserVO userInfo = tenantVO.getUser(); checkAddTenantUser(userInfo); long userId = UnqIdUtil.uniqueId(); userInfo.setUserId(userId); addTenantUser(userInfo, tenantId); //为租户创建角色 long roleId = UnqIdUtil.uniqueId(); addTenantRole(roleId, tenantId, tenantVO.getPackageId()); //用户与角色关联关系 addTenantUserRole(userId, roleId); //隔离方式为数据库隔离,则插入租户数据源数据 if (TenantEnum.DataIsolation.DB.getCode().equals(tenantVO.getDataIsolation())) { TenantDatasourceVO tenantDatasourceVO = tenantVO.getTenantDatasource(); //数据源名称 mTenant.setDatasource(tenantDatasourceVO.getDatasourceName()); //插入多租户数据源 MTenantDatasource tenantDatasource = new MTenantDatasource(); tenantDatasource.setTenantId(tenantId); tenantDatasource.setDatasourceId(UnqIdUtil.uniqueId()); tenantDatasource.setDatasourceName(tenantDatasourceVO.getDatasourceName()); tenantDatasource.setDatasourceUrl(tenantDatasourceVO.getDatasourceUrl()); tenantDatasource.setUsername(tenantDatasourceVO.getUsername()); tenantDatasource.setPassword(tenantDatasourceVO.getPassword()); tenantDatasourceMapper.insert(tenantDatasource, true); } else { //字段隔离 mTenant.setDatasource(TenantEnum.MASTER); mTenant.setDataIsolation(TenantEnum.DataIsolation.COLUMN.getCode()); } //插入租户数据 mTenant.setUserId(userId); mTenant.setTenantId(tenantId); tenantMapper.insert(mTenant, true); //发布消息 - 缓存租户信息 redisManager.publishMessage(RedisKeyConstant.TENANT_DATA_TOPIC_KEY + "." + CommonConstant.ADD, JSONUtil.toJsonStr(tenantVO)); } /** * 删除租户 -> 根据租户ID删除 * @param tenantId 租户ID */ @Override @Transactional(rollbackFor = Exception.class) public void deleteTenantByTenantId(Long tenantId) { //删除租户数据源信息 tenantDatasourceMapper.deleteTenantDatasourceByTenantId(tenantId); //发布消息 - 删除缓存中的租户信息 redisManager.publishMessage(RedisKeyConstant.TENANT_DATA_TOPIC_KEY + "." + CommonConstant.DELETE, String.valueOf(tenantId)); //删除租户数据 tenantMapper.deleteTenantByTenantId(tenantId); } /** * 修改租户 -> 根据租户ID修改 * @param tenantVO 租户信息 */ @Override @Transactional(rollbackFor = Exception.class) public void updateTenantByTenantId(TenantVO tenantVO) { //根据租户ID查询租户 MTenant tenant = tenantMapper.selectTenantByTenantId(tenantVO.getTenantId()); Assert.notNull(tenant, () -> new BusinessException(TenantEnum.ErrorMsg.NONENTITY_TENANT.getDesc())); MTenant newTenant = BeanUtil.copyProperties(tenantVO, MTenant.class); //删除租户数据源信息 tenantDatasourceMapper.deleteTenantDatasourceByTenantId(tenant.getTenantId()); //检查租户数据源是否需要更新 if (TenantEnum.DataIsolation.DB.getCode().equals(tenantVO.getDataIsolation())) { //数据库隔离 TenantDatasourceVO tenantDatasourceVO = tenantVO.getTenantDatasource(); //数据源名称 newTenant.setDatasource(tenantDatasourceVO.getDatasourceName()); //插入多租户数据源 MTenantDatasource tenantDatasource = new MTenantDatasource(); tenantDatasource.setTenantId(tenant.getTenantId()); tenantDatasource.setDatasourceId(UnqIdUtil.uniqueId()); tenantDatasource.setDatasourceName(tenantDatasourceVO.getDatasourceName()); tenantDatasource.setDatasourceUrl(tenantDatasourceVO.getDatasourceUrl()); tenantDatasource.setUsername(tenantDatasourceVO.getUsername()); tenantDatasource.setPassword(tenantDatasourceVO.getPassword()); tenantDatasourceMapper.insert(tenantDatasource, true); } else { //字段隔离 newTenant.setDatasource(TenantEnum.MASTER); newTenant.setDataIsolation(TenantEnum.DataIsolation.COLUMN.getCode()); } //更新租户 tenantMapper.updateTenantByTenantId(newTenant); //如果租户套餐变更,则修改租户套餐 if (!tenantVO.getPackageId().equals(tenant.getPackageId())) { //查询租户下所有角色 List roleList = roleService.getRoleByTenantId(tenant.getTenantId()); //修改租户权限 tenantManager.updateTenantPermission(roleList, tenantVO.getPackageId()); } //发布消息 - 缓存租户信息 redisManager.publishMessage(RedisKeyConstant.TENANT_DATA_TOPIC_KEY + "." + CommonConstant.ADD, JSONUtil.toJsonStr(tenantVO)); } /** * 查询租户(分页) * @param queryVO 查询条件 * @return 租户分页数据 */ @Override public PageResp getPageTenantList(TenantQueryVO queryVO) { //查询租户分页数据 Page tenantVOPage = tenantMapper.selectPageTenantList(queryVO); //查询租户绑定的用户信息 if (CollectionUtil.isNotEmpty(tenantVOPage.getRecords())) { List userIdList = tenantVOPage.getRecords().stream().map(TenantVO::getUserId).toList(); List mUserList = userMapper.selectUserByUserIds(userIdList); Map userMap = mUserList.stream() .collect(Collectors.toMap(MUser::getUserId, Function.identity(), (v1, v2) -> v1)); tenantVOPage.getRecords().forEach(t -> { MUser user = userMap.get(t.getUserId()); if (ObjectUtil.isNotNull(user)) { t.setContactName(user.getUserRealName()); t.setPhone(user.getPhone()); t.setEmail(user.getEmail()); } }); } return new PageResp<>(tenantVOPage.getRecords(), tenantVOPage.getTotalRow()); } /** * 根据租户ID查询租户 * @param tenantId 租户ID * @return 租户数据 */ @Override public TenantVO getTenantByTenantId(Long tenantId) { MTenant mTenant = tenantMapper.selectTenantByTenantId(tenantId); MUser mUser = userMapper.selectUserByUserId(mTenant.getUserId()); TenantVO tenantVO = BeanUtil.copyProperties(mTenant, TenantVO.class); tenantVO.setContactName(mUser.getUserRealName()); tenantVO.setPhone(mUser.getPhone()); tenantVO.setEmail(mUser.getEmail()); //查询数据源信息 if (TenantEnum.DataIsolation.DB.getCode().equals(tenantVO.getDataIsolation())) { MTenantDatasource tenantDatasource = tenantDatasourceMapper.selectTenantDatasourceByTenantId(tenantId); tenantVO.setTenantDatasource(BeanUtil.copyProperties(tenantDatasource, TenantDatasourceVO.class)); } return tenantVO; } /** * 校验租户名是否存在,存在则抛出异常 * @param tenantName 租户名 */ private void checkTenantNameExists(String tenantName) { MTenant tenant = tenantMapper.selectTenantByTenantName(tenantName); Assert.isNull(tenant, () -> new BusinessException(TenantEnum.ErrorMsg.EXISTS_TENANT.getDesc())); } /** * 校验租户的用户信息 * @param user 用户信息 */ private void checkAddTenantUser(UserVO user) { Assert.notNull(user, () -> new BusinessException(TenantEnum.ErrorMsg.ADD_TENANT_USER_NULL.getDesc())); Assert.notBlank(user.getUsername(), () -> new BusinessException(TenantEnum.ErrorMsg.ADD_TENANT_USERNAME_NULL.getDesc())); Assert.notBlank(user.getPassword(), () -> new BusinessException(TenantEnum.ErrorMsg.ADD_TENANT_PASSWORD_NULL.getDesc())); Assert.notBlank(user.getNickname(), () -> new BusinessException(TenantEnum.ErrorMsg.ADD_TENANT_NICKNAME_NULL.getDesc())); Assert.notBlank(user.getUserRealName(), () -> new BusinessException(TenantEnum.ErrorMsg.ADD_TENANT_REALNAME_NULL.getDesc())); Assert.notBlank(user.getPhone(), () -> new BusinessException(TenantEnum.ErrorMsg.ADD_TENANT_PHONE_NULL.getDesc())); Assert.notNull(user.getUserSex(), () -> new BusinessException(TenantEnum.ErrorMsg.ADD_TENANT_USERSEX_NULL.getDesc())); } private void addTenantRole(Long roleId, Long tenantId, Long tenantPackageId) { MRole role = new MRole(); role.setRoleId(roleId); role.setRoleName(RoleEnum.Role.ADMIN.getName()); role.setRoleCode(RoleEnum.Role.ADMIN.getCode()); role.setRoleSort(CommonConstant.ZERO); role.setRemark("系统自动创建角色"); role.setTenantId(tenantId); //插入角色 roleMapper.insert(role, true); //插入角色和权限关联数据 List mTenantPackagePerms = tenantPackagePermMapper.selectTenantPackagePermByTenantPackageId(tenantPackageId); List rolePerms = mTenantPackagePerms.stream().map(tpp -> { MRolePerm rolePerm = new MRolePerm(); rolePerm.setRoleId(roleId); rolePerm.setPermId(tpp.getPermId()); return rolePerm; }).toList(); rolePermMapper.insertBatch(rolePerms); } private void addTenantUser(UserVO userInfo, Long tenantId) { MUser user = new MUser(); user.setUserId(userInfo.getUserId()); user.setUsername(userInfo.getUsername()); user.setNickname(userInfo.getNickname()); user.setUserRealName(userInfo.getUserRealName()); user.setEmail(userInfo.getEmail()); user.setPhone(userInfo.getPhone()); user.setUserSex(userInfo.getUserSex()); //生成盐值,密码加密 String salt = RandomUtil.randomString(6); user.setSalt(salt); user.setPassword(userManager.passwordEncrypt(userInfo.getPassword(), salt)); user.setTenantId(tenantId); userMapper.insert(user, true); } private void addTenantUserRole(Long userId, Long roleId) { MUserRole userRole = new MUserRole(); userRole.setUserId(userId); userRole.setRoleId(roleId); userRoleMapper.insert(userRole, true); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/service/impl/UserServiceImpl.java ================================================ package com.minimalist.basic.service.impl; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.captcha.CircleCaptcha; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.codec.Base64; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import com.minimalist.basic.entity.enums.*; import com.minimalist.basic.entity.po.MPerms; import com.minimalist.basic.entity.po.MUser; import com.minimalist.basic.entity.po.MUserDept; import com.minimalist.basic.entity.po.MUserPost; import com.minimalist.basic.entity.po.MUserRole; import com.minimalist.basic.entity.vo.config.ConfigVO; import com.minimalist.basic.entity.vo.role.RoleVO; import com.minimalist.basic.entity.vo.tenant.TenantVO; import com.minimalist.basic.entity.vo.user.ImageCaptchaVO; import com.minimalist.basic.entity.vo.user.RePasswordVO; import com.minimalist.basic.entity.vo.user.UserInfoVO; import com.minimalist.basic.entity.vo.user.UserLoginReqVO; import com.minimalist.basic.entity.vo.user.UserQueryVO; import com.minimalist.basic.entity.vo.user.UserSettingVO; import com.minimalist.basic.entity.vo.user.UserVO; import com.minimalist.basic.manager.TenantManager; import com.minimalist.basic.manager.UserManager; import com.minimalist.basic.mapper.MUserDeptMapper; import com.minimalist.basic.mapper.MUserMapper; import com.minimalist.basic.mapper.MUserPostMapper; import com.minimalist.basic.mapper.MUserRoleMapper; import com.minimalist.basic.service.*; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.mybatis.bo.PageResp; import com.minimalist.basic.config.redis.RedisManager; import com.minimalist.basic.config.tenant.TenantIgnore; import com.minimalist.basic.utils.*; import com.mybatisflex.core.paginate.Page; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @Slf4j @Service public class UserServiceImpl implements UserService { @Autowired private MUserMapper userMapper; @Autowired private RoleService roleService; @Autowired private MUserRoleMapper userRoleMapper; @Autowired private MUserDeptMapper userDeptMapper; @Autowired private PermService permService; @Autowired private RedisManager redisManager; @Autowired private MUserPostMapper userPostMapper; @Autowired private PostService postService; @Autowired private DeptService deptService; @Autowired private UserManager userManager; @Autowired private TenantService tenantService; @Autowired private TenantManager tenantManager; @Autowired private ConfigService configService; /** * 新增用户 * @param userVO 用户实体 */ @Override @Transactional(rollbackFor = Exception.class) public void addUser(UserVO userVO) { //校验用户名唯一 com.mybatisflex.core.tenant.TenantManager.withoutTenantCondition(() -> userManager.checkUsernameUniqueness(userVO.getUsername(), null) ); //校验邮箱唯一 com.mybatisflex.core.tenant.TenantManager.withoutTenantCondition(() -> userManager.checkUserEmailUniqueness(userVO.getEmail(), null) ); //校验租户的套餐是否满足条件 tenantManager.checkTenantPackage(TenantUtil.getTenantId()); //新增用户数据 MUser user = BeanUtil.copyProperties(userVO, MUser.class); long userId = UnqIdUtil.uniqueId(); user.setUserId(userId); //生成盐值,密码加密 String salt = RandomUtil.randomString(6); user.setSalt(salt); if (StrUtil.isNotBlank(userVO.getPassword())) { user.setPassword(userManager.passwordEncrypt(userVO.getPassword(), salt)); } else { //设置默认密码 123456qwerty user.setPassword(userManager.passwordEncrypt("123456qwerty", salt)); } userMapper.insert(user, true); //新增用户关联信息 userManager.insertUserRelation(userVO.getRoleIds(), userVO.getPostIds(), userVO.getDeptIds(), userId); } /** * 删除用户 * @param userId 用户ID */ @Override @Transactional(rollbackFor = Exception.class) public void deleteUserByUserId(Long userId) { //删除用户 userMapper.deleteUserByUserId(userId); //删除用户关联信息 userManager.deleteUserRelation(userId); } /** * 修改用户 * @param userVO 用户数据 */ @Override @Transactional(rollbackFor = Exception.class) public void updateUserByUserId(UserVO userVO) { //校验用户名唯一 com.mybatisflex.core.tenant.TenantManager.withoutTenantCondition(() -> userManager.checkUsernameUniqueness(userVO.getUsername(), userVO.getUserId()) ); //校验邮箱唯一 com.mybatisflex.core.tenant.TenantManager.withoutTenantCondition(() -> userManager.checkUserEmailUniqueness(userVO.getEmail(), userVO.getUserId()) ); //校验该租户套餐是否满足条件 tenantManager.checkTenantPackage(TenantUtil.getTenantId()); //查询用户信息 MUser oldUser = userMapper.selectUserByUserId(userVO.getUserId()); //修改用户信息 MUser newUser = BeanUtil.copyProperties(userVO, MUser.class); //是否需要修改密码 if (StrUtil.isNotBlank(userVO.getPassword())) { //密码加密 newUser.setPassword(userManager.passwordEncrypt(userVO.getPassword(), oldUser.getSalt())); } //修改用户 userMapper.updateUserByUserId(newUser); //删除用户关联信息 userManager.deleteUserRelation(userVO.getUserId()); //新增用户关联信息 userManager.insertUserRelation(userVO.getRoleIds(), userVO.getPostIds(), userVO.getDeptIds(), userVO.getUserId()); } /** * 查询用户(分页) * @param queryVO 查询条件 * @return 用户分页数据 */ @Override public PageResp getPageUserList(UserQueryVO queryVO) { Page userPage = userMapper.selectPageUserList(queryVO); return new PageResp<>(userPage.getRecords(), userPage.getTotalRow()); } /** * 根据用户ID查询用户 * @param userId 用户ID * @return 用户信息 */ @Override public UserVO getUserByUserId(Long userId) { MUser mUser = userMapper.selectUserByUserId(userId); //拷贝数据 UserVO userVO = BeanUtil.copyProperties(mUser, UserVO.class); //查询用户与岗位关联数据 List userPostList = userPostMapper.selectUserPostRelation(userVO.getUserId()); userVO.setPostIds(userPostList.stream().map(MUserPost::getPostId).collect(Collectors.toSet())); //查询用户与角色关联数据 List userRoleList = userRoleMapper.selectUserRoleRelation(userVO.getUserId()); userVO.setRoleIds(userRoleList.stream().map(MUserRole::getRoleId).collect(Collectors.toSet())); //查询用户与部门关联数据 List userDeptList = userDeptMapper.selectUserDeptRelation(userVO.getUserId()); //部门选中回显 List deptIds = userDeptList.stream().map(d -> d.getDeptId().toString()).toList(); userVO.setCheckedDeptIds(deptIds); return userVO; } /** * 获取用户信息 */ @Override public UserInfoVO getUserInfo() { //获取当前登陆人的userId Long userId = StpUtil.getLoginIdAsLong(); //如果多租户开启 && 当前登陆人是系统租户 && 要查询其他租户数据 if (TenantUtil.checkTenantOnOff() && TenantUtil.checkIsSystemTenant() && TenantUtil.checkQueryTenantData()) { //获取当前操作的租户信息,可能涉及租户切换 TenantVO tenantVO = CommonConstant.tenantMap.get(TenantUtil.getTenantId()); if (ObjectUtil.isNull(tenantVO)) { throw new BusinessException("获取租户信息为空,请检查"); } //取当前操作租户的用户ID,切换为该租户的管理员身份 userId = tenantVO.getUserId(); } //查询用户 MUser user = userMapper.selectUserByUserId(userId); if (ObjectUtil.isNull(user)) { return new UserInfoVO(); } UserInfoVO userInfoVO = BeanUtil.copyProperties(user, UserInfoVO.class); //根据用户ID查询角色 List roles = roleService.getRolesByUserId(userId); //角色不为空,根据角色处理权限信息 if (CollectionUtil.isNotEmpty(roles)) { //存放角色标识符 Set roleCodes = CollectionUtil.set(false); //汇总角色ID List roleIds = roles.stream() //状态 = 正常 .filter(r -> StatusEnum.STATUS_1.getCode().equals(r.getStatus())) .map(r -> { //角色标识符 roleCodes.add(r.getRoleCode()); //返回角色ID return r.getRoleId(); }).distinct().toList(); //存放菜单数据 List menuList = CollectionUtil.list(false); //根据角色ID查询权限 - 返回权限平铺数据 List permList = permService.getPermsByRoleId(roleIds); //汇总权限标识符集合 Set permCodes = permList.stream() //状态 = 正常 .filter(p -> StatusEnum.STATUS_1.getCode().equals(p.getStatus())) .map(p -> { //如果是菜单,存储到菜单集合 if (PermEnum.PermType.MENU.getCode().equals(p.getPermType())) { menuList.add(p); } //返回权限编码 return p.getPermCode(); }) .filter(StrUtil::isNotBlank).collect(Collectors.toSet()); //将角色标识符存入用户实体 userInfoVO.setRoles(roleCodes); //将权限标识符存入用户实体 userInfoVO.setPerms(permCodes); //将菜单存入用户实体 userInfoVO.setMenus(permService.permsToTree(menuList)); //将权限数据向redis存储一份 redisManager.set(StrUtil.indexedFormat(RedisKeyConstant.USER_ROLE_CACHE_KEY, userId), roleCodes, RedisKeyConstant.USER_PERM_CACHE_EX); redisManager.set(StrUtil.indexedFormat(RedisKeyConstant.USER_PERM_CACHE_KEY, userId), permCodes, RedisKeyConstant.USER_PERM_CACHE_EX); } //用户岗位 userInfoVO.setPostList(postService.getPostByUserId(userId)); //用户所属部门 List userDeptList = userDeptMapper.selectUserDeptRelation(userId); //部门选中回显 List deptIds = userDeptList.stream().map(MUserDept::getDeptId).toList(); userInfoVO.setDeptList(deptService.getDeptByDeptIds(deptIds)); return userInfoVO; } /** * 获取图形验证码 * @return 图形验证码 */ @Override public ImageCaptchaVO getImageCaptcha() { ConfigVO config = configService.getConfigByConfigKey(CommonConstant.SYSTEM_CONFIG_CAPTCHA_ENABLE); boolean loginCaptchaEnable = Boolean.parseBoolean(config.getConfigValue()); ImageCaptchaVO imageCaptchaVO = new ImageCaptchaVO(); imageCaptchaVO.setEnable(loginCaptchaEnable); if (!loginCaptchaEnable) { return imageCaptchaVO; } //验证码4个随机字符 CircleCaptcha circleCaptcha = new CircleCaptcha(280, 100, 4, 25); //验证码转小写 String captcha = circleCaptcha.getCode().toLowerCase(); //为验证码生成对应的ID,1个验证码对应1个ID String captchaId = IdUtil.objectId().toLowerCase(); //redis验证码的key String key = StrUtil.indexedFormat(RedisKeyConstant.CAPTCHA_CACHE_KEY, captchaId); //存入redis,value是验证码 redisManager.set(key, captcha, RedisKeyConstant.CAPTCHA_CACHE_EX); //构建图形验证码 imageCaptchaVO.setCaptchaId(captchaId); imageCaptchaVO.setCaptchaImg(circleCaptcha.getImageBase64()); return imageCaptchaVO; } /** * 校验图形验证码 * @param captcha 验证码 * @param captchaId 验证码ID * @return true通过校验 false未通过校验 */ @Override public boolean checkImageCaptcha(String captcha, String captchaId) { String key = StrUtil.indexedFormat(RedisKeyConstant.CAPTCHA_CACHE_KEY, captchaId.toLowerCase()); String captchaCache = redisManager.getAndDelete(key); return captcha.toLowerCase().equals(captchaCache); } /** * 用户登录 * @param reqVO 用户登录信息 * @return token */ @Override public SaTokenInfo userLogin(UserLoginReqVO reqVO) { ConfigVO config = configService.getConfigByConfigKey(CommonConstant.SYSTEM_CONFIG_CAPTCHA_ENABLE); boolean loginCaptchaEnable = Boolean.parseBoolean(config.getConfigValue()); //校验验证码是否正确 if (loginCaptchaEnable) { Assert.isTrue(StrUtil.isNotBlank(reqVO.getCaptcha()), () -> new BusinessException(UserEnum.ErrorMsg.CAPTCHA_CONTENT_EMPTY.getDesc())); Assert.isTrue(StrUtil.isNotBlank(reqVO.getCaptchaId()), () -> new BusinessException(UserEnum.ErrorMsg.CAPTCHA_ID_EMPTY.getDesc())); boolean checkImageCaptcha = checkImageCaptcha(reqVO.getCaptcha(), reqVO.getCaptchaId()); Assert.isTrue(checkImageCaptcha, () -> new BusinessException(UserEnum.ErrorMsg.CAPTCHA_INCORRECT.getDesc())); } MUser loginUser = userMapper.selectUserByUsername(reqVO.getUsername()); Assert.notNull(loginUser, () -> new BusinessException(UserEnum.ErrorMsg.NONENTITY_ACCOUNT.getDesc())); //校验密码是否正确 String passwordEncrypt = userManager.passwordEncrypt(reqVO.getPassword(), loginUser.getSalt()); Assert.isTrue(loginUser.getPassword().equals(passwordEncrypt), () -> new BusinessException(UserEnum.ErrorMsg.U_OR_P_INCORRECT.getDesc())); //校验用户状态 Assert.isTrue(StatusEnum.STATUS_1.getCode().equals(loginUser.getStatus()), () -> new BusinessException(UserEnum.ErrorMsg.USER_FROZEN.getDesc())); //根据用户ID查询租户 TenantVO tenantVO = tenantService.getTenantByTenantId(loginUser.getTenantId()); //账户未绑定租户 Assert.notNull(tenantVO, () -> new BusinessException(UserEnum.ErrorMsg.USER_UNBOUND_TENANT.getDesc())); //租户状态 Assert.isTrue(StatusEnum.STATUS_1.getCode().equals(tenantVO.getStatus().intValue()), () -> new BusinessException(TenantEnum.ErrorMsg.DISABLED_TENANT.getDesc())); //检查租户是否过期 tenantManager.checkTenantExpireTime(tenantVO.getExpireTime()); //登录 StpUtil.login(loginUser.getUserId()); //在登录时缓存参数 - 缓存租户ID StpUtil.getSession().set(TenantIgnore.TENANT_ID, loginUser.getTenantId()); return StpUtil.getTokenInfo(); } /** * 重置密码 * @param passwordVO 重置密码实体 */ @Override public void resetPassword(RePasswordVO passwordVO) { //查询用户 MUser user = userMapper.selectUserByUserId(StpUtil.getLoginIdAsLong()); Assert.notNull(user, () -> new BusinessException(UserEnum.ErrorMsg.NONENTITY_ACCOUNT.getDesc())); //校验旧密码 String oldPassword = userManager.passwordEncrypt(passwordVO.getOldPassword(), user.getSalt()); Assert.isTrue(user.getPassword().equals(oldPassword), () -> new BusinessException(UserEnum.ErrorMsg.OLD_PASSWORD_INCORRECT.getDesc())); //新密码加密 user.setPassword(userManager.passwordEncrypt(passwordVO.getNewPassword(), user.getSalt())); //修改 userMapper.updateUserByUserId(user); } /** * 用户设置 -> 修改用户信息 * @param settingVO 用户信息 */ @Override public void updateUserInfo(UserSettingVO settingVO) { //查询用户 MUser user = userMapper.selectUserByUserId(StpUtil.getLoginIdAsLong()); Assert.notNull(user, () -> new BusinessException(UserEnum.ErrorMsg.NONENTITY_ACCOUNT.getDesc())); MUser updateUser = BeanUtil.copyProperties(settingVO, MUser.class); //用户ID updateUser.setUserId(user.getUserId()); //修改 userMapper.updateUserByUserId(updateUser); } /** * 修改用户头像 * @param userAvatar 用户头像base64编码 */ @Override public void updateUserAvatar(String userAvatar) { //用户ID Long userId = StpUtil.getLoginIdAsLong(); //校验头像大小 byte[] base64Decode = Base64.decode(userAvatar); ConfigVO config = configService.getConfigByConfigKey(CommonConstant.SYSTEM_CONFIG_USER_AVATAR_SIZE); long userAvatarSize = Long.parseLong(config.getConfigValue()); Assert.isFalse(base64Decode.length > userAvatarSize, () -> new BusinessException(UserEnum.ErrorMsg.USER_AVATAR_SIZE.getDesc())); //查询用户 MUser user = userMapper.selectUserByUserId(userId); Assert.notNull(user, () -> new BusinessException(UserEnum.ErrorMsg.NONENTITY_ACCOUNT.getDesc())); //更新用户头像 MUser updateUser = new MUser(); updateUser.setUserId(userId); updateUser.setUserAvatar(userAvatar); userMapper.updateUserByUserId(updateUser); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/utils/Add.java ================================================ package com.minimalist.basic.utils; /** * 添加时的分组校验 */ public interface Add { } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/utils/CommonConstant.java ================================================ package com.minimalist.basic.utils; import com.minimalist.basic.entity.vo.config.ConfigVO; import com.minimalist.basic.entity.vo.tenant.TenantVO; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class CommonConstant { /** 系统配置缓存 */ public static Map systemConfigMap = new ConcurrentHashMap<>(); /** 租户缓存 */ public static Map tenantMap = new ConcurrentHashMap<>(); /** 数字 0 */ public static final int ZERO = 0; /** 数字 1 */ public static final int ONE = 1; /** 增 */ public static final String ADD = "add"; /** 删 */ public static final String DELETE = "delete"; /** 改 */ public static final String UPDATE = "update"; /** 租户ID标识 */ public static final String TRACE_ID = "traceId"; /** 多租户开关配置 key */ public static final String SYSTEM_CONFIG_TENANT = "system.config.tenant"; /** 系统验证码 key */ public static final String SYSTEM_CONFIG_CAPTCHA_ENABLE = "system.config.captcha.enable"; /** 用户头像大小 key */ public static final String SYSTEM_CONFIG_USER_AVATAR_SIZE = "system.config.user.avatar.size"; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/utils/RedisKeyConstant.java ================================================ package com.minimalist.basic.utils; public class RedisKeyConstant { /** * 图形验证码缓存 */ public static final String CAPTCHA_CACHE_KEY = "captcha:{0}"; /** * 图形验证码,有效期 1分钟 */ public static final int CAPTCHA_CACHE_EX = 60; /** * 字典缓存前缀 dict:dictType:dictData */ public static final String DICT_CACHE_KEY = "dict:{0}"; /** * 字典缓存,有效期 30 天 */ public static final int DICT_CACHE_EX = 30 * 24 * 60 * 60; /** * 防重复提交 redis key */ public static final String REPEAT_SUBMIT_KEY = "repeat_submit:{0}"; /** * 用户角色 redis key */ public static final String USER_ROLE_CACHE_KEY = "user_role:{0}"; /** * 用户权限 perm key */ public static final String USER_PERM_CACHE_KEY = "user_perm:{0}"; /** * 用户权限超时时间 */ public static final int USER_PERM_CACHE_EX = 7 * 24 * 60 * 60; /** * 系统配置 订阅/发布 主题 */ public static final String SYSTEM_CONFIG_TOPIC_KEY = "system_config_topic"; /** * 租户信息 订阅/发布 主题 */ public static final String TENANT_DATA_TOPIC_KEY = "tenant_data_topic"; } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/utils/TenantUtil.java ================================================ package com.minimalist.basic.utils; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.servlet.JakartaServletUtil; import com.minimalist.basic.config.exception.BusinessException; import com.minimalist.basic.config.tenant.TenantIgnore; import com.minimalist.basic.entity.enums.UserEnum; import com.minimalist.basic.entity.vo.config.ConfigVO; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import java.nio.charset.StandardCharsets; import java.util.Optional; @Slf4j public class TenantUtil { /** * 校验系统是否开启多租户 * @return true开启,false关闭 */ public static boolean checkTenantOnOff() { //校验系统多租户是否开启 ConfigVO configVO = CommonConstant.systemConfigMap.get(CommonConstant.SYSTEM_CONFIG_TENANT); if (ObjectUtil.isNull(configVO)) { log.warn("校验系统多租户开关,获取CommonConstant.systemConfigMap缓存为空,请检查!!!"); return true; } return Boolean.parseBoolean(configVO.getConfigValue()); } /** * 获取要操作的租户ID * @return 租户ID */ public static long getTenantId() { //1. 从header中获取租户ID,获取到直接返回 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String tenantId = JakartaServletUtil.getHeader(request, TenantIgnore.TENANT_ID, StandardCharsets.UTF_8); if (StrUtil.isNotBlank(tenantId)) { return Long.parseLong(tenantId); } //2. 从当前登陆人身上获取租户ID long loginUserTenantId = getLoginUserTenantId(); if (loginUserTenantId == -1) { //未登录,抛出异常 throw new BusinessException(UserEnum.ErrorMsg.AUTH_EXPIRED.getDesc()); } //3. 校验当前登陆人是否为系统租户 boolean isSystemTenant = CommonConstant.ZERO == loginUserTenantId; if (isSystemTenant) { //是系统租户,校验是查系统数据,还是查其他租户数据 //前端在租户切换后,会将切换的租户ID放到cookie中 Long changeTenantId = TenantUtil.getCookieChangeTenantId(); if (ObjectUtil.isNull(changeTenantId)) { //changeTenantId为空,表示租户未进行切换,直接返回系统租户ID return loginUserTenantId; } //租户切换,返回切换后的租户ID,这表示虽然当前登录的是系统租户,但系统租户下要查询其他租户的数据 return changeTenantId; } else { //非系统租户,直接返回 return loginUserTenantId; } } /** * 检查是否要查询其他租户数据 * 前端在租户切换后,会将切换的租户ID放到cookie中 * @return true是,false否 */ public static boolean checkQueryTenantData() { return TenantUtil.getCookieChangeTenantId() != null; } /** * 检查是否为系统租户,系统租户ID = 0 * @return 是/否 */ public static boolean checkIsSystemTenant() { return CommonConstant.ZERO == getLoginUserTenantId(); } /** * 获取当前登陆人的租户ID * 当前登陆人的租户ID是在登录系统后通过 `StpUtil.getSession().set(TenantIgnore.TENANT_ID, tenantId);` 设置进去的 * 所以取的时候,还需要从 session 中取 * @return 租户ID */ public static long getLoginUserTenantId() { try { return Optional.ofNullable(StpUtil.getSession().getString(TenantIgnore.TENANT_ID)) .map(Long::valueOf) .orElse(-1L); } catch (Exception e) { return -1; } } /** * 获取cookie中,租户切换的租户ID * @return cookie中租户切换的租户ID */ public static Long getCookieChangeTenantId() { try { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); Cookie cookie = JakartaServletUtil.getCookie(request, TenantIgnore.CHANGE_TENANT_ID); return Optional.ofNullable(cookie).map(Cookie::getValue).filter(StrUtil::isNotBlank).map(Long::valueOf).orElse(null); } catch (Exception e) { return null; } } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/utils/TextUtil.java ================================================ package com.minimalist.basic.utils; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HtmlUtil; import lombok.extern.slf4j.Slf4j; import java.net.URI; import java.net.URISyntaxException; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @Slf4j public class TextUtil { /** 数据 */ private static Pattern p_image = Pattern.compile("]*?>", Pattern.CASE_INSENSITIVE); /** 数据 */ private static Pattern r_image = Pattern.compile("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)"); /** * 从富文本中获取图片URL * @param richText 富文本内容 * @return 图片URL列表 */ public static List getImgUrlByRichText(String richText) { List urlList = CollectionUtil.list(false); Matcher pMatcher = p_image.matcher(richText); while (pMatcher.find()) { //得到数据 String img = pMatcher.group(); //匹配中的src数据 Matcher rMatcher = r_image.matcher(img); while (rMatcher.find()) { urlList.add(rMatcher.group(1)); } } return urlList; } /** * 内容编码 * @param text 内容 * @return 编码后的内容 */ public static String encode(String text) { return HtmlUtil.escape(text); } /** * 内容解码 * @param text 内容 * @return 解码后的内容 */ public static String decode(String text) { return HtmlUtil.unescape(text); } /** * 分割字符串,并使List转为List * @param str 字符串,逗号分割 * @return List */ public static List splitAndListStrToListLong(String str) { if (StrUtil.isBlank(str)) { return CollectionUtil.list(false); } List split = StrUtil.split(str, ","); return split.stream().map(Long::parseLong).toList(); } //url匹配正则 private static final Pattern URL_PATTERN = Pattern.compile( "(?i)\\b((?:https?|ftp|file)://|www\\.|ftp\\.)" // 协议头匹配 + "[^\\s\"'<>(){}]+" // 核心内容匹配(排除常见边界符) + "(?=[\\s\"'<>(){}]|$)", // 前瞻确保在边界处停止 Pattern.CASE_INSENSITIVE); /** * 从富文本内容中提取url * @param content 富文本内容 * @return url列表 */ public static Set extractFileUrl(String content) { Set urls = new HashSet<>(); Matcher matcher = URL_PATTERN.matcher(decode(content)); while (matcher.find()) { String url = matcher.group(); urls.add(url); } return urls; } /** * url格式化,去除多个 / * @param url url * @return 格式化后的url */ public static String urlNormalize(String url) { try { URI uri = new URI(url); String normalizedPath = uri.getPath().replaceAll("/+", "/"); URI formattedUri = new URI( uri.getScheme(), uri.getAuthority(), new URI(normalizedPath).normalize().getPath(), // 标准化路径 uri.getQuery(), uri.getFragment() ); return formattedUri.toString(); } catch (URISyntaxException e) { log.warn("格式化url失败:", e); } return url; } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/utils/UnqIdUtil.java ================================================ package com.minimalist.basic.utils; import cn.hutool.core.util.IdUtil; public class UnqIdUtil { /** * 获取唯一ID * @return ID */ public static long uniqueId() { return IdUtil.getSnowflakeNextId(); } } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/utils/Update.java ================================================ package com.minimalist.basic.utils; /** * 更新时的分组校验 */ public interface Update { } ================================================ FILE: minimalist-basic/src/main/java/com/minimalist/basic/utils/ValidateUtil.java ================================================ package com.minimalist.basic.utils; import cn.hutool.core.collection.CollectionUtil; import com.minimalist.basic.config.exception.BusinessException; import jakarta.validation.ConstraintViolation; import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import java.util.List; import java.util.Set; import java.util.StringJoiner; import java.util.stream.Collectors; public class ValidateUtil { /** * 手动校验 */ public static void valid(T t) { ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); Validator validator = validatorFactory.getValidator(); Set> errors = validator.validate(t); List errorMsg = errors.stream().map(ConstraintViolation::getMessage).collect(Collectors.toList()); if (CollectionUtil.isNotEmpty(errorMsg)) { StringJoiner sj = new StringJoiner(","); errorMsg.forEach(sj::add); throw new BusinessException(sj.toString()); } } } ================================================ FILE: minimalist-basic/src/main/resources/mappers/MConfigMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MDeptMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MDictMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MFileMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MNoticeMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MPermsMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MPostMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MRoleDeptMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MRoleMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MRolePermMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MStorageMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MTenantDatasourceMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MTenantMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MTenantPackageMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MTenantPackagePermMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MUserDeptMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MUserMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MUserPostMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/main/resources/mappers/MUserRoleMapper.xml ================================================ ================================================ FILE: minimalist-basic/src/test/java/com/minimalist/basic/MinimalistBasicApplicationTests.java ================================================ package com.minimalist.basic; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest(classes = MinimalistBasicApplicationTests.class) class MinimalistBasicApplicationTests { @Test void contextLoads() { System.out.println("启动测试"); } } ================================================ FILE: minimalist-vue3/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* node_modules dist dist-ssr *.local # Editor directories and files .vscode/* .idea .DS_Store *.suo *.ntvs* *.njsproj *.sln *.sw? ================================================ FILE: minimalist-vue3/index.html ================================================ 极简多租户管理系统
================================================ FILE: minimalist-vue3/package.json ================================================ { "name": "minimalist-vue3", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite --mode dev", "test": "vite --mode dev", "prod": "vite --mode dev", "build": "vite build", "build:dev": "vite build --mode dev", "build:test": "vite build --mode test", "build:prod": "vite build --mode prod", "preview": "vite preview" }, "dependencies": { "@tinymce/tinymce-vue": "^5.1.0", "@vueuse/core": "^10.1.2", "@vueuse/integrations": "^10.1.2", "axios": "^1.4.0", "nprogress": "^0.2.0", "pinia": "^2.0.36", "tinymce": "^6.6.0", "universal-cookie": "^4.0.4", "vue": "^3.2.47", "vue-cropper": "^1.0.9", "vue-router": "^4.1.6", "xgplayer": "^3.0.22" }, "devDependencies": { "@arco-design/web-vue": "^2.45.3", "@vitejs/plugin-vue": "^4.1.0", "vite": "^4.3.2", "vite-plugin-windicss": "^1.8.10", "windicss": "^3.5.6" } } ================================================ FILE: minimalist-vue3/public/tinymce/skins/content/dark/content.css ================================================ body { background-color: #222f3e; color: #fff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; line-height: 1.4; margin: 1rem; } a { color: #4099ff; } table { border-collapse: collapse; } /* Apply a default padding if legacy cellpadding attribute is missing */ table:not([cellpadding]) th, table:not([cellpadding]) td { padding: 0.4rem; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-width"]) th, table[border]:not([border="0"]):not([style*="border-width"]) td { border-width: 1px; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-style"]) th, table[border]:not([border="0"]):not([style*="border-style"]) td { border-style: solid; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-color"]) th, table[border]:not([border="0"]):not([style*="border-color"]) td { border-color: #6d737b; } figure { display: table; margin: 1rem auto; } figure figcaption { color: #8a8f97; display: block; margin-top: 0.25rem; text-align: center; } hr { border-color: #6d737b; border-style: solid; border-width: 1px 0 0 0; } code { background-color: #6d737b; border-radius: 3px; padding: 0.1rem 0.2rem; } .mce-content-body:not([dir=rtl]) blockquote { border-left: 2px solid #6d737b; margin-left: 1.5rem; padding-left: 1rem; } .mce-content-body[dir=rtl] blockquote { border-right: 2px solid #6d737b; margin-right: 1.5rem; padding-right: 1rem; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/content/default/content.css ================================================ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; line-height: 1.4; margin: 1rem; } table { border-collapse: collapse; } /* Apply a default padding if legacy cellpadding attribute is missing */ table:not([cellpadding]) th, table:not([cellpadding]) td { padding: 0.4rem; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-width"]) th, table[border]:not([border="0"]):not([style*="border-width"]) td { border-width: 1px; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-style"]) th, table[border]:not([border="0"]):not([style*="border-style"]) td { border-style: solid; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-color"]) th, table[border]:not([border="0"]):not([style*="border-color"]) td { border-color: #ccc; } figure { display: table; margin: 1rem auto; } figure figcaption { color: #999; display: block; margin-top: 0.25rem; text-align: center; } hr { border-color: #ccc; border-style: solid; border-width: 1px 0 0 0; } code { background-color: #e8e8e8; border-radius: 3px; padding: 0.1rem 0.2rem; } .mce-content-body:not([dir=rtl]) blockquote { border-left: 2px solid #ccc; margin-left: 1.5rem; padding-left: 1rem; } .mce-content-body[dir=rtl] blockquote { border-right: 2px solid #ccc; margin-right: 1.5rem; padding-right: 1rem; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/content/document/content.css ================================================ @media screen { html { background: #f4f4f4; min-height: 100%; } } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } @media screen { body { background-color: #fff; box-shadow: 0 0 4px rgba(0, 0, 0, 0.15); box-sizing: border-box; margin: 1rem auto 0; max-width: 820px; min-height: calc(100vh - 1rem); padding: 4rem 6rem 6rem 6rem; } } table { border-collapse: collapse; } /* Apply a default padding if legacy cellpadding attribute is missing */ table:not([cellpadding]) th, table:not([cellpadding]) td { padding: 0.4rem; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-width"]) th, table[border]:not([border="0"]):not([style*="border-width"]) td { border-width: 1px; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-style"]) th, table[border]:not([border="0"]):not([style*="border-style"]) td { border-style: solid; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-color"]) th, table[border]:not([border="0"]):not([style*="border-color"]) td { border-color: #ccc; } figure figcaption { color: #999; margin-top: 0.25rem; text-align: center; } hr { border-color: #ccc; border-style: solid; border-width: 1px 0 0 0; } .mce-content-body:not([dir=rtl]) blockquote { border-left: 2px solid #ccc; margin-left: 1.5rem; padding-left: 1rem; } .mce-content-body[dir=rtl] blockquote { border-right: 2px solid #ccc; margin-right: 1.5rem; padding-right: 1rem; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/content/tinymce-5/content.css ================================================ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; line-height: 1.4; margin: 1rem; } table { border-collapse: collapse; } /* Apply a default padding if legacy cellpadding attribute is missing */ table:not([cellpadding]) th, table:not([cellpadding]) td { padding: 0.4rem; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-width"]) th, table[border]:not([border="0"]):not([style*="border-width"]) td { border-width: 1px; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-style"]) th, table[border]:not([border="0"]):not([style*="border-style"]) td { border-style: solid; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-color"]) th, table[border]:not([border="0"]):not([style*="border-color"]) td { border-color: #ccc; } figure { display: table; margin: 1rem auto; } figure figcaption { color: #999; display: block; margin-top: 0.25rem; text-align: center; } hr { border-color: #ccc; border-style: solid; border-width: 1px 0 0 0; } code { background-color: #e8e8e8; border-radius: 3px; padding: 0.1rem 0.2rem; } .mce-content-body:not([dir=rtl]) blockquote { border-left: 2px solid #ccc; margin-left: 1.5rem; padding-left: 1rem; } .mce-content-body[dir=rtl] blockquote { border-right: 2px solid #ccc; margin-right: 1.5rem; padding-right: 1rem; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/content/tinymce-5-dark/content.css ================================================ body { background-color: #2f3742; color: #dfe0e4; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; line-height: 1.4; margin: 1rem; } a { color: #4099ff; } table { border-collapse: collapse; } /* Apply a default padding if legacy cellpadding attribute is missing */ table:not([cellpadding]) th, table:not([cellpadding]) td { padding: 0.4rem; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-width"]) th, table[border]:not([border="0"]):not([style*="border-width"]) td { border-width: 1px; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-style"]) th, table[border]:not([border="0"]):not([style*="border-style"]) td { border-style: solid; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-color"]) th, table[border]:not([border="0"]):not([style*="border-color"]) td { border-color: #6d737b; } figure { display: table; margin: 1rem auto; } figure figcaption { color: #8a8f97; display: block; margin-top: 0.25rem; text-align: center; } hr { border-color: #6d737b; border-style: solid; border-width: 1px 0 0 0; } code { background-color: #6d737b; border-radius: 3px; padding: 0.1rem 0.2rem; } .mce-content-body:not([dir=rtl]) blockquote { border-left: 2px solid #6d737b; margin-left: 1.5rem; padding-left: 1rem; } .mce-content-body[dir=rtl] blockquote { border-right: 2px solid #6d737b; margin-right: 1.5rem; padding-right: 1rem; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/content/writer/content.css ================================================ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; line-height: 1.4; margin: 1rem auto; max-width: 900px; } table { border-collapse: collapse; } /* Apply a default padding if legacy cellpadding attribute is missing */ table:not([cellpadding]) th, table:not([cellpadding]) td { padding: 0.4rem; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-width"]) th, table[border]:not([border="0"]):not([style*="border-width"]) td { border-width: 1px; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-style"]) th, table[border]:not([border="0"]):not([style*="border-style"]) td { border-style: solid; } /* Set default table styles if a table has a positive border attribute and no inline css */ table[border]:not([border="0"]):not([style*="border-color"]) th, table[border]:not([border="0"]):not([style*="border-color"]) td { border-color: #ccc; } figure { display: table; margin: 1rem auto; } figure figcaption { color: #999; display: block; margin-top: 0.25rem; text-align: center; } hr { border-color: #ccc; border-style: solid; border-width: 1px 0 0 0; } code { background-color: #e8e8e8; border-radius: 3px; padding: 0.1rem 0.2rem; } .mce-content-body:not([dir=rtl]) blockquote { border-left: 2px solid #ccc; margin-left: 1.5rem; padding-left: 1rem; } .mce-content-body[dir=rtl] blockquote { border-right: 2px solid #ccc; margin-right: 1.5rem; padding-right: 1rem; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/langs/zh-Hans.js ================================================ tinymce.addI18n("zh-Hans",{"Redo":"\u91cd\u505a","Undo":"\u64a4\u9500","Cut":"\u526a\u5207","Copy":"\u590d\u5236","Paste":"\u7c98\u8d34","Select all":"\u5168\u9009","New document":"\u65b0\u5efa\u6587\u6863","Ok":"\u786e\u5b9a","Cancel":"\u53d6\u6d88","Visual aids":"\u7f51\u683c\u7ebf","Bold":"\u7c97\u4f53","Italic":"\u659c\u4f53","Underline":"\u4e0b\u5212\u7ebf","Strikethrough":"\u5220\u9664\u7ebf","Superscript":"\u4e0a\u6807","Subscript":"\u4e0b\u6807","Clear formatting":"\u6e05\u9664\u683c\u5f0f","Remove":"\u79fb\u9664","Align left":"\u5de6\u5bf9\u9f50","Align center":"\u5c45\u4e2d\u5bf9\u9f50","Align right":"\u53f3\u5bf9\u9f50","No alignment":"\u672a\u5bf9\u9f50","Justify":"\u4e24\u7aef\u5bf9\u9f50","Bullet list":"\u65e0\u5e8f\u5217\u8868","Numbered list":"\u6709\u5e8f\u5217\u8868","Decrease indent":"\u51cf\u5c11\u7f29\u8fdb","Increase indent":"\u589e\u52a0\u7f29\u8fdb","Close":"\u5173\u95ed","Formats":"\u683c\u5f0f","Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.":"\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u6253\u5f00\u526a\u8d34\u677f\uff0c\u8bf7\u4f7f\u7528Ctrl+X/C/V\u7b49\u5feb\u6377\u952e\u3002","Headings":"\u6807\u9898","Heading 1":"\u4e00\u7ea7\u6807\u9898","Heading 2":"\u4e8c\u7ea7\u6807\u9898","Heading 3":"\u4e09\u7ea7\u6807\u9898","Heading 4":"\u56db\u7ea7\u6807\u9898","Heading 5":"\u4e94\u7ea7\u6807\u9898","Heading 6":"\u516d\u7ea7\u6807\u9898","Preformatted":"\u9884\u5148\u683c\u5f0f\u5316\u7684","Div":"Div","Pre":"\u524d\u8a00","Code":"\u4ee3\u7801","Paragraph":"\u6bb5\u843d","Blockquote":"\u5f15\u6587\u533a\u5757","Inline":"\u6587\u672c","Blocks":"\u6837\u5f0f","Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.":"\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002","Fonts":"\u5b57\u4f53","Font sizes":"\u5b57\u4f53\u5927\u5c0f","Class":"\u7c7b\u578b","Browse for an image":"\u6d4f\u89c8\u56fe\u50cf","OR":"\u6216","Drop an image here":"\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64","Upload":"\u4e0a\u4f20","Uploading image":"\u4e0a\u4f20\u56fe\u7247","Block":"\u5757","Align":"\u5bf9\u9f50","Default":"\u9884\u8bbe","Circle":"\u7a7a\u5fc3\u5706","Disc":"\u5b9e\u5fc3\u5706","Square":"\u5b9e\u5fc3\u65b9\u5757","Lower Alpha":"\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd","Lower Greek":"\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd","Lower Roman":"\u5c0f\u5199\u7f57\u9a6c\u6570\u5b57","Upper Alpha":"\u5927\u5199\u82f1\u6587\u5b57\u6bcd","Upper Roman":"\u5927\u5199\u7f57\u9a6c\u6570\u5b57","Anchor...":"\u951a\u70b9...","Anchor":"\u951a\u70b9","Name":"\u540d\u79f0","ID":"ID","ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.":"ID\u5e94\u8be5\u4ee5\u82f1\u6587\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u9762\u53ea\u80fd\u6709\u82f1\u6587\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002","You have unsaved changes are you sure you want to navigate away?":"\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f","Restore last draft":"\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f","Special character...":"\u7279\u6b8a\u5b57\u7b26...","Special Character":"\u7279\u6b8a\u5b57\u7b26","Source code":"\u6e90\u4ee3\u7801","Insert/Edit code sample":"\u63d2\u5165/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b","Language":"\u8bed\u8a00","Code sample...":"\u793a\u4f8b\u4ee3\u7801...","Left to right":"\u7531\u5de6\u5230\u53f3","Right to left":"\u7531\u53f3\u5230\u5de6","Title":"\u6807\u9898","Fullscreen":"\u5168\u5c4f","Action":"\u52a8\u4f5c","Shortcut":"\u5feb\u6377\u65b9\u5f0f","Help":"\u5e2e\u52a9","Address":"\u5730\u5740","Focus to menubar":"\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f","Focus to toolbar":"\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f","Focus to element path":"\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84","Focus to contextual toolbar":"\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355","Insert link (if link plugin activated)":"\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Save (if save plugin activated)":"\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Find (if searchreplace plugin activated)":"\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Plugins installed ({0}):":"\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):","Premium plugins:":"\u4f18\u79c0\u63d2\u4ef6\uff1a","Learn more...":"\u4e86\u89e3\u66f4\u591a...","You are using {0}":"\u4f60\u6b63\u5728\u4f7f\u7528 {0}","Plugins":"\u63d2\u4ef6","Handy Shortcuts":"\u5feb\u6377\u952e","Horizontal line":"\u6c34\u5e73\u5206\u5272\u7ebf","Insert/edit image":"\u63d2\u5165/\u7f16\u8f91\u56fe\u7247","Alternative description":"\u66ff\u4ee3\u63cf\u8ff0","Accessibility":"\u8f85\u52a9\u529f\u80fd","Image is decorative":"\u56fe\u50cf\u662f\u88c5\u9970\u6027\u7684","Source":"\u6e90","Dimensions":"\u5c3a\u5bf8","Constrain proportions":"\u4fdd\u6301\u6bd4\u4f8b","General":"\u4e00\u822c","Advanced":"\u9ad8\u7ea7","Style":"\u6837\u5f0f","Vertical space":"\u5782\u76f4\u95f4\u8ddd","Horizontal space":"\u6c34\u5e73\u95f4\u8ddd","Border":"\u6846\u7ebf","Insert image":"\u63d2\u5165\u56fe\u7247","Image...":"\u56fe\u7247...","Image list":"\u56fe\u7247\u6e05\u5355","Resize":"\u8c03\u6574\u5927\u5c0f","Insert date/time":"\u63d2\u5165\u65e5\u671f/\u65f6\u95f4","Date/time":"\u65e5\u671f/\u65f6\u95f4","Insert/edit link":"\u63d2\u5165/\u7f16\u8f91\u94fe\u63a5","Text to display":"\u8981\u663e\u793a\u7684\u6587\u672c","Url":"\u5730\u5740","Open link in...":"\u94fe\u63a5\u6253\u5f00\u4f4d\u7f6e...","Current window":"\u5f53\u524d\u7a97\u53e3","None":"\u65e0","New window":"\u65b0\u7a97\u53e3","Open link":"\u6253\u5f00\u94fe\u63a5","Remove link":"\u79fb\u9664\u94fe\u63a5","Anchors":"\u951a\u70b9","Link...":"\u94fe\u63a5...","Paste or type a link":"\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5","The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?":"\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto: \u524d\u7f00\u5417\uff1f","The URL you entered seems to be an external link. Do you want to add the required http:// prefix?":"\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:// \u524d\u7f00\u5417\uff1f","The URL you entered seems to be an external link. Do you want to add the required https:// prefix?":"\u60a8\u8f93\u5165\u7684 URL \u4f3c\u4e4e\u662f\u4e00\u4e2a\u5916\u90e8\u94fe\u63a5\u3002\u60a8\u60f3\u6dfb\u52a0\u6240\u9700\u7684 https:// \u524d\u7f00\u5417\uff1f","Link list":"\u94fe\u63a5\u6e05\u5355","Insert video":"\u63d2\u5165\u89c6\u9891","Insert/edit video":"\u63d2\u5165/\u7f16\u8f91\u89c6\u9891","Insert/edit media":"\u63d2\u5165/\u7f16\u8f91\u5a92\u4f53","Alternative source":"\u955c\u50cf","Alternative source URL":"\u66ff\u4ee3\u6765\u6e90\u7f51\u5740","Media poster (Image URL)":"\u5c01\u9762(\u56fe\u7247\u5730\u5740)","Paste your embed code below:":"\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:","Embed":"\u5185\u5d4c","Media...":"\u591a\u5a92\u4f53...","Nonbreaking space":"\u4e0d\u95f4\u65ad\u7a7a\u683c","Page break":"\u5206\u9875\u7b26","Paste as text":"\u7c98\u8d34\u4e3a\u6587\u672c","Preview":"\u9884\u89c8","Print":"\u6253\u5370","Print...":"\u6253\u5370...","Save":"\u4fdd\u5b58","Find":"\u5bfb\u627e","Replace with":"\u66ff\u6362\u4e3a","Replace":"\u66ff\u6362","Replace all":"\u66ff\u6362\u5168\u90e8","Previous":"\u4e0a\u4e00\u4e2a","Next":"\u4e0b\u4e00\u4e2a","Find and Replace":"\u67e5\u627e\u548c\u66ff\u6362","Find and replace...":"\u67e5\u627e\u5e76\u66ff\u6362...","Could not find the specified string.":"\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9\u3002","Match case":"\u5927\u5c0f\u5199\u5339\u914d","Find whole words only":"\u5168\u5b57\u5339\u914d","Find in selection":"\u5728\u9009\u533a\u4e2d\u67e5\u627e","Insert table":"\u63d2\u5165\u8868\u683c","Table properties":"\u8868\u683c\u5c5e\u6027","Delete table":"\u5220\u9664\u8868\u683c","Cell":"\u5355\u5143\u683c","Row":"\u884c","Column":"\u680f\u76ee","Cell properties":"\u5355\u5143\u683c\u5c5e\u6027","Merge cells":"\u5408\u5e76\u5355\u5143\u683c","Split cell":"\u62c6\u5206\u5355\u5143\u683c","Insert row before":"\u5728\u4e0a\u65b9\u63d2\u5165\u884c","Insert row after":"\u5728\u4e0b\u65b9\u63d2\u5165\u884c","Delete row":"\u5220\u9664\u884c","Row properties":"\u884c\u5c5e\u6027","Cut row":"\u526a\u5207\u884c","Cut column":"\u526a\u5207\u5217","Copy row":"\u590d\u5236\u884c","Copy column":"\u590d\u5236\u5217","Paste row before":"\u7c98\u8d34\u884c\u5230\u4e0a\u65b9","Paste column before":"\u7c98\u8d34\u6b64\u5217\u524d","Paste row after":"\u7c98\u8d34\u884c\u5230\u4e0b\u65b9","Paste column after":"\u7c98\u8d34\u540e\u9762\u7684\u5217","Insert column before":"\u5728\u5de6\u4fa7\u63d2\u5165\u5217","Insert column after":"\u5728\u53f3\u4fa7\u63d2\u5165\u5217","Delete column":"\u5220\u9664\u5217","Cols":"\u5217","Rows":"\u884c\u6570","Width":"\u5bbd\u5ea6","Height":"\u9ad8\u5ea6","Cell spacing":"\u5355\u5143\u683c\u5916\u95f4\u8ddd","Cell padding":"\u5355\u5143\u683c\u5185\u8fb9\u8ddd","Row clipboard actions":"\u884c\u526a\u8d34\u677f\u64cd\u4f5c","Column clipboard actions":"\u5217\u526a\u8d34\u677f\u64cd\u4f5c","Table styles":"\u8868\u683c\u6837\u5f0f","Cell styles":"\u5355\u5143\u683c\u6837\u5f0f","Column header":"\u5217\u6807\u9898","Row header":"\u884c\u5934","Table caption":"\u8868\u683c\u6807\u9898","Caption":"\u6807\u9898","Show caption":"\u663e\u793a\u6807\u9898","Left":"\u5de6","Center":"\u5c45\u4e2d","Right":"\u53f3","Cell type":"\u50a8\u5b58\u683c\u522b","Scope":"\u8303\u56f4","Alignment":"\u5bf9\u9f50","Horizontal align":"\u6c34\u5e73\u5bf9\u9f50","Vertical align":"\u5782\u76f4\u5bf9\u9f50","Top":"\u4e0a\u65b9\u5bf9\u9f50","Middle":"\u5c45\u4e2d\u5bf9\u9f50","Bottom":"\u4e0b\u65b9\u5bf9\u9f50","Header cell":"\u8868\u5934\u5355\u5143\u683c","Row group":"\u884c\u7ec4","Column group":"\u5217\u7ec4","Row type":"\u884c\u7c7b\u578b","Header":"\u8868\u5934","Body":"\u8868\u4f53","Footer":"\u8868\u5c3e","Border color":"\u6846\u7ebf\u989c\u8272","Solid":"\u5b9e\u7ebf","Dotted":"\u865a\u7ebf","Dashed":"\u865a\u7ebf","Double":"\u53cc\u7cbe\u5ea6","Groove":"\u51f9\u69fd","Ridge":"\u6d77\u810a\u5ea7","Inset":"\u5d4c\u5165","Outset":"\u5916\u7f6e","Hidden":"\u9690\u85cf","Insert template...":"\u63d2\u5165\u6a21\u677f...","Templates":"\u6a21\u677f","Template":"\u6a21\u677f","Insert Template":"\u63d2\u5165\u6a21\u677f","Text color":"\u6587\u672c\u989c\u8272","Background color":"\u80cc\u666f\u989c\u8272","Custom...":"\u81ea\u5b9a\u4e49......","Custom color":"\u81ea\u5b9a\u4e49\u989c\u8272","No color":"\u65e0","Remove color":"\u79fb\u9664\u989c\u8272","Show blocks":"\u663e\u793a\u533a\u5757\u8fb9\u6846","Show invisible characters":"\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26","Word count":"\u5b57\u6570","Count":"\u8ba1\u6570","Document":"\u6587\u6863","Selection":"\u9009\u62e9","Words":"\u5355\u8bcd","Words: {0}":"\u5b57\u6570\uff1a{0}","{0} words":"{0} \u5b57","File":"\u6587\u4ef6","Edit":"\u7f16\u8f91","Insert":"\u63d2\u5165","View":"\u67e5\u770b","Format":"\u683c\u5f0f","Table":"\u8868\u683c","Tools":"\u5de5\u5177","Powered by {0}":"\u7531{0}\u9a71\u52a8","Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help":"\u7f16\u8f91\u533a\u3002\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9","Image title":"\u56fe\u7247\u6807\u9898","Border width":"\u8fb9\u6846\u5bbd\u5ea6","Border style":"\u8fb9\u6846\u6837\u5f0f","Error":"\u9519\u8bef","Warn":"\u8b66\u544a","Valid":"\u6709\u6548","To open the popup, press Shift+Enter":"\u6309Shitf+Enter\u952e\u6253\u5f00\u5bf9\u8bdd\u6846","Rich Text Area":"\u5bcc\u6587\u672c\u533a\u57df","Rich Text Area. Press ALT-0 for help.":"\u7f16\u8f91\u533a\u3002\u6309Alt+0\u952e\u6253\u5f00\u5e2e\u52a9\u3002","System Font":"\u7cfb\u7edf\u5b57\u4f53","Failed to upload image: {0}":"\u56fe\u7247\u4e0a\u4f20\u5931\u8d25: {0}","Failed to load plugin: {0} from url {1}":"\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25: {0} \u6765\u81ea\u94fe\u63a5 {1}","Failed to load plugin url: {0}":"\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25 \u94fe\u63a5: {0}","Failed to initialize plugin: {0}":"\u63d2\u4ef6\u521d\u59cb\u5316\u5931\u8d25: {0}","example":"\u793a\u4f8b","Search":"\u641c\u7d22","All":"\u5168\u90e8","Currency":"\u8d27\u5e01","Text":"\u6587\u5b57","Quotations":"\u5f15\u7528","Mathematical":"\u6570\u5b66","Extended Latin":"\u62c9\u4e01\u8bed\u6269\u5145","Symbols":"\u7b26\u53f7","Arrows":"\u7bad\u5934","User Defined":"\u81ea\u5b9a\u4e49","dollar sign":"\u7f8e\u5143\u7b26\u53f7","currency sign":"\u8d27\u5e01\u7b26\u53f7","euro-currency sign":"\u6b27\u5143\u7b26\u53f7","colon sign":"\u5192\u53f7","cruzeiro sign":"\u514b\u9c81\u8d5b\u7f57\u5e01\u7b26\u53f7","french franc sign":"\u6cd5\u90ce\u7b26\u53f7","lira sign":"\u91cc\u62c9\u7b26\u53f7","mill sign":"\u5bc6\u5c14\u7b26\u53f7","naira sign":"\u5948\u62c9\u7b26\u53f7","peseta sign":"\u6bd4\u585e\u5854\u7b26\u53f7","rupee sign":"\u5362\u6bd4\u7b26\u53f7","won sign":"\u97e9\u5143\u7b26\u53f7","new sheqel sign":"\u65b0\u8c22\u514b\u5c14\u7b26\u53f7","dong sign":"\u8d8a\u5357\u76fe\u7b26\u53f7","kip sign":"\u8001\u631d\u57fa\u666e\u7b26\u53f7","tugrik sign":"\u56fe\u683c\u91cc\u514b\u7b26\u53f7","drachma sign":"\u5fb7\u62c9\u514b\u9a6c\u7b26\u53f7","german penny symbol":"\u5fb7\u56fd\u4fbf\u58eb\u7b26\u53f7","peso sign":"\u6bd4\u7d22\u7b26\u53f7","guarani sign":"\u74dc\u62c9\u5c3c\u7b26\u53f7","austral sign":"\u6fb3\u5143\u7b26\u53f7","hryvnia sign":"\u683c\u91cc\u592b\u5c3c\u4e9a\u7b26\u53f7","cedi sign":"\u585e\u5730\u7b26\u53f7","livre tournois sign":"\u91cc\u5f17\u5f17\u5c14\u7b26\u53f7","spesmilo sign":"spesmilo\u7b26\u53f7","tenge sign":"\u575a\u6208\u7b26\u53f7","indian rupee sign":"\u5370\u5ea6\u5362\u6bd4","turkish lira sign":"\u571f\u8033\u5176\u91cc\u62c9","nordic mark sign":"\u5317\u6b27\u9a6c\u514b","manat sign":"\u9a6c\u7eb3\u7279\u7b26\u53f7","ruble sign":"\u5362\u5e03\u7b26\u53f7","yen character":"\u65e5\u5143\u5b57\u6837","yuan character":"\u4eba\u6c11\u5e01\u5143\u5b57\u6837","yuan character, in hong kong and taiwan":"\u5143\u5b57\u6837\uff08\u6e2f\u53f0\u5730\u533a\uff09","yen/yuan character variant one":"\u5143\u5b57\u6837\uff08\u5927\u5199\uff09","Emojis":"Emojis","Emojis...":"Emojis...","Loading emojis...":"\u6b63\u5728\u52a0\u8f7dEmojis...","Could not load emojis":"\u65e0\u6cd5\u52a0\u8f7dEmojis","People":"\u4eba\u7c7b","Animals and Nature":"\u52a8\u7269\u548c\u81ea\u7136","Food and Drink":"\u98df\u7269\u548c\u996e\u54c1","Activity":"\u6d3b\u52a8","Travel and Places":"\u65c5\u6e38\u548c\u5730\u70b9","Objects":"\u7269\u4ef6","Flags":"\u65d7\u5e1c","Characters":"\u5b57\u7b26","Characters (no spaces)":"\u5b57\u7b26(\u65e0\u7a7a\u683c)","{0} characters":"{0} \u4e2a\u5b57\u7b26","Error: Form submit field collision.":"\u9519\u8bef: \u8868\u5355\u63d0\u4ea4\u5b57\u6bb5\u51b2\u7a81\u3002","Error: No form element found.":"\u9519\u8bef: \u6ca1\u6709\u8868\u5355\u63a7\u4ef6\u3002","Color swatch":"\u989c\u8272\u6837\u672c","Color Picker":"\u9009\u8272\u5668","Invalid hex color code: {0}":"\u5341\u516d\u8fdb\u5236\u989c\u8272\u4ee3\u7801\u65e0\u6548\uff1a {0}","Invalid input":"\u65e0\u6548\u8f93\u5165","R":"R","Red component":"\u7ea2\u8272\u90e8\u5206","G":"G","Green component":"\u7eff\u8272\u90e8\u5206","B":"B","Blue component":"\u767d\u8272\u90e8\u5206","#":"#","Hex color code":"\u5341\u516d\u8fdb\u5236\u989c\u8272\u4ee3\u7801","Range 0 to 255":"\u8303\u56f40\u81f3255","Turquoise":"\u9752\u7eff\u8272","Green":"\u7eff\u8272","Blue":"\u84dd\u8272","Purple":"\u7d2b\u8272","Navy Blue":"\u6d77\u519b\u84dd","Dark Turquoise":"\u6df1\u84dd\u7eff\u8272","Dark Green":"\u6df1\u7eff\u8272","Medium Blue":"\u4e2d\u84dd\u8272","Medium Purple":"\u4e2d\u7d2b\u8272","Midnight Blue":"\u6df1\u84dd\u8272","Yellow":"\u9ec4\u8272","Orange":"\u6a59\u8272","Red":"\u7ea2\u8272","Light Gray":"\u6d45\u7070\u8272","Gray":"\u7070\u8272","Dark Yellow":"\u6697\u9ec4\u8272","Dark Orange":"\u6df1\u6a59\u8272","Dark Red":"\u6df1\u7ea2\u8272","Medium Gray":"\u4e2d\u7070\u8272","Dark Gray":"\u6df1\u7070\u8272","Light Green":"\u6d45\u7eff\u8272","Light Yellow":"\u6d45\u9ec4\u8272","Light Red":"\u6d45\u7ea2\u8272","Light Purple":"\u6d45\u7d2b\u8272","Light Blue":"\u6d45\u84dd\u8272","Dark Purple":"\u6df1\u7d2b\u8272","Dark Blue":"\u6df1\u84dd\u8272","Black":"\u9ed1\u8272","White":"\u767d\u8272","Switch to or from fullscreen mode":"\u5207\u6362\u5168\u5c4f\u6a21\u5f0f","Open help dialog":"\u6253\u5f00\u5e2e\u52a9\u5bf9\u8bdd\u6846","history":"\u5386\u53f2","styles":"\u6837\u5f0f","formatting":"\u683c\u5f0f\u5316","alignment":"\u5bf9\u9f50","indentation":"\u7f29\u8fdb","Font":"\u5b57\u4f53","Size":"\u5b57\u53f7","More...":"\u66f4\u591a...","Select...":"\u9009\u62e9...","Preferences":"\u9996\u9009\u9879","Yes":"\u662f","No":"\u5426","Keyboard Navigation":"\u952e\u76d8\u6307\u5f15","Version":"\u7248\u672c","Code view":"\u4ee3\u7801\u89c6\u56fe","Open popup menu for split buttons":"\u6253\u5f00\u5f39\u51fa\u5f0f\u83dc\u5355\uff0c\u7528\u4e8e\u62c6\u5206\u6309\u94ae","List Properties":"\u5217\u8868\u5c5e\u6027","List properties...":"\u6807\u9898\u5b57\u4f53\u5c5e\u6027","Start list at number":"\u4ee5\u6570\u5b57\u5f00\u59cb\u5217\u8868","Line height":"\u884c\u9ad8","Dropped file type is not supported":"\u6b64\u6587\u4ef6\u7c7b\u578b\u4e0d\u652f\u6301\u62d6\u653e","Loading...":"\u52a0\u8f7d\u4e2d...","ImageProxy HTTP error: Rejected request":"\u56fe\u7247\u4ee3\u7406\u8bf7\u6c42\u9519\u8bef\uff1a\u8bf7\u6c42\u88ab\u62d2\u7edd","ImageProxy HTTP error: Could not find Image Proxy":"\u56fe\u7247\u4ee3\u7406\u8bf7\u6c42\u9519\u8bef\uff1a\u65e0\u6cd5\u627e\u5230\u56fe\u7247\u4ee3\u7406","ImageProxy HTTP error: Incorrect Image Proxy URL":"\u56fe\u7247\u4ee3\u7406\u8bf7\u6c42\u9519\u8bef\uff1a\u56fe\u7247\u4ee3\u7406\u5730\u5740\u9519\u8bef","ImageProxy HTTP error: Unknown ImageProxy error":"\u56fe\u7247\u4ee3\u7406\u8bf7\u6c42\u9519\u8bef\uff1a\u672a\u77e5\u7684\u56fe\u7247\u4ee3\u7406\u9519\u8bef"}); ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/oxide/content.css ================================================ .mce-content-body .mce-item-anchor { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; } .mce-content-body .mce-item-anchor:empty { cursor: default; display: inline-block; height: 12px !important; padding: 0 2px; -webkit-user-modify: read-only; -moz-user-modify: read-only; -webkit-user-select: all; -moz-user-select: all; user-select: all; width: 8px !important; } .mce-content-body .mce-item-anchor:not(:empty) { background-position-x: 2px; display: inline-block; padding-left: 12px; } .mce-content-body .mce-item-anchor[data-mce-selected] { outline-offset: 1px; } .tox-comments-visible .tox-comment[contenteditable="false"]:not([data-mce-selected]), .tox-comments-visible span.tox-comment img:not([data-mce-selected]), .tox-comments-visible span.tox-comment > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #ffe89d; } .tox-comments-visible .tox-comment[contenteditable="false"][data-mce-annotation-active="true"]:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] img:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment:not([data-mce-selected]) { background-color: #ffe89d; outline: none; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"]:not([data-mce-selected="inline-boundary"]) { background-color: #fed635; } .tox-checklist > li:not(.tox-checklist--hidden) { list-style: none; margin: 0.25em 0; } .tox-checklist > li:not(.tox-checklist--hidden)::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); cursor: pointer; height: 1em; margin-left: -1.5em; margin-top: 0.125em; position: absolute; width: 1em; } .tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); } [dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { margin-left: 0; margin-right: -1.5em; } /* stylelint-disable */ /* http://prismjs.com/ */ /** * prism.js default theme for JavaScript, CSS and HTML * Based on dabblet (http://dabblet.com) * @author Lea Verou */ code[class*="language-"], pre[class*="language-"] { color: black; background: none; text-shadow: 0 1px white; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; font-size: 1em; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.5; -moz-tab-size: 4; tab-size: 4; -webkit-hyphens: none; hyphens: none; } pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { text-shadow: none; background: #b3d4fc; } pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection { text-shadow: none; background: #b3d4fc; } @media print { code[class*="language-"], pre[class*="language-"] { text-shadow: none; } } /* Code blocks */ pre[class*="language-"] { padding: 1em; margin: 0.5em 0; overflow: auto; } :not(pre) > code[class*="language-"], pre[class*="language-"] { background: #f5f2f0; } /* Inline code */ :not(pre) > code[class*="language-"] { padding: 0.1em; border-radius: 0.3em; white-space: normal; } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: slategray; } .token.punctuation { color: #999; } .token.namespace { opacity: 0.7; } .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: #905; } .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #690; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { color: #9a6e3a; /* This background color was intended by the author of this theme. */ background: hsla(0, 0%, 100%, 0.5); } .token.atrule, .token.attr-value, .token.keyword { color: #07a; } .token.function, .token.class-name { color: #DD4A68; } .token.regex, .token.important, .token.variable { color: #e90; } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } /* stylelint-enable */ .mce-content-body { overflow-wrap: break-word; word-wrap: break-word; } .mce-content-body .mce-visual-caret { background-color: black; background-color: currentColor; position: absolute; } .mce-content-body .mce-visual-caret-hidden { display: none; } .mce-content-body *[data-mce-caret] { left: -1000px; margin: 0; padding: 0; position: absolute; right: auto; top: 0; } .mce-content-body .mce-offscreen-selection { left: -2000000px; max-width: 1000000px; position: absolute; } .mce-content-body *[contentEditable=false] { cursor: default; } .mce-content-body *[contentEditable=true] { cursor: text; } .tox-cursor-format-painter { cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; } div.mce-footnotes hr { margin-inline-end: auto; margin-inline-start: 0; width: 25%; } div.mce-footnotes li > a.mce-footnotes-backlink { text-decoration: none; } @media print { sup.mce-footnote a { color: black; text-decoration: none; } div.mce-footnotes { break-inside: avoid; width: 100%; } div.mce-footnotes li > a.mce-footnotes-backlink { display: none; } } .mce-content-body figure.align-left { float: left; } .mce-content-body figure.align-right { float: right; } .mce-content-body figure.image.align-center { display: table; margin-left: auto; margin-right: auto; } .mce-preview-object { border: 1px solid gray; display: inline-block; line-height: 0; margin: 0 2px 0 2px; position: relative; } .mce-preview-object .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-preview-object[data-mce-selected="2"] .mce-shim { display: none; } .mce-content-body .mce-mergetag { cursor: default !important; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body .mce-mergetag:hover { background-color: rgba(0, 108, 231, 0.1); } .mce-content-body .mce-mergetag-affix { background-color: rgba(0, 108, 231, 0.1); color: #006ce7; } .mce-object { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; border: 1px dashed #aaa; } .mce-pagebreak { border: 1px dashed #aaa; cursor: default; display: block; height: 5px; margin-top: 15px; page-break-before: always; width: 100%; } @media print { .mce-pagebreak { border: 0; } } .tiny-pageembed .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tiny-pageembed[data-mce-selected="2"] .mce-shim { display: none; } .tiny-pageembed { display: inline-block; position: relative; } .tiny-pageembed--21by9, .tiny-pageembed--16by9, .tiny-pageembed--4by3, .tiny-pageembed--1by1 { display: block; overflow: hidden; padding: 0; position: relative; width: 100%; } .tiny-pageembed--21by9 { padding-top: 42.857143%; } .tiny-pageembed--16by9 { padding-top: 56.25%; } .tiny-pageembed--4by3 { padding-top: 75%; } .tiny-pageembed--1by1 { padding-top: 100%; } .tiny-pageembed--21by9 iframe, .tiny-pageembed--16by9 iframe, .tiny-pageembed--4by3 iframe, .tiny-pageembed--1by1 iframe { border: 0; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-content-body[data-mce-placeholder] { position: relative; } .mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { color: rgba(34, 47, 62, 0.7); content: attr(data-mce-placeholder); position: absolute; } .mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { left: 1px; } .mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { right: 1px; } .mce-content-body div.mce-resizehandle { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; height: 10px; position: absolute; width: 10px; z-index: 1298; } .mce-content-body div.mce-resizehandle:hover { background-color: #4099ff; } .mce-content-body div.mce-resizehandle:nth-of-type(1) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(2) { cursor: nesw-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(3) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(4) { cursor: nesw-resize; } .mce-content-body .mce-resize-backdrop { z-index: 10000; } .mce-content-body .mce-clonedresizable { cursor: default; opacity: 0.5; outline: 1px dashed black; position: absolute; z-index: 10001; } .mce-content-body .mce-clonedresizable.mce-resizetable-columns th, .mce-content-body .mce-clonedresizable.mce-resizetable-columns td { border: 0; } .mce-content-body .mce-resize-helper { background: #555; background: rgba(0, 0, 0, 0.75); border: 1px; border-radius: 3px; color: white; display: none; font-family: sans-serif; font-size: 12px; line-height: 14px; margin: 5px 10px; padding: 5px; position: absolute; white-space: nowrap; z-index: 10002; } .tox-rtc-user-selection { position: relative; } .tox-rtc-user-cursor { bottom: 0; cursor: default; position: absolute; top: 0; width: 2px; } .tox-rtc-user-cursor::before { background-color: inherit; border-radius: 50%; content: ''; display: block; height: 8px; position: absolute; right: -3px; top: -3px; width: 8px; } .tox-rtc-user-cursor:hover::after { background-color: inherit; border-radius: 100px; box-sizing: border-box; color: #fff; content: attr(data-user); display: block; font-size: 12px; font-weight: bold; left: -5px; min-height: 8px; min-width: 8px; padding: 0 12px; position: absolute; top: -11px; white-space: nowrap; z-index: 1000; } .tox-rtc-user-selection--1 .tox-rtc-user-cursor { background-color: #2dc26b; } .tox-rtc-user-selection--2 .tox-rtc-user-cursor { background-color: #e03e2d; } .tox-rtc-user-selection--3 .tox-rtc-user-cursor { background-color: #f1c40f; } .tox-rtc-user-selection--4 .tox-rtc-user-cursor { background-color: #3598db; } .tox-rtc-user-selection--5 .tox-rtc-user-cursor { background-color: #b96ad9; } .tox-rtc-user-selection--6 .tox-rtc-user-cursor { background-color: #e67e23; } .tox-rtc-user-selection--7 .tox-rtc-user-cursor { background-color: #aaa69d; } .tox-rtc-user-selection--8 .tox-rtc-user-cursor { background-color: #f368e0; } .tox-rtc-remote-image { background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; border: 1px solid #ccc; min-height: 240px; min-width: 320px; } .mce-match-marker { background: #aaa; color: #fff; } .mce-match-marker-selected { background: #39f; color: #fff; } .mce-match-marker-selected::-moz-selection { background: #39f; color: #fff; } .mce-match-marker-selected::selection { background: #39f; color: #fff; } .mce-content-body img[data-mce-selected], .mce-content-body video[data-mce-selected], .mce-content-body audio[data-mce-selected], .mce-content-body object[data-mce-selected], .mce-content-body embed[data-mce-selected], .mce-content-body table[data-mce-selected], .mce-content-body details[data-mce-selected] { outline: 3px solid #b4d7ff; } .mce-content-body hr[data-mce-selected] { outline: 3px solid #b4d7ff; outline-offset: 1px; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false][data-mce-selected] { cursor: not-allowed; outline: 3px solid #b4d7ff; } .mce-content-body.mce-content-readonly *[contentEditable=true]:focus, .mce-content-body.mce-content-readonly *[contentEditable=true]:hover { outline: none; } .mce-content-body *[data-mce-selected="inline-boundary"] { background-color: #b4d7ff; } .mce-content-body .mce-edit-focus { outline: 3px solid #b4d7ff; } .mce-content-body td[data-mce-selected], .mce-content-body th[data-mce-selected] { position: relative; } .mce-content-body td[data-mce-selected]::-moz-selection, .mce-content-body th[data-mce-selected]::-moz-selection { background: none; } .mce-content-body td[data-mce-selected]::selection, .mce-content-body th[data-mce-selected]::selection { background: none; } .mce-content-body td[data-mce-selected] *, .mce-content-body th[data-mce-selected] * { outline: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { background-color: rgba(180, 215, 255, 0.7); border: 1px solid rgba(180, 215, 255, 0.7); bottom: -1px; content: ''; left: -1px; mix-blend-mode: multiply; position: absolute; right: -1px; top: -1px; } @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { border-color: rgba(0, 84, 180, 0.7); } } .mce-content-body img[data-mce-selected]::-moz-selection { background: none; } .mce-content-body img[data-mce-selected]::selection { background: none; } .ephox-snooker-resizer-bar { background-color: #b4d7ff; opacity: 0; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .ephox-snooker-resizer-cols { cursor: col-resize; } .ephox-snooker-resizer-rows { cursor: row-resize; } .ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { opacity: 1; } .mce-spellchecker-word { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; height: 2rem; } .mce-spellchecker-grammar { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; } .mce-toc { border: 1px solid gray; } .mce-toc h2 { margin: 4px; } .mce-toc li { list-style-type: none; } [data-mce-block] { display: block; } table[style*="border-width: 0px"], .mce-item-table:not([border]), .mce-item-table[border="0"], table[style*="border-width: 0px"] td, .mce-item-table:not([border]) td, .mce-item-table[border="0"] td, table[style*="border-width: 0px"] th, .mce-item-table:not([border]) th, .mce-item-table[border="0"] th, table[style*="border-width: 0px"] caption, .mce-item-table:not([border]) caption, .mce-item-table[border="0"] caption { border: 1px dashed #bbb; } .mce-visualblocks p, .mce-visualblocks h1, .mce-visualblocks h2, .mce-visualblocks h3, .mce-visualblocks h4, .mce-visualblocks h5, .mce-visualblocks h6, .mce-visualblocks div:not([data-mce-bogus]), .mce-visualblocks section, .mce-visualblocks article, .mce-visualblocks blockquote, .mce-visualblocks address, .mce-visualblocks pre, .mce-visualblocks figure, .mce-visualblocks figcaption, .mce-visualblocks hgroup, .mce-visualblocks aside, .mce-visualblocks ul, .mce-visualblocks ol, .mce-visualblocks dl { background-repeat: no-repeat; border: 1px dashed #bbb; margin-left: 3px; padding-top: 10px; } .mce-visualblocks p { background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); } .mce-visualblocks h1 { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); } .mce-visualblocks h2 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); } .mce-visualblocks h3 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); } .mce-visualblocks h4 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); } .mce-visualblocks h5 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); } .mce-visualblocks h6 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); } .mce-visualblocks div:not([data-mce-bogus]) { background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); } .mce-visualblocks section { background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); } .mce-visualblocks article { background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); } .mce-visualblocks blockquote { background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); } .mce-visualblocks address { background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); } .mce-visualblocks pre { background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); } .mce-visualblocks figure { background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); } .mce-visualblocks figcaption { border: 1px dashed #bbb; } .mce-visualblocks hgroup { background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); } .mce-visualblocks aside { background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); } .mce-visualblocks ul { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); } .mce-visualblocks ol { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); } .mce-visualblocks dl { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); } .mce-visualblocks:not([dir=rtl]) p, .mce-visualblocks:not([dir=rtl]) h1, .mce-visualblocks:not([dir=rtl]) h2, .mce-visualblocks:not([dir=rtl]) h3, .mce-visualblocks:not([dir=rtl]) h4, .mce-visualblocks:not([dir=rtl]) h5, .mce-visualblocks:not([dir=rtl]) h6, .mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), .mce-visualblocks:not([dir=rtl]) section, .mce-visualblocks:not([dir=rtl]) article, .mce-visualblocks:not([dir=rtl]) blockquote, .mce-visualblocks:not([dir=rtl]) address, .mce-visualblocks:not([dir=rtl]) pre, .mce-visualblocks:not([dir=rtl]) figure, .mce-visualblocks:not([dir=rtl]) figcaption, .mce-visualblocks:not([dir=rtl]) hgroup, .mce-visualblocks:not([dir=rtl]) aside, .mce-visualblocks:not([dir=rtl]) ul, .mce-visualblocks:not([dir=rtl]) ol, .mce-visualblocks:not([dir=rtl]) dl { margin-left: 3px; } .mce-visualblocks[dir=rtl] p, .mce-visualblocks[dir=rtl] h1, .mce-visualblocks[dir=rtl] h2, .mce-visualblocks[dir=rtl] h3, .mce-visualblocks[dir=rtl] h4, .mce-visualblocks[dir=rtl] h5, .mce-visualblocks[dir=rtl] h6, .mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), .mce-visualblocks[dir=rtl] section, .mce-visualblocks[dir=rtl] article, .mce-visualblocks[dir=rtl] blockquote, .mce-visualblocks[dir=rtl] address, .mce-visualblocks[dir=rtl] pre, .mce-visualblocks[dir=rtl] figure, .mce-visualblocks[dir=rtl] figcaption, .mce-visualblocks[dir=rtl] hgroup, .mce-visualblocks[dir=rtl] aside, .mce-visualblocks[dir=rtl] ul, .mce-visualblocks[dir=rtl] ol, .mce-visualblocks[dir=rtl] dl { background-position-x: right; margin-right: 3px; } .mce-nbsp, .mce-shy { background: #aaa; } .mce-shy::after { content: '-'; } body { font-family: sans-serif; } table { border-collapse: collapse; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/oxide/content.inline.css ================================================ .mce-content-body .mce-item-anchor { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; } .mce-content-body .mce-item-anchor:empty { cursor: default; display: inline-block; height: 12px !important; padding: 0 2px; -webkit-user-modify: read-only; -moz-user-modify: read-only; -webkit-user-select: all; -moz-user-select: all; user-select: all; width: 8px !important; } .mce-content-body .mce-item-anchor:not(:empty) { background-position-x: 2px; display: inline-block; padding-left: 12px; } .mce-content-body .mce-item-anchor[data-mce-selected] { outline-offset: 1px; } .tox-comments-visible .tox-comment[contenteditable="false"]:not([data-mce-selected]), .tox-comments-visible span.tox-comment img:not([data-mce-selected]), .tox-comments-visible span.tox-comment > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #ffe89d; } .tox-comments-visible .tox-comment[contenteditable="false"][data-mce-annotation-active="true"]:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] img:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment:not([data-mce-selected]) { background-color: #ffe89d; outline: none; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"]:not([data-mce-selected="inline-boundary"]) { background-color: #fed635; } .tox-checklist > li:not(.tox-checklist--hidden) { list-style: none; margin: 0.25em 0; } .tox-checklist > li:not(.tox-checklist--hidden)::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); cursor: pointer; height: 1em; margin-left: -1.5em; margin-top: 0.125em; position: absolute; width: 1em; } .tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); } [dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { margin-left: 0; margin-right: -1.5em; } /* stylelint-disable */ /* http://prismjs.com/ */ /** * prism.js default theme for JavaScript, CSS and HTML * Based on dabblet (http://dabblet.com) * @author Lea Verou */ code[class*="language-"], pre[class*="language-"] { color: black; background: none; text-shadow: 0 1px white; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; font-size: 1em; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.5; -moz-tab-size: 4; tab-size: 4; -webkit-hyphens: none; hyphens: none; } pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { text-shadow: none; background: #b3d4fc; } pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection { text-shadow: none; background: #b3d4fc; } @media print { code[class*="language-"], pre[class*="language-"] { text-shadow: none; } } /* Code blocks */ pre[class*="language-"] { padding: 1em; margin: 0.5em 0; overflow: auto; } :not(pre) > code[class*="language-"], pre[class*="language-"] { background: #f5f2f0; } /* Inline code */ :not(pre) > code[class*="language-"] { padding: 0.1em; border-radius: 0.3em; white-space: normal; } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: slategray; } .token.punctuation { color: #999; } .token.namespace { opacity: 0.7; } .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: #905; } .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #690; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { color: #9a6e3a; /* This background color was intended by the author of this theme. */ background: hsla(0, 0%, 100%, 0.5); } .token.atrule, .token.attr-value, .token.keyword { color: #07a; } .token.function, .token.class-name { color: #DD4A68; } .token.regex, .token.important, .token.variable { color: #e90; } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } /* stylelint-enable */ .mce-content-body { overflow-wrap: break-word; word-wrap: break-word; } .mce-content-body .mce-visual-caret { background-color: black; background-color: currentColor; position: absolute; } .mce-content-body .mce-visual-caret-hidden { display: none; } .mce-content-body *[data-mce-caret] { left: -1000px; margin: 0; padding: 0; position: absolute; right: auto; top: 0; } .mce-content-body .mce-offscreen-selection { left: -2000000px; max-width: 1000000px; position: absolute; } .mce-content-body *[contentEditable=false] { cursor: default; } .mce-content-body *[contentEditable=true] { cursor: text; } .tox-cursor-format-painter { cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; } div.mce-footnotes hr { margin-inline-end: auto; margin-inline-start: 0; width: 25%; } div.mce-footnotes li > a.mce-footnotes-backlink { text-decoration: none; } @media print { sup.mce-footnote a { color: black; text-decoration: none; } div.mce-footnotes { break-inside: avoid; width: 100%; } div.mce-footnotes li > a.mce-footnotes-backlink { display: none; } } .mce-content-body figure.align-left { float: left; } .mce-content-body figure.align-right { float: right; } .mce-content-body figure.image.align-center { display: table; margin-left: auto; margin-right: auto; } .mce-preview-object { border: 1px solid gray; display: inline-block; line-height: 0; margin: 0 2px 0 2px; position: relative; } .mce-preview-object .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-preview-object[data-mce-selected="2"] .mce-shim { display: none; } .mce-content-body .mce-mergetag { cursor: default !important; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body .mce-mergetag:hover { background-color: rgba(0, 108, 231, 0.1); } .mce-content-body .mce-mergetag-affix { background-color: rgba(0, 108, 231, 0.1); color: #006ce7; } .mce-object { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; border: 1px dashed #aaa; } .mce-pagebreak { border: 1px dashed #aaa; cursor: default; display: block; height: 5px; margin-top: 15px; page-break-before: always; width: 100%; } @media print { .mce-pagebreak { border: 0; } } .tiny-pageembed .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tiny-pageembed[data-mce-selected="2"] .mce-shim { display: none; } .tiny-pageembed { display: inline-block; position: relative; } .tiny-pageembed--21by9, .tiny-pageembed--16by9, .tiny-pageembed--4by3, .tiny-pageembed--1by1 { display: block; overflow: hidden; padding: 0; position: relative; width: 100%; } .tiny-pageembed--21by9 { padding-top: 42.857143%; } .tiny-pageembed--16by9 { padding-top: 56.25%; } .tiny-pageembed--4by3 { padding-top: 75%; } .tiny-pageembed--1by1 { padding-top: 100%; } .tiny-pageembed--21by9 iframe, .tiny-pageembed--16by9 iframe, .tiny-pageembed--4by3 iframe, .tiny-pageembed--1by1 iframe { border: 0; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-content-body[data-mce-placeholder] { position: relative; } .mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { color: rgba(34, 47, 62, 0.7); content: attr(data-mce-placeholder); position: absolute; } .mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { left: 1px; } .mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { right: 1px; } .mce-content-body div.mce-resizehandle { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; height: 10px; position: absolute; width: 10px; z-index: 1298; } .mce-content-body div.mce-resizehandle:hover { background-color: #4099ff; } .mce-content-body div.mce-resizehandle:nth-of-type(1) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(2) { cursor: nesw-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(3) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(4) { cursor: nesw-resize; } .mce-content-body .mce-resize-backdrop { z-index: 10000; } .mce-content-body .mce-clonedresizable { cursor: default; opacity: 0.5; outline: 1px dashed black; position: absolute; z-index: 10001; } .mce-content-body .mce-clonedresizable.mce-resizetable-columns th, .mce-content-body .mce-clonedresizable.mce-resizetable-columns td { border: 0; } .mce-content-body .mce-resize-helper { background: #555; background: rgba(0, 0, 0, 0.75); border: 1px; border-radius: 3px; color: white; display: none; font-family: sans-serif; font-size: 12px; line-height: 14px; margin: 5px 10px; padding: 5px; position: absolute; white-space: nowrap; z-index: 10002; } .tox-rtc-user-selection { position: relative; } .tox-rtc-user-cursor { bottom: 0; cursor: default; position: absolute; top: 0; width: 2px; } .tox-rtc-user-cursor::before { background-color: inherit; border-radius: 50%; content: ''; display: block; height: 8px; position: absolute; right: -3px; top: -3px; width: 8px; } .tox-rtc-user-cursor:hover::after { background-color: inherit; border-radius: 100px; box-sizing: border-box; color: #fff; content: attr(data-user); display: block; font-size: 12px; font-weight: bold; left: -5px; min-height: 8px; min-width: 8px; padding: 0 12px; position: absolute; top: -11px; white-space: nowrap; z-index: 1000; } .tox-rtc-user-selection--1 .tox-rtc-user-cursor { background-color: #2dc26b; } .tox-rtc-user-selection--2 .tox-rtc-user-cursor { background-color: #e03e2d; } .tox-rtc-user-selection--3 .tox-rtc-user-cursor { background-color: #f1c40f; } .tox-rtc-user-selection--4 .tox-rtc-user-cursor { background-color: #3598db; } .tox-rtc-user-selection--5 .tox-rtc-user-cursor { background-color: #b96ad9; } .tox-rtc-user-selection--6 .tox-rtc-user-cursor { background-color: #e67e23; } .tox-rtc-user-selection--7 .tox-rtc-user-cursor { background-color: #aaa69d; } .tox-rtc-user-selection--8 .tox-rtc-user-cursor { background-color: #f368e0; } .tox-rtc-remote-image { background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; border: 1px solid #ccc; min-height: 240px; min-width: 320px; } .mce-match-marker { background: #aaa; color: #fff; } .mce-match-marker-selected { background: #39f; color: #fff; } .mce-match-marker-selected::-moz-selection { background: #39f; color: #fff; } .mce-match-marker-selected::selection { background: #39f; color: #fff; } .mce-content-body img[data-mce-selected], .mce-content-body video[data-mce-selected], .mce-content-body audio[data-mce-selected], .mce-content-body object[data-mce-selected], .mce-content-body embed[data-mce-selected], .mce-content-body table[data-mce-selected], .mce-content-body details[data-mce-selected] { outline: 3px solid #b4d7ff; } .mce-content-body hr[data-mce-selected] { outline: 3px solid #b4d7ff; outline-offset: 1px; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false][data-mce-selected] { cursor: not-allowed; outline: 3px solid #b4d7ff; } .mce-content-body.mce-content-readonly *[contentEditable=true]:focus, .mce-content-body.mce-content-readonly *[contentEditable=true]:hover { outline: none; } .mce-content-body *[data-mce-selected="inline-boundary"] { background-color: #b4d7ff; } .mce-content-body .mce-edit-focus { outline: 3px solid #b4d7ff; } .mce-content-body td[data-mce-selected], .mce-content-body th[data-mce-selected] { position: relative; } .mce-content-body td[data-mce-selected]::-moz-selection, .mce-content-body th[data-mce-selected]::-moz-selection { background: none; } .mce-content-body td[data-mce-selected]::selection, .mce-content-body th[data-mce-selected]::selection { background: none; } .mce-content-body td[data-mce-selected] *, .mce-content-body th[data-mce-selected] * { outline: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { background-color: rgba(180, 215, 255, 0.7); border: 1px solid rgba(180, 215, 255, 0.7); bottom: -1px; content: ''; left: -1px; mix-blend-mode: multiply; position: absolute; right: -1px; top: -1px; } @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { border-color: rgba(0, 84, 180, 0.7); } } .mce-content-body img[data-mce-selected]::-moz-selection { background: none; } .mce-content-body img[data-mce-selected]::selection { background: none; } .ephox-snooker-resizer-bar { background-color: #b4d7ff; opacity: 0; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .ephox-snooker-resizer-cols { cursor: col-resize; } .ephox-snooker-resizer-rows { cursor: row-resize; } .ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { opacity: 1; } .mce-spellchecker-word { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; height: 2rem; } .mce-spellchecker-grammar { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; } .mce-toc { border: 1px solid gray; } .mce-toc h2 { margin: 4px; } .mce-toc li { list-style-type: none; } [data-mce-block] { display: block; } table[style*="border-width: 0px"], .mce-item-table:not([border]), .mce-item-table[border="0"], table[style*="border-width: 0px"] td, .mce-item-table:not([border]) td, .mce-item-table[border="0"] td, table[style*="border-width: 0px"] th, .mce-item-table:not([border]) th, .mce-item-table[border="0"] th, table[style*="border-width: 0px"] caption, .mce-item-table:not([border]) caption, .mce-item-table[border="0"] caption { border: 1px dashed #bbb; } .mce-visualblocks p, .mce-visualblocks h1, .mce-visualblocks h2, .mce-visualblocks h3, .mce-visualblocks h4, .mce-visualblocks h5, .mce-visualblocks h6, .mce-visualblocks div:not([data-mce-bogus]), .mce-visualblocks section, .mce-visualblocks article, .mce-visualblocks blockquote, .mce-visualblocks address, .mce-visualblocks pre, .mce-visualblocks figure, .mce-visualblocks figcaption, .mce-visualblocks hgroup, .mce-visualblocks aside, .mce-visualblocks ul, .mce-visualblocks ol, .mce-visualblocks dl { background-repeat: no-repeat; border: 1px dashed #bbb; margin-left: 3px; padding-top: 10px; } .mce-visualblocks p { background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); } .mce-visualblocks h1 { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); } .mce-visualblocks h2 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); } .mce-visualblocks h3 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); } .mce-visualblocks h4 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); } .mce-visualblocks h5 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); } .mce-visualblocks h6 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); } .mce-visualblocks div:not([data-mce-bogus]) { background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); } .mce-visualblocks section { background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); } .mce-visualblocks article { background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); } .mce-visualblocks blockquote { background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); } .mce-visualblocks address { background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); } .mce-visualblocks pre { background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); } .mce-visualblocks figure { background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); } .mce-visualblocks figcaption { border: 1px dashed #bbb; } .mce-visualblocks hgroup { background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); } .mce-visualblocks aside { background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); } .mce-visualblocks ul { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); } .mce-visualblocks ol { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); } .mce-visualblocks dl { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); } .mce-visualblocks:not([dir=rtl]) p, .mce-visualblocks:not([dir=rtl]) h1, .mce-visualblocks:not([dir=rtl]) h2, .mce-visualblocks:not([dir=rtl]) h3, .mce-visualblocks:not([dir=rtl]) h4, .mce-visualblocks:not([dir=rtl]) h5, .mce-visualblocks:not([dir=rtl]) h6, .mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), .mce-visualblocks:not([dir=rtl]) section, .mce-visualblocks:not([dir=rtl]) article, .mce-visualblocks:not([dir=rtl]) blockquote, .mce-visualblocks:not([dir=rtl]) address, .mce-visualblocks:not([dir=rtl]) pre, .mce-visualblocks:not([dir=rtl]) figure, .mce-visualblocks:not([dir=rtl]) figcaption, .mce-visualblocks:not([dir=rtl]) hgroup, .mce-visualblocks:not([dir=rtl]) aside, .mce-visualblocks:not([dir=rtl]) ul, .mce-visualblocks:not([dir=rtl]) ol, .mce-visualblocks:not([dir=rtl]) dl { margin-left: 3px; } .mce-visualblocks[dir=rtl] p, .mce-visualblocks[dir=rtl] h1, .mce-visualblocks[dir=rtl] h2, .mce-visualblocks[dir=rtl] h3, .mce-visualblocks[dir=rtl] h4, .mce-visualblocks[dir=rtl] h5, .mce-visualblocks[dir=rtl] h6, .mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), .mce-visualblocks[dir=rtl] section, .mce-visualblocks[dir=rtl] article, .mce-visualblocks[dir=rtl] blockquote, .mce-visualblocks[dir=rtl] address, .mce-visualblocks[dir=rtl] pre, .mce-visualblocks[dir=rtl] figure, .mce-visualblocks[dir=rtl] figcaption, .mce-visualblocks[dir=rtl] hgroup, .mce-visualblocks[dir=rtl] aside, .mce-visualblocks[dir=rtl] ul, .mce-visualblocks[dir=rtl] ol, .mce-visualblocks[dir=rtl] dl { background-position-x: right; margin-right: 3px; } .mce-nbsp, .mce-shy { background: #aaa; } .mce-shy::after { content: '-'; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/oxide/skin.css ================================================ .tox { box-shadow: none; box-sizing: content-box; color: #222f3e; cursor: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; font-style: normal; font-weight: normal; line-height: normal; -webkit-tap-highlight-color: transparent; text-decoration: none; text-shadow: none; text-transform: none; vertical-align: initial; white-space: normal; } .tox *:not(svg):not(rect) { box-sizing: inherit; color: inherit; cursor: inherit; direction: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; -webkit-tap-highlight-color: inherit; text-align: inherit; text-decoration: inherit; text-shadow: inherit; text-transform: inherit; vertical-align: inherit; white-space: inherit; } .tox *:not(svg):not(rect) { /* stylelint-disable-line no-duplicate-selectors */ background: transparent; border: 0; box-shadow: none; float: none; height: auto; margin: 0; max-width: none; outline: 0; padding: 0; position: static; width: auto; } .tox:not([dir=rtl]) { direction: ltr; text-align: left; } .tox[dir=rtl] { direction: rtl; text-align: right; } .tox-tinymce { border: 2px solid #eeeeee; border-radius: 10px; box-shadow: none; box-sizing: border-box; display: flex; flex-direction: column; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; overflow: hidden; position: relative; visibility: inherit !important; } .tox.tox-tinymce-inline { border: none; box-shadow: none; overflow: initial; } .tox.tox-tinymce-inline .tox-editor-container { overflow: initial; } .tox.tox-tinymce-inline .tox-editor-header { background-color: #fff; border: 2px solid #eeeeee; border-radius: 10px; box-shadow: none; overflow: hidden; } .tox-tinymce-aux { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; z-index: 1300; } .tox-tinymce *:focus, .tox-tinymce-aux *:focus { outline: none; } button::-moz-focus-inner { border: 0; } .tox[dir=rtl] .tox-icon--flip svg { transform: rotateY(180deg); } .tox .accessibility-issue__header { align-items: center; display: flex; margin-bottom: 4px; } .tox .accessibility-issue__description { align-items: stretch; border-radius: 6px; display: flex; justify-content: space-between; } .tox .accessibility-issue__description > div { padding-bottom: 4px; } .tox .accessibility-issue__description > div > div { align-items: center; display: flex; margin-bottom: 4px; } .tox .accessibility-issue__description > div > div .tox-icon svg { display: block; } .tox .accessibility-issue__repair { margin-top: 16px; } .tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { background-color: rgba(0, 101, 216, 0.1); color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { color: #006ce7; } .tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { fill: #006ce7; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon { background-color: #006ce7; color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus { background-color: #0060ce; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active { background-color: #0054b4; } .tox .tox-dialog__body-content .accessibility-issue--warn { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { background-color: rgba(255, 165, 0, 0.08); color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { color: #8f5d00; } .tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { fill: #8f5d00; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon { background-color: #FFE89D; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus { background-color: #F2D574; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active { background-color: #E8C657; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { background-color: rgba(204, 0, 0, 0.1); color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { color: #c00; } .tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { fill: #c00; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon { background-color: #F2BFBF; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus { background-color: #E9A4A4; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active { background-color: #EE9494; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { background-color: rgba(120, 171, 70, 0.1); color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > *:last-child { display: none; } .tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { color: #527530; } .tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { fill: #527530; } .tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1, .tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { font-size: 14px; margin-top: 0; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button { margin-left: 4px; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { margin-left: auto; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description { padding: 4px 4px 4px 8px; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button { margin-right: 4px; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { margin-right: auto; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description { padding: 4px 8px 4px 4px; } .tox .tox-advtemplate .tox-form__grid { flex: 1; } .tox .tox-advtemplate .tox-form__grid > div:first-child { display: flex; flex-direction: column; width: 30%; } .tox .tox-advtemplate .tox-form__grid > div:first-child > div:nth-child(2) { flex-basis: 0; flex-grow: 1; overflow: auto; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid > div:first-child { width: 100%; } } .tox .tox-advtemplate iframe { border-color: #eeeeee; border-radius: 10px; border-style: solid; border-width: 1px; margin: 0 10px; } .tox .tox-anchorbar { display: flex; flex: 0 0 auto; } .tox .tox-bottom-anchorbar { display: flex; flex: 0 0 auto; } .tox .tox-bar { display: flex; flex: 0 0 auto; } .tox .tox-button { background-color: #006ce7; background-image: none; background-position: 0 0; background-repeat: repeat; border-color: #006ce7; border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #fff; cursor: pointer; display: inline-block; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 14px; font-style: normal; font-weight: bold; letter-spacing: normal; line-height: 24px; margin: 0; outline: none; padding: 4px 16px; position: relative; text-align: center; text-decoration: none; text-transform: none; white-space: nowrap; } .tox .tox-button::before { border-radius: 6px; bottom: -1px; box-shadow: inset 0 0 0 2px #fff, 0 0 0 1px #006ce7, 0 0 0 3px rgba(0, 108, 231, 0.25); content: ''; left: -1px; opacity: 0; pointer-events: none; position: absolute; right: -1px; top: -1px; } .tox .tox-button[disabled] { background-color: #006ce7; background-image: none; border-color: #006ce7; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-button:focus:not(:disabled) { background-color: #0060ce; background-image: none; border-color: #0060ce; box-shadow: none; color: #fff; } .tox .tox-button:focus-visible:not(:disabled)::before { opacity: 1; } .tox .tox-button:hover:not(:disabled) { background-color: #0060ce; background-image: none; border-color: #0060ce; box-shadow: none; color: #fff; } .tox .tox-button:active:not(:disabled) { background-color: #0054b4; background-image: none; border-color: #0054b4; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled { background-color: #0054b4; background-image: none; border-color: #0054b4; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled[disabled] { background-color: #0054b4; background-image: none; border-color: #0054b4; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-button.tox-button--enabled:focus:not(:disabled) { background-color: #00489b; background-image: none; border-color: #00489b; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled:hover:not(:disabled) { background-color: #00489b; background-image: none; border-color: #00489b; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled:active:not(:disabled) { background-color: #003c81; background-image: none; border-color: #003c81; box-shadow: none; color: #fff; } .tox .tox-button--icon-and-text, .tox .tox-button.tox-button--icon-and-text, .tox .tox-button.tox-button--secondary.tox-button--icon-and-text { display: flex; padding: 5px 4px; } .tox .tox-button--icon-and-text .tox-icon svg, .tox .tox-button.tox-button--icon-and-text .tox-icon svg, .tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg { display: block; fill: currentColor; } .tox .tox-button--secondary { background-color: #f0f0f0; background-image: none; background-position: 0 0; background-repeat: repeat; border-color: #f0f0f0; border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; color: #222f3e; font-size: 14px; font-style: normal; font-weight: bold; letter-spacing: normal; outline: none; padding: 4px 16px; text-decoration: none; text-transform: none; } .tox .tox-button--secondary[disabled] { background-color: #f0f0f0; background-image: none; border-color: #f0f0f0; box-shadow: none; color: rgba(34, 47, 62, 0.5); } .tox .tox-button--secondary:focus:not(:disabled) { background-color: #e3e3e3; background-image: none; border-color: #e3e3e3; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary:hover:not(:disabled) { background-color: #e3e3e3; background-image: none; border-color: #e3e3e3; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary:active:not(:disabled) { background-color: #d6d6d6; background-image: none; border-color: #d6d6d6; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary.tox-button--enabled { background-color: #a8c8ed; background-image: none; border-color: #a8c8ed; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary.tox-button--enabled[disabled] { background-color: #a8c8ed; background-image: none; border-color: #a8c8ed; box-shadow: none; color: rgba(34, 47, 62, 0.5); } .tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled) { background-color: #93bbe9; background-image: none; border-color: #93bbe9; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled) { background-color: #93bbe9; background-image: none; border-color: #93bbe9; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary.tox-button--enabled:active:not(:disabled) { background-color: #7daee4; background-image: none; border-color: #7daee4; box-shadow: none; color: #222f3e; } .tox .tox-button--icon, .tox .tox-button.tox-button--icon, .tox .tox-button.tox-button--secondary.tox-button--icon { padding: 4px; } .tox .tox-button--icon .tox-icon svg, .tox .tox-button.tox-button--icon .tox-icon svg, .tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { display: block; fill: currentColor; } .tox .tox-button-link { background: 0; border: none; box-sizing: border-box; cursor: pointer; display: inline-block; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; font-weight: normal; line-height: 1.3; margin: 0; padding: 0; white-space: nowrap; } .tox .tox-button-link--sm { font-size: 14px; } .tox .tox-button--naked { background-color: transparent; border-color: transparent; box-shadow: unset; color: #222f3e; } .tox .tox-button--naked[disabled] { background-color: rgba(34, 47, 62, 0.12); border-color: transparent; box-shadow: unset; color: rgba(34, 47, 62, 0.5); } .tox .tox-button--naked:hover:not(:disabled) { background-color: rgba(34, 47, 62, 0.12); border-color: transparent; box-shadow: unset; color: #222f3e; } .tox .tox-button--naked:focus:not(:disabled) { background-color: rgba(34, 47, 62, 0.12); border-color: transparent; box-shadow: unset; color: #222f3e; } .tox .tox-button--naked:active:not(:disabled) { background-color: rgba(34, 47, 62, 0.18); border-color: transparent; box-shadow: unset; color: #222f3e; } .tox .tox-button--naked .tox-icon svg { fill: currentColor; } .tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { color: #222f3e; } .tox .tox-checkbox { align-items: center; border-radius: 6px; cursor: pointer; display: flex; height: 36px; min-width: 36px; } .tox .tox-checkbox__input { /* Hide from view but visible to screen readers */ height: 1px; overflow: hidden; position: absolute; top: auto; width: 1px; } .tox .tox-checkbox__icons { align-items: center; border-radius: 6px; box-shadow: 0 0 0 2px transparent; box-sizing: content-box; display: flex; height: 24px; justify-content: center; padding: calc(4px - 1px); width: 24px; } .tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: block; fill: rgba(34, 47, 62, 0.3); } .tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { display: none; fill: #006ce7; } .tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { display: none; fill: #006ce7; } .tox .tox-checkbox--disabled { color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { fill: rgba(34, 47, 62, 0.5); } .tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: none; } .tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { display: block; } .tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: none; } .tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { display: block; } .tox input.tox-checkbox__input:focus + .tox-checkbox__icons { border-radius: 6px; box-shadow: inset 0 0 0 1px #006ce7; padding: calc(4px - 1px); } .tox:not([dir=rtl]) .tox-checkbox__label { margin-left: 4px; } .tox:not([dir=rtl]) .tox-checkbox__input { left: -10000px; } .tox:not([dir=rtl]) .tox-bar .tox-checkbox { margin-left: 4px; } .tox[dir=rtl] .tox-checkbox__label { margin-right: 4px; } .tox[dir=rtl] .tox-checkbox__input { right: -10000px; } .tox[dir=rtl] .tox-bar .tox-checkbox { margin-right: 4px; } .tox { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-collection--toolbar .tox-collection__group { display: flex; padding: 0; } .tox .tox-collection--grid .tox-collection__group { display: flex; flex-wrap: wrap; max-height: 208px; overflow-x: hidden; overflow-y: auto; padding: 0; } .tox .tox-collection--list .tox-collection__group { border-bottom-width: 0; border-color: #e3e3e3; border-left-width: 0; border-right-width: 0; border-style: solid; border-top-width: 1px; padding: 4px 0; } .tox .tox-collection--list .tox-collection__group:first-child { border-top-width: 0; } .tox .tox-collection__group-heading { background-color: #fcfcfc; color: rgba(34, 47, 62, 0.7); cursor: default; font-size: 12px; font-style: normal; font-weight: normal; margin-bottom: 4px; margin-top: -4px; padding: 4px 8px; text-transform: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .tox .tox-collection__item { align-items: center; border-radius: 3px; color: #222f3e; display: flex; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .tox .tox-collection--list .tox-collection__item { padding: 4px 8px; } .tox .tox-collection--toolbar .tox-collection__item { border-radius: 3px; padding: 4px; } .tox .tox-collection--grid .tox-collection__item { border-radius: 3px; padding: 4px; } .tox .tox-collection--list .tox-collection__item--enabled { background-color: #fff; color: #222f3e; } .tox .tox-collection--list .tox-collection__item--active { background-color: #cce2fa; } .tox .tox-collection--toolbar .tox-collection__item--enabled { background-color: #a6ccf7; color: #222f3e; } .tox .tox-collection--toolbar .tox-collection__item--active { background-color: #cce2fa; } .tox .tox-collection--grid .tox-collection__item--enabled { background-color: #a6ccf7; color: #222f3e; } .tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { background-color: #cce2fa; color: #222f3e; } .tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { color: #222f3e; } .tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { color: #222f3e; } .tox .tox-collection__item-icon, .tox .tox-collection__item-checkmark { align-items: center; display: flex; height: 24px; justify-content: center; width: 24px; } .tox .tox-collection__item-icon svg, .tox .tox-collection__item-checkmark svg { fill: currentColor; } .tox .tox-collection--toolbar-lg .tox-collection__item-icon { height: 48px; width: 48px; } .tox .tox-collection__item-label { color: currentColor; display: inline-block; flex: 1; font-size: 14px; font-style: normal; font-weight: normal; line-height: 24px; text-transform: none; word-break: break-all; } .tox .tox-collection__item-accessory { color: rgba(34, 47, 62, 0.7); display: inline-block; font-size: 14px; height: 24px; line-height: 24px; text-transform: none; } .tox .tox-collection__item-caret { align-items: center; display: flex; min-height: 24px; } .tox .tox-collection__item-caret::after { content: ''; font-size: 0; min-height: inherit; } .tox .tox-collection__item-caret svg { fill: #222f3e; } .tox .tox-collection__item--state-disabled { background-color: transparent; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg { display: none; } .tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory + .tox-collection__item-checkmark { display: none; } .tox .tox-collection--horizontal { background-color: #fff; border: 1px solid #e3e3e3; border-radius: 6px; box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: nowrap; margin-bottom: 0; overflow-x: auto; padding: 0; } .tox .tox-collection--horizontal .tox-collection__group { align-items: center; display: flex; flex-wrap: nowrap; margin: 0; padding: 0 4px; } .tox .tox-collection--horizontal .tox-collection__item { height: 28px; margin: 6px 1px 5px 0; padding: 0 4px; } .tox .tox-collection--horizontal .tox-collection__item-label { white-space: nowrap; } .tox .tox-collection--horizontal .tox-collection__item-caret { margin-left: 4px; } .tox .tox-collection__item-container { display: flex; } .tox .tox-collection__item-container--row { align-items: center; flex: 1 1 auto; flex-direction: row; } .tox .tox-collection__item-container--row.tox-collection__item-container--align-left { margin-right: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--align-right { justify-content: flex-end; margin-left: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { align-items: flex-start; margin-bottom: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { align-items: center; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { align-items: flex-end; margin-top: auto; } .tox .tox-collection__item-container--column { align-self: center; flex: 1 1 auto; flex-direction: column; } .tox .tox-collection__item-container--column.tox-collection__item-container--align-left { align-items: flex-start; } .tox .tox-collection__item-container--column.tox-collection__item-container--align-right { align-items: flex-end; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { align-self: flex-start; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { align-self: center; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { align-self: flex-end; } .tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { border-right: 1px solid transparent; } .tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > *:not(:first-child) { margin-left: 8px; } .tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { margin-left: 4px; } .tox:not([dir=rtl]) .tox-collection__item-accessory { margin-left: 16px; text-align: right; } .tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret { margin-left: 16px; } .tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { border-left: 1px solid transparent; } .tox[dir=rtl] .tox-collection--list .tox-collection__item > *:not(:first-child) { margin-right: 8px; } .tox[dir=rtl] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { margin-right: 4px; } .tox[dir=rtl] .tox-collection__item-accessory { margin-right: 16px; text-align: left; } .tox[dir=rtl] .tox-collection .tox-collection__item-caret { margin-right: 16px; transform: rotateY(180deg); } .tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret { margin-right: 4px; } .tox .tox-color-picker-container { display: flex; flex-direction: row; height: 225px; margin: 0; } .tox .tox-sv-palette { box-sizing: border-box; display: flex; height: 100%; } .tox .tox-sv-palette-spectrum { height: 100%; } .tox .tox-sv-palette, .tox .tox-sv-palette-spectrum { width: 225px; } .tox .tox-sv-palette-thumb { background: none; border: 1px solid black; border-radius: 50%; box-sizing: content-box; height: 12px; position: absolute; width: 12px; } .tox .tox-sv-palette-inner-thumb { border: 1px solid white; border-radius: 50%; height: 10px; position: absolute; width: 10px; } .tox .tox-hue-slider { box-sizing: border-box; height: 100%; width: 25px; } .tox .tox-hue-slider-spectrum { background: linear-gradient(to bottom, #f00, #ff0080, #f0f, #8000ff, #00f, #0080ff, #0ff, #00ff80, #0f0, #80ff00, #ff0, #ff8000, #f00); height: 100%; width: 100%; } .tox .tox-hue-slider, .tox .tox-hue-slider-spectrum { width: 20px; } .tox .tox-hue-slider-thumb { background: white; border: 1px solid black; box-sizing: content-box; height: 4px; width: 100%; } .tox .tox-rgb-form { display: flex; flex-direction: column; justify-content: space-between; } .tox .tox-rgb-form div { align-items: center; display: flex; justify-content: space-between; margin-bottom: 5px; width: inherit; } .tox .tox-rgb-form input { width: 6em; } .tox .tox-rgb-form input.tox-invalid { /* Need !important to override Chrome's focus styling unfortunately */ border: 1px solid red !important; } .tox .tox-rgb-form .tox-rgba-preview { border: 1px solid black; flex-grow: 2; margin-bottom: 0; } .tox:not([dir=rtl]) .tox-sv-palette { margin-right: 15px; } .tox:not([dir=rtl]) .tox-hue-slider { margin-right: 15px; } .tox:not([dir=rtl]) .tox-hue-slider-thumb { margin-left: -1px; } .tox:not([dir=rtl]) .tox-rgb-form label { margin-right: 0.5em; } .tox[dir=rtl] .tox-sv-palette { margin-left: 15px; } .tox[dir=rtl] .tox-hue-slider { margin-left: 15px; } .tox[dir=rtl] .tox-hue-slider-thumb { margin-right: -1px; } .tox[dir=rtl] .tox-rgb-form label { margin-left: 0.5em; } .tox .tox-toolbar .tox-swatches, .tox .tox-toolbar__primary .tox-swatches, .tox .tox-toolbar__overflow .tox-swatches { margin: 5px 0 6px 11px; } .tox .tox-collection--list .tox-collection__group .tox-swatches-menu { border: 0; margin: -4px -4px; } .tox .tox-swatches__row { display: flex; } .tox .tox-swatch { height: 30px; transition: transform 0.15s, box-shadow 0.15s; width: 30px; } .tox .tox-swatch:hover, .tox .tox-swatch:focus { box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; transform: scale(0.8); } .tox .tox-swatch--remove { align-items: center; display: flex; justify-content: center; } .tox .tox-swatch--remove svg path { stroke: #e74c3c; } .tox .tox-swatches__picker-btn { align-items: center; background-color: transparent; border: 0; cursor: pointer; display: flex; height: 30px; justify-content: center; outline: none; padding: 0; width: 30px; } .tox .tox-swatches__picker-btn svg { fill: #222f3e; height: 24px; width: 24px; } .tox .tox-swatches__picker-btn:hover { background: #cce2fa; } .tox div.tox-swatch:not(.tox-swatch--remove) svg { display: none; fill: #222f3e; height: 24px; margin: calc((30px - 24px) / 2) calc((30px - 24px) / 2); width: 24px; } .tox div.tox-swatch:not(.tox-swatch--remove) svg path { fill: #fff; paint-order: stroke; stroke: #222f3e; stroke-width: 2px; } .tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg { display: block; } .tox:not([dir=rtl]) .tox-swatches__picker-btn { margin-left: auto; } .tox[dir=rtl] .tox-swatches__picker-btn { margin-right: auto; } .tox .tox-comment-thread { background: #fff; position: relative; } .tox .tox-comment-thread > *:not(:first-child) { margin-top: 8px; } .tox .tox-comment { background: #fff; border: 1px solid #eeeeee; border-radius: 6px; box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); padding: 8px 8px 16px 8px; position: relative; } .tox .tox-comment__header { align-items: center; color: #222f3e; display: flex; justify-content: space-between; } .tox .tox-comment__date { color: #222f3e; font-size: 12px; line-height: 18px; } .tox .tox-comment__body { color: #222f3e; font-size: 14px; font-style: normal; font-weight: normal; line-height: 1.3; margin-top: 8px; position: relative; text-transform: initial; } .tox .tox-comment__body textarea { resize: none; white-space: normal; width: 100%; } .tox .tox-comment__expander { padding-top: 8px; } .tox .tox-comment__expander p { color: rgba(34, 47, 62, 0.7); font-size: 14px; font-style: normal; } .tox .tox-comment__body p { margin: 0; } .tox .tox-comment__buttonspacing { padding-top: 16px; text-align: center; } .tox .tox-comment-thread__overlay::after { background: #fff; bottom: 0; content: ""; display: flex; left: 0; opacity: 0.9; position: absolute; right: 0; top: 0; z-index: 5; } .tox .tox-comment__reply { display: flex; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; margin-top: 8px; } .tox .tox-comment__reply > *:first-child { margin-bottom: 8px; width: 100%; } .tox .tox-comment__edit { display: flex; flex-wrap: wrap; justify-content: flex-end; margin-top: 16px; } .tox .tox-comment__gradient::after { background: linear-gradient(rgba(255, 255, 255, 0), #fff); bottom: 0; content: ""; display: block; height: 5em; margin-top: -40px; position: absolute; width: 100%; } .tox .tox-comment__overlay { background: #fff; bottom: 0; display: flex; flex-direction: column; flex-grow: 1; left: 0; opacity: 0.9; position: absolute; right: 0; text-align: center; top: 0; z-index: 5; } .tox .tox-comment__loading-text { align-items: center; color: #222f3e; display: flex; flex-direction: column; position: relative; } .tox .tox-comment__loading-text > div { padding-bottom: 16px; } .tox .tox-comment__overlaytext { bottom: 0; flex-direction: column; font-size: 14px; left: 0; padding: 1em; position: absolute; right: 0; top: 0; z-index: 10; } .tox .tox-comment__overlaytext p { background-color: #fff; box-shadow: 0 0 8px 8px #fff; color: #222f3e; text-align: center; } .tox .tox-comment__overlaytext div:nth-of-type(2) { font-size: 0.8em; } .tox .tox-comment__busy-spinner { align-items: center; background-color: #fff; bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; z-index: 20; } .tox .tox-comment__scroll { display: flex; flex-direction: column; flex-shrink: 1; overflow: auto; } .tox .tox-conversations { margin: 8px; } .tox:not([dir=rtl]) .tox-comment__edit { margin-left: 8px; } .tox:not([dir=rtl]) .tox-comment__buttonspacing > *:last-child, .tox:not([dir=rtl]) .tox-comment__edit > *:last-child, .tox:not([dir=rtl]) .tox-comment__reply > *:last-child { margin-left: 8px; } .tox[dir=rtl] .tox-comment__edit { margin-right: 8px; } .tox[dir=rtl] .tox-comment__buttonspacing > *:last-child, .tox[dir=rtl] .tox-comment__edit > *:last-child, .tox[dir=rtl] .tox-comment__reply > *:last-child { margin-right: 8px; } .tox .tox-user { align-items: center; display: flex; } .tox .tox-user__avatar svg { fill: rgba(34, 47, 62, 0.7); } .tox .tox-user__avatar img { border-radius: 50%; height: 36px; object-fit: cover; vertical-align: middle; width: 36px; } .tox .tox-user__name { color: #222f3e; font-size: 14px; font-style: normal; font-weight: bold; line-height: 18px; text-transform: none; } .tox:not([dir=rtl]) .tox-user__avatar svg, .tox:not([dir=rtl]) .tox-user__avatar img { margin-right: 8px; } .tox:not([dir=rtl]) .tox-user__avatar + .tox-user__name { margin-left: 8px; } .tox[dir=rtl] .tox-user__avatar svg, .tox[dir=rtl] .tox-user__avatar img { margin-left: 8px; } .tox[dir=rtl] .tox-user__avatar + .tox-user__name { margin-right: 8px; } .tox .tox-dialog-wrap { align-items: center; bottom: 0; display: flex; justify-content: center; left: 0; position: fixed; right: 0; top: 0; z-index: 1100; } .tox .tox-dialog-wrap__backdrop { background-color: rgba(255, 255, 255, 0.75); bottom: 0; left: 0; position: absolute; right: 0; top: 0; z-index: 1; } .tox .tox-dialog-wrap__backdrop--opaque { background-color: #fff; } .tox .tox-dialog { background-color: #fff; border-color: #eeeeee; border-radius: 10px; border-style: solid; border-width: 0px; box-shadow: 0 16px 16px -10px rgba(34, 47, 62, 0.15), 0 0 40px 1px rgba(34, 47, 62, 0.15); display: flex; flex-direction: column; max-height: 100%; max-width: 480px; overflow: hidden; position: relative; width: 95vw; z-index: 2; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog { align-self: flex-start; margin: 8px auto; max-height: calc(100vh - 8px * 2); width: calc(100vw - 16px); } } .tox .tox-dialog-inline { z-index: 1100; } .tox .tox-dialog__header { align-items: center; background-color: #fff; border-bottom: none; color: #222f3e; display: flex; font-size: 16px; justify-content: space-between; padding: 8px 16px 0 16px; position: relative; } .tox .tox-dialog__header .tox-button { z-index: 1; } .tox .tox-dialog__draghandle { cursor: grab; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tox .tox-dialog__draghandle:active { cursor: grabbing; } .tox .tox-dialog__dismiss { margin-left: auto; } .tox .tox-dialog__title { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 20px; font-style: normal; font-weight: normal; line-height: 1.3; margin: 0; text-transform: none; } .tox .tox-dialog__body { color: #222f3e; display: flex; flex: 1; font-size: 16px; font-style: normal; font-weight: normal; line-height: 1.3; min-width: 0; text-align: left; text-transform: none; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog__body { flex-direction: column; } } .tox .tox-dialog__body-nav { align-items: flex-start; display: flex; flex-direction: column; flex-shrink: 0; padding: 16px 16px; } @media only screen and (min-width: 768px ) { .tox .tox-dialog__body-nav { max-width: 11em; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { flex-direction: row; -webkit-overflow-scrolling: touch; overflow-x: auto; padding-bottom: 0; } } .tox .tox-dialog__body-nav-item { border-bottom: 2px solid transparent; color: rgba(34, 47, 62, 0.7); display: inline-block; flex-shrink: 0; font-size: 14px; line-height: 1.3; margin-bottom: 8px; max-width: 13em; text-decoration: none; } .tox .tox-dialog__body-nav-item:focus { background-color: rgba(0, 108, 231, 0.1); } .tox .tox-dialog__body-nav-item--active { border-bottom: 2px solid #006ce7; color: #006ce7; } .tox .tox-dialog__body-content { box-sizing: border-box; display: flex; flex: 1; flex-direction: column; max-height: min(650px, calc(100vh - 110px)); overflow: auto; -webkit-overflow-scrolling: touch; padding: 16px 16px; } .tox .tox-dialog__body-content > * { margin-bottom: 0; margin-top: 16px; } .tox .tox-dialog__body-content > *:first-child { margin-top: 0; } .tox .tox-dialog__body-content > *:last-child { margin-bottom: 0; } .tox .tox-dialog__body-content > *:only-child { margin-bottom: 0; margin-top: 0; } .tox .tox-dialog__body-content a { color: #006ce7; cursor: pointer; text-decoration: none; } .tox .tox-dialog__body-content a:hover, .tox .tox-dialog__body-content a:focus { color: #0054b4; text-decoration: none; } .tox .tox-dialog__body-content a:active { color: #0054b4; text-decoration: none; } .tox .tox-dialog__body-content svg { fill: #222f3e; } .tox .tox-dialog__body-content strong { font-weight: bold; } .tox .tox-dialog__body-content ul { list-style-type: disc; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dd { padding-inline-start: 2.5rem; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dl { margin-bottom: 16px; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dl, .tox .tox-dialog__body-content dd, .tox .tox-dialog__body-content dt { display: block; margin-inline-end: 0; margin-inline-start: 0; } .tox .tox-dialog__body-content .tox-form__group h1 { color: #222f3e; font-size: 20px; font-style: normal; font-weight: bold; letter-spacing: normal; margin-bottom: 16px; margin-top: 2rem; text-transform: none; } .tox .tox-dialog__body-content .tox-form__group h2 { color: #222f3e; font-size: 16px; font-style: normal; font-weight: bold; letter-spacing: normal; margin-bottom: 16px; margin-top: 2rem; text-transform: none; } .tox .tox-dialog__body-content .tox-form__group p { margin-bottom: 16px; } .tox .tox-dialog__body-content .tox-form__group h1:first-child, .tox .tox-dialog__body-content .tox-form__group h2:first-child, .tox .tox-dialog__body-content .tox-form__group p:first-child { margin-top: 0; } .tox .tox-dialog__body-content .tox-form__group h1:last-child, .tox .tox-dialog__body-content .tox-form__group h2:last-child, .tox .tox-dialog__body-content .tox-form__group p:last-child { margin-bottom: 0; } .tox .tox-dialog__body-content .tox-form__group h1:only-child, .tox .tox-dialog__body-content .tox-form__group h2:only-child, .tox .tox-dialog__body-content .tox-form__group p:only-child { margin-bottom: 0; margin-top: 0; } .tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center { text-align: center; } .tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end { text-align: end; } .tox .tox-dialog--width-lg { height: 650px; max-width: 1200px; } .tox .tox-dialog--fullscreen { height: 100%; max-width: 100%; } .tox .tox-dialog--fullscreen .tox-dialog__body-content { max-height: 100%; } .tox .tox-dialog--width-md { max-width: 800px; } .tox .tox-dialog--width-md .tox-dialog__body-content { overflow: auto; } .tox .tox-dialog__body-content--centered { text-align: center; } .tox .tox-dialog__footer { align-items: center; background-color: #fff; border-top: none; display: flex; justify-content: space-between; padding: 8px 16px; } .tox .tox-dialog__footer-start, .tox .tox-dialog__footer-end { display: flex; } .tox .tox-dialog__busy-spinner { align-items: center; background-color: rgba(255, 255, 255, 0.75); bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; z-index: 3; } .tox .tox-dialog__table { border-collapse: collapse; width: 100%; } .tox .tox-dialog__table thead th { font-weight: bold; padding-bottom: 8px; } .tox .tox-dialog__table thead th:first-child { padding-right: 8px; } .tox .tox-dialog__table tbody tr { border-bottom: 1px solid #626262; } .tox .tox-dialog__table tbody tr:last-child { border-bottom: none; } .tox .tox-dialog__table td { padding-bottom: 8px; padding-top: 8px; } .tox .tox-dialog__table td:first-child { padding-right: 8px; } .tox .tox-dialog__iframe { min-height: 200px; } .tox .tox-dialog__iframe.tox-dialog__iframe--opaque { background: #fff; } .tox .tox-dialog__iframe.tox-dialog__iframe--bordered { border: 1px solid #eeeeee; border-radius: 6px; } .tox .tox-dialog__popups { position: absolute; width: 100%; z-index: 1100; } .tox .tox-dialog__body-iframe { display: flex; flex: 1; flex-direction: column; } .tox .tox-dialog__body-iframe .tox-navobj { display: flex; flex: 1; } .tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { flex: 1; height: 100%; } .tox .tox-dialog-dock-fadeout { opacity: 0; visibility: hidden; } .tox .tox-dialog-dock-fadein { opacity: 1; visibility: visible; } .tox .tox-dialog-dock-transition { transition: visibility 0s linear 0.3s, opacity 0.3s ease; } .tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { transition-delay: 0s; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav { margin-right: 0; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child) { margin-left: 8px; } } .tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start > *, .tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end > * { margin-left: 8px; } .tox[dir=rtl] .tox-dialog__body { text-align: right; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav { margin-left: 0; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child) { margin-right: 8px; } } .tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start > *, .tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end > * { margin-right: 8px; } body.tox-dialog__disable-scroll { overflow: hidden; } .tox .tox-dropzone-container { display: flex; flex: 1; } .tox .tox-dropzone { align-items: center; background: #fff; border: 2px dashed #eeeeee; box-sizing: border-box; display: flex; flex-direction: column; flex-grow: 1; justify-content: center; min-height: 100px; padding: 10px; } .tox .tox-dropzone p { color: rgba(34, 47, 62, 0.7); margin: 0 0 16px 0; } .tox .tox-edit-area { display: flex; flex: 1; overflow: hidden; position: relative; } .tox .tox-edit-area::before { border: 2px solid #2D6ADF; border-radius: 4px; content: ''; inset: 0; opacity: 0; pointer-events: none; position: absolute; transition: opacity 0.15s; z-index: 1; } .tox .tox-edit-area__iframe { background-color: #fff; border: 0; box-sizing: border-box; flex: 1; height: 100%; position: absolute; width: 100%; } .tox.tox-edit-focus .tox-edit-area::before { opacity: 1; } .tox.tox-inline-edit-area { border: 1px dotted #eeeeee; } .tox .tox-editor-container { display: flex; flex: 1 1 auto; flex-direction: column; overflow: hidden; } .tox .tox-editor-header { display: grid; grid-template-columns: 1fr min-content; z-index: 2; } .tox:not(.tox-tinymce-inline) .tox-editor-header { background-color: #fff; border-bottom: none; box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.1), 0 8px 8px -4px rgba(34, 47, 62, 0.07); padding: 4px 0; } .tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition) { transition: box-shadow 0.5s; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { border-top: 1px solid #e3e3e3; box-shadow: none; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { background-color: #fff; box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.2), 0 8px 8px -4px rgba(34, 47, 62, 0.15); padding: 4px 0; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.2), 0 8px 8px -4px rgba(34, 47, 62, 0.15); } .tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty { background: none; border: none; box-shadow: none; padding: 0; } .tox-editor-dock-fadeout { opacity: 0; visibility: hidden; } .tox-editor-dock-fadein { opacity: 1; visibility: visible; } .tox-editor-dock-transition { transition: visibility 0s linear 0.25s, opacity 0.25s ease; } .tox-editor-dock-transition.tox-editor-dock-fadein { transition-delay: 0s; } .tox .tox-control-wrap { flex: 1; position: relative; } .tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, .tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, .tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { display: none; } .tox .tox-control-wrap svg { display: block; } .tox .tox-control-wrap__status-icon-wrap { position: absolute; top: 50%; transform: translateY(-50%); } .tox .tox-control-wrap__status-icon-invalid svg { fill: #c00; } .tox .tox-control-wrap__status-icon-unknown svg { fill: orange; } .tox .tox-control-wrap__status-icon-valid svg { fill: green; } .tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield, .tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield, .tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield { padding-right: 32px; } .tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap { right: 4px; } .tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield, .tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield, .tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield { padding-left: 32px; } .tox[dir=rtl] .tox-control-wrap__status-icon-wrap { left: 4px; } .tox .tox-autocompleter { max-width: 25em; } .tox .tox-autocompleter .tox-menu { box-sizing: border-box; max-width: 25em; } .tox .tox-autocompleter .tox-autocompleter-highlight { font-weight: bold; } .tox .tox-color-input { display: flex; position: relative; z-index: 1; } .tox .tox-color-input .tox-textfield { z-index: -1; } .tox .tox-color-input span { border-color: rgba(34, 47, 62, 0.2); border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; height: 24px; position: absolute; top: 6px; width: 24px; } .tox .tox-color-input span:hover:not([aria-disabled=true]), .tox .tox-color-input span:focus:not([aria-disabled=true]) { border-color: #006ce7; cursor: pointer; } .tox .tox-color-input span::before { background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), linear-gradient(-45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%), linear-gradient(-45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%); background-position: 0 0, 0 6px, 6px -6px, -6px 0; background-size: 12px 12px; border: 1px solid #fff; border-radius: 6px; box-sizing: border-box; content: ''; height: 24px; left: -1px; position: absolute; top: -1px; width: 24px; z-index: -1; } .tox .tox-color-input span[aria-disabled=true] { cursor: not-allowed; } .tox:not([dir=rtl]) .tox-color-input { /* stylelint-disable-next-line no-descending-specificity */ } .tox:not([dir=rtl]) .tox-color-input .tox-textfield { padding-left: 36px; } .tox:not([dir=rtl]) .tox-color-input span { left: 6px; } .tox[dir="rtl"] .tox-color-input { /* stylelint-disable-next-line no-descending-specificity */ } .tox[dir="rtl"] .tox-color-input .tox-textfield { padding-right: 36px; } .tox[dir="rtl"] .tox-color-input span { right: 6px; } .tox .tox-label, .tox .tox-toolbar-label { color: rgba(34, 47, 62, 0.7); display: block; font-size: 14px; font-style: normal; font-weight: normal; line-height: 1.3; padding: 0 8px 0 0; text-transform: none; white-space: nowrap; } .tox .tox-toolbar-label { padding: 0 8px; } .tox[dir=rtl] .tox-label { padding: 0 0 0 8px; } .tox .tox-form { display: flex; flex: 1; flex-direction: column; } .tox .tox-form__group { box-sizing: border-box; margin-bottom: 4px; } .tox .tox-form-group--maximize { flex: 1; } .tox .tox-form__group--error { color: #c00; } .tox .tox-form__group--collection { display: flex; } .tox .tox-form__grid { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-between; } .tox .tox-form__grid--2col > .tox-form__group { width: calc(50% - (8px / 2)); } .tox .tox-form__grid--3col > .tox-form__group { width: calc(100% / 3 - (8px / 2)); } .tox .tox-form__grid--4col > .tox-form__group { width: calc(25% - (8px / 2)); } .tox .tox-form__controls-h-stack { align-items: center; display: flex; } .tox .tox-form__group--inline { align-items: center; display: flex; } .tox .tox-form__group--stretched { display: flex; flex: 1; flex-direction: column; } .tox .tox-form__group--stretched .tox-textarea { flex: 1; } .tox .tox-form__group--stretched .tox-navobj { display: flex; flex: 1; } .tox .tox-form__group--stretched .tox-navobj :nth-child(2) { flex: 1; height: 100%; } .tox:not([dir=rtl]) .tox-form__controls-h-stack > *:not(:first-child) { margin-left: 4px; } .tox[dir=rtl] .tox-form__controls-h-stack > *:not(:first-child) { margin-right: 4px; } .tox .tox-lock.tox-locked .tox-lock-icon__unlock, .tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { display: none; } .tox .tox-textfield, .tox .tox-toolbar-textfield, .tox .tox-listboxfield .tox-listbox--select, .tox .tox-textarea, .tox .tox-textarea-wrap .tox-textarea:focus { -webkit-appearance: none; -moz-appearance: none; appearance: none; background-color: #fff; border-color: #eeeeee; border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #222f3e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; line-height: 24px; margin: 0; min-height: 34px; outline: none; padding: 5px 5.5px; resize: none; width: 100%; } .tox .tox-textfield[disabled], .tox .tox-textarea[disabled] { background-color: #f2f2f2; color: rgba(34, 47, 62, 0.85); cursor: not-allowed; } .tox .tox-textfield:focus, .tox .tox-dialog__iframe.tox-dialog__iframe--bordered:focus-within, .tox .tox-listboxfield .tox-listbox--select:focus, .tox .tox-textarea-wrap:focus-within, .tox .tox-textarea:focus, .tox .tox-custom-editor:focus-within { background-color: #fff; border-color: #006ce7; box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); outline: none; } .tox .tox-toolbar-textfield { border-width: 0; margin-bottom: 3px; margin-top: 2px; max-width: 250px; } .tox .tox-naked-btn { background-color: transparent; border: 0; border-color: transparent; box-shadow: unset; color: #006ce7; cursor: pointer; display: block; margin: 0; padding: 0; } .tox .tox-naked-btn svg { display: block; fill: #222f3e; } .tox:not([dir=rtl]) .tox-toolbar-textfield + * { margin-left: 4px; } .tox[dir=rtl] .tox-toolbar-textfield + * { margin-right: 4px; } .tox .tox-listboxfield { cursor: pointer; position: relative; } .tox .tox-listboxfield .tox-listbox--select[disabled] { background-color: #f2f2f2; color: rgba(34, 47, 62, 0.85); cursor: not-allowed; } .tox .tox-listbox__select-label { cursor: default; flex: 1; margin: 0 4px; } .tox .tox-listbox__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; } .tox .tox-listbox__select-chevron svg { fill: #222f3e; } .tox .tox-listboxfield .tox-listbox--select { align-items: center; display: flex; } .tox:not([dir=rtl]) .tox-listboxfield svg { right: 8px; } .tox[dir=rtl] .tox-listboxfield svg { left: 8px; } .tox .tox-selectfield { cursor: pointer; position: relative; } .tox .tox-selectfield select { -webkit-appearance: none; -moz-appearance: none; appearance: none; background-color: #fff; border-color: #eeeeee; border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #222f3e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; line-height: 24px; margin: 0; min-height: 34px; outline: none; padding: 5px 5.5px; resize: none; width: 100%; } .tox .tox-selectfield select[disabled] { background-color: #f2f2f2; color: rgba(34, 47, 62, 0.85); cursor: not-allowed; } .tox .tox-selectfield select::-ms-expand { display: none; } .tox .tox-selectfield select:focus { background-color: #fff; border-color: #006ce7; box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); outline: none; } .tox .tox-selectfield svg { pointer-events: none; position: absolute; top: 50%; transform: translateY(-50%); } .tox:not([dir=rtl]) .tox-selectfield select[size="0"], .tox:not([dir=rtl]) .tox-selectfield select[size="1"] { padding-right: 24px; } .tox:not([dir=rtl]) .tox-selectfield svg { right: 8px; } .tox[dir=rtl] .tox-selectfield select[size="0"], .tox[dir=rtl] .tox-selectfield select[size="1"] { padding-left: 24px; } .tox[dir=rtl] .tox-selectfield svg { left: 8px; } .tox .tox-textarea-wrap { border-color: #eeeeee; border-radius: 6px; border-style: solid; border-width: 1px; display: flex; flex: 1; overflow: hidden; } .tox .tox-textarea { -webkit-appearance: textarea; -moz-appearance: textarea; appearance: textarea; white-space: pre-wrap; } .tox .tox-textarea-wrap .tox-textarea { border: none; } .tox .tox-textarea-wrap .tox-textarea:focus { border: none; } .tox-fullscreen { border: 0; height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; padding: 0; touch-action: pinch-zoom; width: 100%; } .tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { display: none; } .tox.tox-tinymce.tox-fullscreen, .tox-shadowhost.tox-fullscreen { left: 0; position: fixed; top: 0; z-index: 1200; } .tox.tox-tinymce.tox-fullscreen { background-color: transparent; } .tox-fullscreen .tox.tox-tinymce-aux, .tox-fullscreen ~ .tox.tox-tinymce-aux { z-index: 1201; } .tox .tox-help__more-link { list-style: none; margin-top: 1em; } .tox .tox-imagepreview { background-color: #666; height: 380px; overflow: hidden; position: relative; width: 100%; } .tox .tox-imagepreview.tox-imagepreview__loaded { overflow: auto; } .tox .tox-imagepreview__container { display: flex; left: 100vw; position: absolute; top: 100vw; } .tox .tox-imagepreview__image { background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); } .tox .tox-image-tools .tox-spacer { flex: 1; } .tox .tox-image-tools .tox-bar { align-items: center; display: flex; height: 60px; justify-content: center; } .tox .tox-image-tools .tox-imagepreview, .tox .tox-image-tools .tox-imagepreview + .tox-bar { margin-top: 8px; } .tox .tox-image-tools .tox-croprect-block { background: black; filter: alpha(opacity=50); opacity: 0.5; position: absolute; zoom: 1; } .tox .tox-image-tools .tox-croprect-handle { border: 2px solid white; height: 20px; left: 0; position: absolute; top: 0; width: 20px; } .tox .tox-image-tools .tox-croprect-handle-move { border: 0; cursor: move; position: absolute; } .tox .tox-image-tools .tox-croprect-handle-nw { border-width: 2px 0 0 2px; cursor: nw-resize; left: 100px; margin: -2px 0 0 -2px; top: 100px; } .tox .tox-image-tools .tox-croprect-handle-ne { border-width: 2px 2px 0 0; cursor: ne-resize; left: 200px; margin: -2px 0 0 -20px; top: 100px; } .tox .tox-image-tools .tox-croprect-handle-sw { border-width: 0 0 2px 2px; cursor: sw-resize; left: 100px; margin: -20px 2px 0 -2px; top: 200px; } .tox .tox-image-tools .tox-croprect-handle-se { border-width: 0 2px 2px 0; cursor: se-resize; left: 200px; margin: -20px 0 0 -20px; top: 200px; } .tox .tox-insert-table-picker { display: flex; flex-wrap: wrap; width: 170px; } .tox .tox-insert-table-picker > div { border-color: #eeeeee; border-style: solid; border-width: 0 1px 1px 0; box-sizing: border-box; height: 17px; width: 17px; } .tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { margin: -4px -4px; } .tox .tox-insert-table-picker .tox-insert-table-picker__selected { background-color: rgba(0, 108, 231, 0.5); border-color: rgba(0, 108, 231, 0.5); } .tox .tox-insert-table-picker__label { color: rgba(34, 47, 62, 0.7); display: block; font-size: 14px; padding: 4px; text-align: center; width: 100%; } .tox:not([dir=rtl]) { /* stylelint-disable-next-line no-descending-specificity */ } .tox:not([dir=rtl]) .tox-insert-table-picker > div:nth-child(10n) { border-right: 0; } .tox[dir=rtl] { /* stylelint-disable-next-line no-descending-specificity */ } .tox[dir=rtl] .tox-insert-table-picker > div:nth-child(10n+1) { border-right: 0; } .tox { /* stylelint-disable */ /* stylelint-enable */ } .tox .tox-menu { background-color: #fff; border: 1px solid transparent; border-radius: 6px; box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); display: inline-block; overflow: hidden; vertical-align: top; z-index: 1150; } .tox .tox-menu.tox-collection.tox-collection--list { padding: 0 4px; } .tox .tox-menu.tox-collection.tox-collection--toolbar { padding: 8px; } .tox .tox-menu.tox-collection.tox-collection--grid { padding: 8px; } @media only screen and (min-width: 768px ) { .tox .tox-menu .tox-collection__item-label { overflow-wrap: break-word; word-break: normal; } } .tox .tox-menu__label h1, .tox .tox-menu__label h2, .tox .tox-menu__label h3, .tox .tox-menu__label h4, .tox .tox-menu__label h5, .tox .tox-menu__label h6, .tox .tox-menu__label p, .tox .tox-menu__label blockquote, .tox .tox-menu__label code { margin: 0; } .tox .tox-menubar { background: repeating-linear-gradient(transparent 0px 1px, transparent 1px 39px) center top 39px / 100% calc(100% - 39px) no-repeat; background-color: #fff; display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: wrap; grid-column: 1 / -1; grid-row: 1; padding: 0 11px 0 12px; } .tox .tox-promotion + .tox-menubar { grid-column: 1; } .tox .tox-promotion { background: repeating-linear-gradient(transparent 0px 1px, transparent 1px 39px) center top 39px / 100% calc(100% - 39px) no-repeat; background-color: #fff; grid-column: 2; grid-row: 1; padding-inline-end: 8px; padding-inline-start: 4px; padding-top: 5px; } .tox .tox-promotion-link { align-items: unsafe center; background-color: #E8F1F8; border-radius: 5px; color: #086BE6; cursor: pointer; display: flex; font-size: 14px; height: 26.6px; padding: 4px 8px; white-space: nowrap; } .tox .tox-promotion-link:hover { background-color: #B4D7FF; } .tox .tox-promotion-link:focus { background-color: #D9EDF7; } /* Deprecated. Remove in next major release */ .tox .tox-mbtn { align-items: center; background: transparent; border: 0; border-radius: 3px; box-shadow: none; color: #222f3e; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 28px; justify-content: center; margin: 5px 1px 6px 0; outline: none; overflow: hidden; padding: 0 4px; text-transform: none; width: auto; } .tox .tox-mbtn[disabled] { background-color: transparent; border: 0; box-shadow: none; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-mbtn:focus:not(:disabled) { background: #cce2fa; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-mbtn--active { background: #a6ccf7; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { background: #cce2fa; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-mbtn__select-label { cursor: default; font-weight: normal; margin: 0 4px; } .tox .tox-mbtn[disabled] .tox-mbtn__select-label { cursor: not-allowed; } .tox .tox-mbtn__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; display: none; } .tox .tox-notification { border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; display: grid; font-size: 14px; font-weight: normal; grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); margin-top: 4px; opacity: 0; padding: 4px; transition: transform 100ms ease-in, opacity 150ms ease-in; } .tox .tox-notification p { font-size: 14px; font-weight: normal; } .tox .tox-notification a { cursor: pointer; text-decoration: underline; } .tox .tox-notification--in { opacity: 1; } .tox .tox-notification--success { background-color: #e4eeda; border-color: #d7e6c8; color: #222f3e; } .tox .tox-notification--success p { color: #222f3e; } .tox .tox-notification--success a { color: #517342; } .tox .tox-notification--success svg { fill: #222f3e; } .tox .tox-notification--error { background-color: #f5cccc; border-color: #f0b3b3; color: #222f3e; } .tox .tox-notification--error p { color: #222f3e; } .tox .tox-notification--error a { color: #77181f; } .tox .tox-notification--error svg { fill: #222f3e; } .tox .tox-notification--warn, .tox .tox-notification--warning { background-color: #fff5cc; border-color: #fff0b3; color: #222f3e; } .tox .tox-notification--warn p, .tox .tox-notification--warning p { color: #222f3e; } .tox .tox-notification--warn a, .tox .tox-notification--warning a { color: #7a6e25; } .tox .tox-notification--warn svg, .tox .tox-notification--warning svg { fill: #222f3e; } .tox .tox-notification--info { background-color: #d6e7fb; border-color: #c1dbf9; color: #222f3e; } .tox .tox-notification--info p { color: #222f3e; } .tox .tox-notification--info a { color: #2a64a6; } .tox .tox-notification--info svg { fill: #222f3e; } .tox .tox-notification__body { align-self: center; color: #222f3e; font-size: 14px; grid-column-end: 3; grid-column-start: 2; grid-row-end: 2; grid-row-start: 1; text-align: center; white-space: normal; word-break: break-all; word-break: break-word; } .tox .tox-notification__body > * { margin: 0; } .tox .tox-notification__body > * + * { margin-top: 1rem; } .tox .tox-notification__icon { align-self: center; grid-column-end: 2; grid-column-start: 1; grid-row-end: 2; grid-row-start: 1; justify-self: end; } .tox .tox-notification__icon svg { display: block; } .tox .tox-notification__dismiss { align-self: start; grid-column-end: 4; grid-column-start: 3; grid-row-end: 2; grid-row-start: 1; justify-self: end; } .tox .tox-notification .tox-progress-bar { grid-column-end: 4; grid-column-start: 1; grid-row-end: 3; grid-row-start: 2; justify-self: center; } .tox .tox-pop { display: inline-block; position: relative; } .tox .tox-pop--resizing { transition: width 0.1s ease; } .tox .tox-pop--resizing .tox-toolbar, .tox .tox-pop--resizing .tox-toolbar__group { flex-wrap: nowrap; } .tox .tox-pop--transition { transition: 0.15s ease; transition-property: left, right, top, bottom; } .tox .tox-pop--transition::before, .tox .tox-pop--transition::after { transition: all 0.15s, visibility 0s, opacity 0.075s ease 0.075s; } .tox .tox-pop__dialog { background-color: #fff; border: 1px solid #eeeeee; border-radius: 6px; box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); min-width: 0; overflow: hidden; } .tox .tox-pop__dialog > *:not(.tox-toolbar) { margin: 4px 4px 4px 8px; } .tox .tox-pop__dialog .tox-toolbar { background-color: transparent; margin-bottom: -1px; } .tox .tox-pop::before, .tox .tox-pop::after { border-style: solid; content: ''; display: block; height: 0; opacity: 1; position: absolute; width: 0; } .tox .tox-pop.tox-pop--inset::before, .tox .tox-pop.tox-pop--inset::after { opacity: 0; transition: all 0s 0.15s, visibility 0s, opacity 0.075s ease; } .tox .tox-pop.tox-pop--bottom::before, .tox .tox-pop.tox-pop--bottom::after { left: 50%; top: 100%; } .tox .tox-pop.tox-pop--bottom::after { border-color: #fff transparent transparent transparent; border-width: 8px; margin-left: -8px; margin-top: -1px; } .tox .tox-pop.tox-pop--bottom::before { border-color: #eeeeee transparent transparent transparent; border-width: 9px; margin-left: -9px; } .tox .tox-pop.tox-pop--top::before, .tox .tox-pop.tox-pop--top::after { left: 50%; top: 0; transform: translateY(-100%); } .tox .tox-pop.tox-pop--top::after { border-color: transparent transparent #fff transparent; border-width: 8px; margin-left: -8px; margin-top: 1px; } .tox .tox-pop.tox-pop--top::before { border-color: transparent transparent #eeeeee transparent; border-width: 9px; margin-left: -9px; } .tox .tox-pop.tox-pop--left::before, .tox .tox-pop.tox-pop--left::after { left: 0; top: calc(50% - 1px); transform: translateY(-50%); } .tox .tox-pop.tox-pop--left::after { border-color: transparent #fff transparent transparent; border-width: 8px; margin-left: -15px; } .tox .tox-pop.tox-pop--left::before { border-color: transparent #eeeeee transparent transparent; border-width: 10px; margin-left: -19px; } .tox .tox-pop.tox-pop--right::before, .tox .tox-pop.tox-pop--right::after { left: 100%; top: calc(50% + 1px); transform: translateY(-50%); } .tox .tox-pop.tox-pop--right::after { border-color: transparent transparent transparent #fff; border-width: 8px; margin-left: -1px; } .tox .tox-pop.tox-pop--right::before { border-color: transparent transparent transparent #eeeeee; border-width: 10px; margin-left: -1px; } .tox .tox-pop.tox-pop--align-left::before, .tox .tox-pop.tox-pop--align-left::after { left: 20px; } .tox .tox-pop.tox-pop--align-right::before, .tox .tox-pop.tox-pop--align-right::after { left: calc(100% - 20px); } .tox .tox-sidebar-wrap { display: flex; flex-direction: row; flex-grow: 1; min-height: 0; } .tox .tox-sidebar { background-color: #fff; display: flex; flex-direction: row; justify-content: flex-end; } .tox .tox-sidebar__slider { display: flex; overflow: hidden; } .tox .tox-sidebar__pane-container { display: flex; } .tox .tox-sidebar__pane { display: flex; } .tox .tox-sidebar--sliding-closed { opacity: 0; } .tox .tox-sidebar--sliding-open { opacity: 1; } .tox .tox-sidebar--sliding-growing, .tox .tox-sidebar--sliding-shrinking { transition: width 0.5s ease, opacity 0.5s ease; } .tox .tox-selector { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; display: inline-block; height: 10px; position: absolute; width: 10px; } .tox.tox-platform-touch .tox-selector { height: 12px; width: 12px; } .tox .tox-slider { align-items: center; display: flex; flex: 1; height: 24px; justify-content: center; position: relative; } .tox .tox-slider__rail { background-color: transparent; border: 1px solid #eeeeee; border-radius: 6px; height: 10px; min-width: 120px; width: 100%; } .tox .tox-slider__handle { background-color: #006ce7; border: 2px solid #0054b4; border-radius: 6px; box-shadow: none; height: 24px; left: 50%; position: absolute; top: 50%; transform: translateX(-50%) translateY(-50%); width: 14px; } .tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { margin-inline-start: 8px; } .tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { margin-inline-start: 32px; } .tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { margin-inline-start: 32px; } .tox .tox-source-code { overflow: auto; } .tox .tox-spinner { display: flex; } .tox .tox-spinner > div { animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; background-color: rgba(34, 47, 62, 0.7); border-radius: 100%; height: 8px; width: 8px; } .tox .tox-spinner > div:nth-child(1) { animation-delay: -0.32s; } .tox .tox-spinner > div:nth-child(2) { animation-delay: -0.16s; } @keyframes tam-bouncing-dots { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } } .tox:not([dir=rtl]) .tox-spinner > div:not(:first-child) { margin-left: 4px; } .tox[dir=rtl] .tox-spinner > div:not(:first-child) { margin-right: 4px; } .tox .tox-statusbar { align-items: center; background-color: #fff; border-top: 1px solid #e3e3e3; color: rgba(34, 47, 62, 0.7); display: flex; flex: 0 0 auto; font-size: 14px; font-weight: normal; height: 25px; overflow: hidden; padding: 0 8px; position: relative; text-transform: none; } .tox .tox-statusbar__text-container { display: flex; flex: 1 1 auto; justify-content: flex-end; overflow: hidden; } .tox .tox-statusbar__path { display: flex; flex: 1 1 auto; margin-right: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-statusbar__path > * { display: inline; white-space: nowrap; } .tox .tox-statusbar__wordcount { flex: 0 0 auto; margin-left: 1ch; } .tox .tox-statusbar a, .tox .tox-statusbar__path-item, .tox .tox-statusbar__wordcount { color: rgba(34, 47, 62, 0.7); text-decoration: none; } .tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]) { color: #222f3e; cursor: pointer; } .tox .tox-statusbar__branding svg { fill: rgba(34, 47, 62, 0.8); height: 1.14em; vertical-align: -0.28em; width: 3.6em; } .tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg, .tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg { fill: #222f3e; } .tox .tox-statusbar__resize-handle { align-items: flex-end; align-self: stretch; cursor: nwse-resize; display: flex; flex: 0 0 auto; justify-content: flex-end; margin-left: auto; margin-right: -8px; padding-bottom: 3px; padding-left: 1ch; padding-right: 3px; } .tox .tox-statusbar__resize-handle svg { display: block; fill: rgba(34, 47, 62, 0.5); } .tox .tox-statusbar__resize-handle:focus svg { background-color: #dee0e2; border-radius: 1px 1px 5px 1px; box-shadow: 0 0 0 2px #dee0e2; } .tox:not([dir=rtl]) .tox-statusbar__path > * { margin-right: 4px; } .tox:not([dir=rtl]) .tox-statusbar__branding { margin-left: 2ch; } .tox[dir=rtl] .tox-statusbar { flex-direction: row-reverse; } .tox[dir=rtl] .tox-statusbar__path > * { margin-left: 4px; } .tox .tox-throbber { z-index: 1299; } .tox .tox-throbber__busy-spinner { align-items: center; background-color: rgba(255, 255, 255, 0.6); bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; } .tox .tox-tbtn { align-items: center; background: transparent; border: 0; border-radius: 3px; box-shadow: none; color: #222f3e; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 28px; justify-content: center; margin: 6px 1px 5px 0; outline: none; overflow: hidden; padding: 0; text-transform: none; width: 34px; } .tox .tox-tbtn svg { display: block; fill: #222f3e; } .tox .tox-tbtn.tox-tbtn-more { padding-left: 5px; padding-right: 5px; width: inherit; } .tox .tox-tbtn:focus { background: #cce2fa; border: 0; box-shadow: none; } .tox .tox-tbtn:hover { background: #cce2fa; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tbtn:hover svg { fill: #222f3e; } .tox .tox-tbtn:active { background: #a6ccf7; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tbtn:active svg { fill: #222f3e; } .tox .tox-tbtn--disabled .tox-tbtn--enabled svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-tbtn--disabled, .tox .tox-tbtn--disabled:hover, .tox .tox-tbtn:disabled, .tox .tox-tbtn:disabled:hover { background: transparent; border: 0; box-shadow: none; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-tbtn--disabled svg, .tox .tox-tbtn--disabled:hover svg, .tox .tox-tbtn:disabled svg, .tox .tox-tbtn:disabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: rgba(34, 47, 62, 0.5); } .tox .tox-tbtn--enabled, .tox .tox-tbtn--enabled:hover { background: #a6ccf7; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tbtn--enabled > *, .tox .tox-tbtn--enabled:hover > * { transform: none; } .tox .tox-tbtn--enabled svg, .tox .tox-tbtn--enabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: #222f3e; } .tox .tox-tbtn--enabled.tox-tbtn--disabled svg, .tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { color: #222f3e; } .tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { fill: #222f3e; } .tox .tox-tbtn:active > * { transform: none; } .tox .tox-tbtn--md { height: 42px; width: 51px; } .tox .tox-tbtn--lg { flex-direction: column; height: 56px; width: 68px; } .tox .tox-tbtn--return { align-self: stretch; height: unset; width: 16px; } .tox .tox-tbtn--labeled { padding: 0 4px; width: unset; } .tox .tox-tbtn__vlabel { display: block; font-size: 10px; font-weight: normal; letter-spacing: -0.025em; margin-bottom: 4px; white-space: nowrap; } .tox .tox-number-input { border-radius: 3px; display: flex; margin: 6px 1px 5px 0; padding: 0 4px; width: auto; } .tox .tox-number-input .tox-input-wrapper { background: #f7f7f7; display: flex; pointer-events: none; text-align: center; } .tox .tox-number-input .tox-input-wrapper:focus { background: #cce2fa; } .tox .tox-number-input input { border-radius: 3px; color: #222f3e; font-size: 14px; margin: 2px 0; pointer-events: all; width: 60px; } .tox .tox-number-input input:hover { background: #cce2fa; color: #222f3e; } .tox .tox-number-input input:focus { background: #fff; color: #222f3e; } .tox .tox-number-input input:disabled { background: transparent; border: 0; box-shadow: none; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-number-input button { background: #f7f7f7; color: #222f3e; height: 28px; text-align: center; width: 24px; } .tox .tox-number-input button svg { display: block; fill: #222f3e; margin: 0 auto; transform: scale(0.67); } .tox .tox-number-input button:focus { background: #cce2fa; } .tox .tox-number-input button:hover { background: #cce2fa; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-number-input button:hover svg { fill: #222f3e; } .tox .tox-number-input button:active { background: #a6ccf7; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-number-input button:active svg { fill: #222f3e; } .tox .tox-number-input button:disabled { background: transparent; border: 0; box-shadow: none; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-number-input button:disabled svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-number-input button.minus { border-radius: 3px 0 0 3px; } .tox .tox-number-input button.plus { border-radius: 0 3px 3px 0; } .tox .tox-number-input:focus:not(:active) > button, .tox .tox-number-input:focus:not(:active) > .tox-input-wrapper { background: #cce2fa; } .tox .tox-tbtn--select { margin: 6px 1px 5px 0; padding: 0 4px; width: auto; } .tox .tox-tbtn__select-label { cursor: default; font-weight: normal; height: initial; margin: 0 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-tbtn__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; } .tox .tox-tbtn__select-chevron svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-tbtn--bespoke { background: #f7f7f7; } .tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { margin-inline-start: 4px; } .tox .tox-tbtn--bespoke .tox-tbtn__select-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 7em; } .tox .tox-tbtn--disabled .tox-tbtn__select-label, .tox .tox-tbtn--select:disabled .tox-tbtn__select-label { cursor: not-allowed; } .tox .tox-split-button { border: 0; border-radius: 3px; box-sizing: border-box; display: flex; margin: 6px 1px 5px 0; overflow: hidden; } .tox .tox-split-button:hover { box-shadow: 0 0 0 1px #cce2fa inset; } .tox .tox-split-button:focus { background: #cce2fa; box-shadow: none; color: #222f3e; } .tox .tox-split-button > * { border-radius: 0; } .tox .tox-split-button__chevron { width: 16px; } .tox .tox-split-button__chevron svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-split-button .tox-tbtn { margin: 0; } .tox .tox-split-button.tox-tbtn--disabled:hover, .tox .tox-split-button.tox-tbtn--disabled:focus, .tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, .tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus { background: transparent; box-shadow: none; color: rgba(34, 47, 62, 0.5); } .tox.tox-platform-touch .tox-split-button .tox-tbtn--select { padding: 0 0px; } .tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { width: 30px; } .tox.tox-platform-touch .tox-split-button__chevron { width: 20px; } .tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color, .tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color { opacity: 0.6; } .tox .tox-toolbar-overlord { background-color: #fff; } .tox .tox-toolbar, .tox .tox-toolbar__primary, .tox .tox-toolbar__overflow { background-attachment: local; background-color: #fff; background-image: repeating-linear-gradient(#e3e3e3 0px 1px, transparent 1px 39px); background-position: center top 40px; background-repeat: no-repeat; background-size: calc(100% - 11px * 2) calc(100% - 41px); display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: wrap; padding: 0 0px; transform: perspective(1px); } .tox .tox-toolbar-overlord > .tox-toolbar, .tox .tox-toolbar-overlord > .tox-toolbar__primary, .tox .tox-toolbar-overlord > .tox-toolbar__overflow { background-position: center top 0px; background-size: calc(100% - 11px * 2) calc(100% - 0px); } .tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { height: 0; opacity: 0; padding-bottom: 0; padding-top: 0; visibility: hidden; } .tox .tox-toolbar__overflow--growing { transition: height 0.3s ease, opacity 0.2s linear 0.1s; } .tox .tox-toolbar__overflow--shrinking { transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; } .tox .tox-toolbar-overlord, .tox .tox-anchorbar { grid-column: 1 / -1; } .tox .tox-menubar + .tox-toolbar, .tox .tox-menubar + .tox-toolbar-overlord { border-top: 1px solid transparent; margin-top: -1px; padding-bottom: 1px; padding-top: 1px; } .tox .tox-toolbar--scrolling { flex-wrap: nowrap; overflow-x: auto; } .tox .tox-pop .tox-toolbar { border-width: 0; } .tox .tox-toolbar--no-divider { background-image: none; } .tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, .tox .tox-toolbar-overlord .tox-toolbar__primary { background-position: center top 39px; } .tox .tox-editor-header > .tox-toolbar--scrolling, .tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { background-image: none; } .tox.tox-tinymce-aux .tox-toolbar__overflow { background-color: #fff; background-position: center top 43px; background-size: calc(100% - 8px * 2) calc(100% - 51px); border: none; border-radius: 6px; box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); overscroll-behavior: none; padding: 4px 0; } .tox-pop .tox-pop__dialog { /* stylelint-disable-next-line no-descending-specificity */ } .tox-pop .tox-pop__dialog .tox-toolbar { background-position: center top 43px; background-size: calc(100% - 11px * 2) calc(100% - 51px); padding: 4px 0; } .tox .tox-toolbar__group { align-items: center; display: flex; flex-wrap: wrap; margin: 0 0; padding: 0 11px 0 12px; } .tox .tox-toolbar__group--pull-right { margin-left: auto; } .tox .tox-toolbar--scrolling .tox-toolbar__group { flex-shrink: 0; flex-wrap: nowrap; } .tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type) { border-right: 1px solid transparent; } .tox[dir=rtl] .tox-toolbar__group:not(:last-of-type) { border-left: 1px solid transparent; } .tox .tox-tooltip { display: inline-block; padding: 8px; position: relative; } .tox .tox-tooltip__body { background-color: #222f3e; border-radius: 6px; box-shadow: 0 2px 4px rgba(34, 47, 62, 0.3); color: rgba(255, 255, 255, 0.75); font-size: 14px; font-style: normal; font-weight: normal; padding: 4px 8px; text-transform: none; } .tox .tox-tooltip__arrow { position: absolute; } .tox .tox-tooltip--down .tox-tooltip__arrow { border-left: 8px solid transparent; border-right: 8px solid transparent; border-top: 8px solid #222f3e; bottom: 0; left: 50%; position: absolute; transform: translateX(-50%); } .tox .tox-tooltip--up .tox-tooltip__arrow { border-bottom: 8px solid #222f3e; border-left: 8px solid transparent; border-right: 8px solid transparent; left: 50%; position: absolute; top: 0; transform: translateX(-50%); } .tox .tox-tooltip--right .tox-tooltip__arrow { border-bottom: 8px solid transparent; border-left: 8px solid #222f3e; border-top: 8px solid transparent; position: absolute; right: 0; top: 50%; transform: translateY(-50%); } .tox .tox-tooltip--left .tox-tooltip__arrow { border-bottom: 8px solid transparent; border-right: 8px solid #222f3e; border-top: 8px solid transparent; left: 0; position: absolute; top: 50%; transform: translateY(-50%); } .tox .tox-tree { display: flex; flex-direction: column; } .tox .tox-tree .tox-trbtn { align-items: center; background: transparent; border: 0; border-radius: 4px; box-shadow: none; color: #222f3e; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 28px; margin-bottom: 4px; margin-top: 4px; outline: none; overflow: hidden; padding: 0; padding-left: 8px; text-transform: none; } .tox .tox-tree .tox-trbtn .tox-tree__label { cursor: default; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-tree .tox-trbtn svg { display: block; fill: #222f3e; } .tox .tox-tree .tox-trbtn:focus { background: #cce2fa; border: 0; box-shadow: none; } .tox .tox-tree .tox-trbtn:hover { background: #cce2fa; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tree .tox-trbtn:hover svg { fill: #222f3e; } .tox .tox-tree .tox-trbtn:active { background: #a6ccf7; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tree .tox-trbtn:active svg { fill: #222f3e; } .tox .tox-tree .tox-trbtn--disabled, .tox .tox-tree .tox-trbtn--disabled:hover, .tox .tox-tree .tox-trbtn:disabled, .tox .tox-tree .tox-trbtn:disabled:hover { background: transparent; border: 0; box-shadow: none; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-tree .tox-trbtn--disabled svg, .tox .tox-tree .tox-trbtn--disabled:hover svg, .tox .tox-tree .tox-trbtn:disabled svg, .tox .tox-tree .tox-trbtn:disabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: rgba(34, 47, 62, 0.5); } .tox .tox-tree .tox-trbtn--enabled, .tox .tox-tree .tox-trbtn--enabled:hover { background: #a6ccf7; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tree .tox-trbtn--enabled > *, .tox .tox-tree .tox-trbtn--enabled:hover > * { transform: none; } .tox .tox-tree .tox-trbtn--enabled svg, .tox .tox-tree .tox-trbtn--enabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: #222f3e; } .tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) { color: #222f3e; } .tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg { fill: #222f3e; } .tox .tox-tree .tox-trbtn:active > * { transform: none; } .tox .tox-tree .tox-trbtn--return { align-self: stretch; height: unset; width: 16px; } .tox .tox-tree .tox-trbtn--labeled { padding: 0 4px; width: unset; } .tox .tox-tree .tox-trbtn__vlabel { display: block; font-size: 10px; font-weight: normal; letter-spacing: -0.025em; margin-bottom: 4px; white-space: nowrap; } .tox .tox-tree .tox-tree--directory { display: flex; flex-direction: column; /* stylelint-disable no-descending-specificity */ } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label { font-weight: bold; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn { margin-left: auto; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg { fill: transparent; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg { fill: #222f3e; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg { fill: #222f3e; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) { background-color: transparent; color: #222f3e; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg { fill: #222f3e; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron { margin-right: 6px; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--growing) .tox-chevron, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--shrinking) .tox-chevron { transition: transform 0.5s ease-in-out; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--growing) .tox-chevron, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--open) .tox-chevron { transform: rotate(90deg); } .tox .tox-tree .tox-tree--leaf__label { font-weight: normal; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn { margin-left: auto; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg { fill: transparent; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg, .tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg { fill: #222f3e; } .tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg { fill: #222f3e; } .tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) { background-color: transparent; color: #222f3e; } .tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg { fill: #222f3e; } .tox .tox-tree .tox-tree--directory__children { overflow: hidden; padding-left: 16px; } .tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing, .tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking { transition: height 0.5s ease-in-out; } .tox .tox-tree .tox-trbtn.tox-tree--leaf__label { display: flex; justify-content: space-between; } .tox .tox-view-wrap, .tox .tox-view-wrap__slot-container { background-color: #fff; display: flex; flex: 1; flex-direction: column; } .tox .tox-view { display: flex; flex: 1 1 auto; flex-direction: column; overflow: hidden; } .tox .tox-view__header { align-items: center; display: flex; font-size: 16px; justify-content: space-between; padding: 8px 8px 0 8px; position: relative; } .tox .tox-view--mobile.tox-view__header, .tox .tox-view--mobile.tox-view__toolbar { padding: 8px; } .tox .tox-view--scrolling { flex-wrap: nowrap; overflow-x: auto; } .tox .tox-view__toolbar { display: flex; flex-direction: row; gap: 8px; justify-content: space-between; padding: 8px 8px 0 8px; } .tox .tox-view__toolbar__group { display: flex; flex-direction: row; gap: 12px; } .tox .tox-view__header-start, .tox .tox-view__header-end { display: flex; } .tox .tox-view__pane { height: 100%; padding: 8px; width: 100%; } .tox .tox-view__pane_panel { border: 1px solid #eeeeee; border-radius: 6px; } .tox:not([dir=rtl]) .tox-view__header .tox-view__header-start > *, .tox:not([dir=rtl]) .tox-view__header .tox-view__header-end > * { margin-left: 8px; } .tox[dir=rtl] .tox-view__header .tox-view__header-start > *, .tox[dir=rtl] .tox-view__header .tox-view__header-end > * { margin-right: 8px; } .tox .tox-well { border: 1px solid #eeeeee; border-radius: 6px; padding: 8px; width: 100%; } .tox .tox-well > *:first-child { margin-top: 0; } .tox .tox-well > *:last-child { margin-bottom: 0; } .tox .tox-well > *:only-child { margin: 0; } .tox .tox-custom-editor { border: 1px solid #eeeeee; border-radius: 6px; display: flex; flex: 1; overflow: hidden; position: relative; } /* stylelint-disable */ .tox { /* stylelint-enable */ } .tox .tox-dialog-loading::before { background-color: rgba(0, 0, 0, 0.5); content: ""; height: 100%; position: absolute; width: 100%; z-index: 1000; } .tox .tox-tab { cursor: pointer; } .tox .tox-dialog__content-js { display: flex; flex: 1; } .tox .tox-dialog__body-content .tox-collection { display: flex; flex: 1; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/oxide/skin.shadowdom.css ================================================ body.tox-dialog__disable-scroll { overflow: hidden; } .tox-fullscreen { border: 0; height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; padding: 0; touch-action: pinch-zoom; width: 100%; } .tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { display: none; } .tox.tox-tinymce.tox-fullscreen, .tox-shadowhost.tox-fullscreen { left: 0; position: fixed; top: 0; z-index: 1200; } .tox.tox-tinymce.tox-fullscreen { background-color: transparent; } .tox-fullscreen .tox.tox-tinymce-aux, .tox-fullscreen ~ .tox.tox-tinymce-aux { z-index: 1201; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/oxide-dark/content.css ================================================ .mce-content-body .mce-item-anchor { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; } .mce-content-body .mce-item-anchor:empty { cursor: default; display: inline-block; height: 12px !important; padding: 0 2px; -webkit-user-modify: read-only; -moz-user-modify: read-only; -webkit-user-select: all; -moz-user-select: all; user-select: all; width: 8px !important; } .mce-content-body .mce-item-anchor:not(:empty) { background-position-x: 2px; display: inline-block; padding-left: 12px; } .mce-content-body .mce-item-anchor[data-mce-selected] { outline-offset: 1px; } .tox-comments-visible .tox-comment[contenteditable="false"]:not([data-mce-selected]), .tox-comments-visible span.tox-comment img:not([data-mce-selected]), .tox-comments-visible span.tox-comment > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #ffe89d; } .tox-comments-visible .tox-comment[contenteditable="false"][data-mce-annotation-active="true"]:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] img:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment:not([data-mce-selected]) { background-color: #ffe89d; outline: none; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"]:not([data-mce-selected="inline-boundary"]) { background-color: #fed635; } .tox-checklist > li:not(.tox-checklist--hidden) { list-style: none; margin: 0.25em 0; } .tox-checklist > li:not(.tox-checklist--hidden)::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); cursor: pointer; height: 1em; margin-left: -1.5em; margin-top: 0.125em; position: absolute; width: 1em; } .tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); } [dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { margin-left: 0; margin-right: -1.5em; } /* stylelint-disable */ /* http://prismjs.com/ */ /** * Dracula Theme originally by Zeno Rocha [@zenorocha] * https://draculatheme.com/ * * Ported for PrismJS by Albert Vallverdu [@byverdu] */ code[class*="language-"], pre[class*="language-"] { color: #f8f8f2; background: none; text-shadow: 0 1px rgba(0, 0, 0, 0.3); font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.5; -moz-tab-size: 4; tab-size: 4; -webkit-hyphens: none; hyphens: none; } /* Code blocks */ pre[class*="language-"] { padding: 1em; margin: 0.5em 0; overflow: auto; border-radius: 0.3em; } :not(pre) > code[class*="language-"], pre[class*="language-"] { background: #282a36; } /* Inline code */ :not(pre) > code[class*="language-"] { padding: 0.1em; border-radius: 0.3em; white-space: normal; } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: #6272a4; } .token.punctuation { color: #f8f8f2; } .namespace { opacity: 0.7; } .token.property, .token.tag, .token.constant, .token.symbol, .token.deleted { color: #ff79c6; } .token.boolean, .token.number { color: #bd93f9; } .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #50fa7b; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string, .token.variable { color: #f8f8f2; } .token.atrule, .token.attr-value, .token.function, .token.class-name { color: #f1fa8c; } .token.keyword { color: #8be9fd; } .token.regex, .token.important { color: #ffb86c; } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } /* stylelint-enable */ .mce-content-body { overflow-wrap: break-word; word-wrap: break-word; } .mce-content-body .mce-visual-caret { background-color: black; background-color: currentColor; position: absolute; } .mce-content-body .mce-visual-caret-hidden { display: none; } .mce-content-body *[data-mce-caret] { left: -1000px; margin: 0; padding: 0; position: absolute; right: auto; top: 0; } .mce-content-body .mce-offscreen-selection { left: -2000000px; max-width: 1000000px; position: absolute; } .mce-content-body *[contentEditable=false] { cursor: default; } .mce-content-body *[contentEditable=true] { cursor: text; } .tox-cursor-format-painter { cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; } div.mce-footnotes hr { margin-inline-end: auto; margin-inline-start: 0; width: 25%; } div.mce-footnotes li > a.mce-footnotes-backlink { text-decoration: none; } @media print { sup.mce-footnote a { color: black; text-decoration: none; } div.mce-footnotes { break-inside: avoid; width: 100%; } div.mce-footnotes li > a.mce-footnotes-backlink { display: none; } } .mce-content-body figure.align-left { float: left; } .mce-content-body figure.align-right { float: right; } .mce-content-body figure.image.align-center { display: table; margin-left: auto; margin-right: auto; } .mce-preview-object { border: 1px solid gray; display: inline-block; line-height: 0; margin: 0 2px 0 2px; position: relative; } .mce-preview-object .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-preview-object[data-mce-selected="2"] .mce-shim { display: none; } .mce-content-body .mce-mergetag { cursor: default !important; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body .mce-mergetag:hover { background-color: rgba(0, 108, 231, 0.3); } .mce-content-body .mce-mergetag-affix { background-color: rgba(0, 108, 231, 0.3); color: #006ce7; } .mce-object { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; border: 1px dashed #aaa; } .mce-pagebreak { border: 1px dashed #aaa; cursor: default; display: block; height: 5px; margin-top: 15px; page-break-before: always; width: 100%; } @media print { .mce-pagebreak { border: 0; } } .tiny-pageembed .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tiny-pageembed[data-mce-selected="2"] .mce-shim { display: none; } .tiny-pageembed { display: inline-block; position: relative; } .tiny-pageembed--21by9, .tiny-pageembed--16by9, .tiny-pageembed--4by3, .tiny-pageembed--1by1 { display: block; overflow: hidden; padding: 0; position: relative; width: 100%; } .tiny-pageembed--21by9 { padding-top: 42.857143%; } .tiny-pageembed--16by9 { padding-top: 56.25%; } .tiny-pageembed--4by3 { padding-top: 75%; } .tiny-pageembed--1by1 { padding-top: 100%; } .tiny-pageembed--21by9 iframe, .tiny-pageembed--16by9 iframe, .tiny-pageembed--4by3 iframe, .tiny-pageembed--1by1 iframe { border: 0; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-content-body[data-mce-placeholder] { position: relative; } .mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { color: rgba(34, 47, 62, 0.7); content: attr(data-mce-placeholder); position: absolute; } .mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { left: 1px; } .mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { right: 1px; } .mce-content-body div.mce-resizehandle { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; height: 10px; position: absolute; width: 10px; z-index: 1298; } .mce-content-body div.mce-resizehandle:hover { background-color: #4099ff; } .mce-content-body div.mce-resizehandle:nth-of-type(1) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(2) { cursor: nesw-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(3) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(4) { cursor: nesw-resize; } .mce-content-body .mce-resize-backdrop { z-index: 10000; } .mce-content-body .mce-clonedresizable { cursor: default; opacity: 0.5; outline: 1px dashed black; position: absolute; z-index: 10001; } .mce-content-body .mce-clonedresizable.mce-resizetable-columns th, .mce-content-body .mce-clonedresizable.mce-resizetable-columns td { border: 0; } .mce-content-body .mce-resize-helper { background: #555; background: rgba(0, 0, 0, 0.75); border: 1px; border-radius: 3px; color: white; display: none; font-family: sans-serif; font-size: 12px; line-height: 14px; margin: 5px 10px; padding: 5px; position: absolute; white-space: nowrap; z-index: 10002; } .tox-rtc-user-selection { position: relative; } .tox-rtc-user-cursor { bottom: 0; cursor: default; position: absolute; top: 0; width: 2px; } .tox-rtc-user-cursor::before { background-color: inherit; border-radius: 50%; content: ''; display: block; height: 8px; position: absolute; right: -3px; top: -3px; width: 8px; } .tox-rtc-user-cursor:hover::after { background-color: inherit; border-radius: 100px; box-sizing: border-box; color: #fff; content: attr(data-user); display: block; font-size: 12px; font-weight: bold; left: -5px; min-height: 8px; min-width: 8px; padding: 0 12px; position: absolute; top: -11px; white-space: nowrap; z-index: 1000; } .tox-rtc-user-selection--1 .tox-rtc-user-cursor { background-color: #2dc26b; } .tox-rtc-user-selection--2 .tox-rtc-user-cursor { background-color: #e03e2d; } .tox-rtc-user-selection--3 .tox-rtc-user-cursor { background-color: #f1c40f; } .tox-rtc-user-selection--4 .tox-rtc-user-cursor { background-color: #3598db; } .tox-rtc-user-selection--5 .tox-rtc-user-cursor { background-color: #b96ad9; } .tox-rtc-user-selection--6 .tox-rtc-user-cursor { background-color: #e67e23; } .tox-rtc-user-selection--7 .tox-rtc-user-cursor { background-color: #aaa69d; } .tox-rtc-user-selection--8 .tox-rtc-user-cursor { background-color: #f368e0; } .tox-rtc-remote-image { background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; border: 1px solid #ccc; min-height: 240px; min-width: 320px; } .mce-match-marker { background: #aaa; color: #fff; } .mce-match-marker-selected { background: #39f; color: #fff; } .mce-match-marker-selected::-moz-selection { background: #39f; color: #fff; } .mce-match-marker-selected::selection { background: #39f; color: #fff; } .mce-content-body img[data-mce-selected], .mce-content-body video[data-mce-selected], .mce-content-body audio[data-mce-selected], .mce-content-body object[data-mce-selected], .mce-content-body embed[data-mce-selected], .mce-content-body table[data-mce-selected], .mce-content-body details[data-mce-selected] { outline: 3px solid #4099ff; } .mce-content-body hr[data-mce-selected] { outline: 3px solid #4099ff; outline-offset: 1px; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { outline: 3px solid #4099ff; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { outline: 3px solid #4099ff; } .mce-content-body *[contentEditable=false][data-mce-selected] { cursor: not-allowed; outline: 3px solid #4099ff; } .mce-content-body.mce-content-readonly *[contentEditable=true]:focus, .mce-content-body.mce-content-readonly *[contentEditable=true]:hover { outline: none; } .mce-content-body *[data-mce-selected="inline-boundary"] { background-color: #4099ff; } .mce-content-body .mce-edit-focus { outline: 3px solid #4099ff; } .mce-content-body td[data-mce-selected], .mce-content-body th[data-mce-selected] { position: relative; } .mce-content-body td[data-mce-selected]::-moz-selection, .mce-content-body th[data-mce-selected]::-moz-selection { background: none; } .mce-content-body td[data-mce-selected]::selection, .mce-content-body th[data-mce-selected]::selection { background: none; } .mce-content-body td[data-mce-selected] *, .mce-content-body th[data-mce-selected] * { outline: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { background-color: rgba(180, 215, 255, 0.7); border: 1px solid transparent; bottom: -1px; content: ''; left: -1px; mix-blend-mode: lighten; position: absolute; right: -1px; top: -1px; } @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { border-color: rgba(0, 84, 180, 0.7); } } .mce-content-body img[data-mce-selected]::-moz-selection { background: none; } .mce-content-body img[data-mce-selected]::selection { background: none; } .ephox-snooker-resizer-bar { background-color: #4099ff; opacity: 0; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .ephox-snooker-resizer-cols { cursor: col-resize; } .ephox-snooker-resizer-rows { cursor: row-resize; } .ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { opacity: 1; } .mce-spellchecker-word { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; height: 2rem; } .mce-spellchecker-grammar { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; } .mce-toc { border: 1px solid gray; } .mce-toc h2 { margin: 4px; } .mce-toc li { list-style-type: none; } [data-mce-block] { display: block; } table[style*="border-width: 0px"], .mce-item-table:not([border]), .mce-item-table[border="0"], table[style*="border-width: 0px"] td, .mce-item-table:not([border]) td, .mce-item-table[border="0"] td, table[style*="border-width: 0px"] th, .mce-item-table:not([border]) th, .mce-item-table[border="0"] th, table[style*="border-width: 0px"] caption, .mce-item-table:not([border]) caption, .mce-item-table[border="0"] caption { border: 1px dashed #bbb; } .mce-visualblocks p, .mce-visualblocks h1, .mce-visualblocks h2, .mce-visualblocks h3, .mce-visualblocks h4, .mce-visualblocks h5, .mce-visualblocks h6, .mce-visualblocks div:not([data-mce-bogus]), .mce-visualblocks section, .mce-visualblocks article, .mce-visualblocks blockquote, .mce-visualblocks address, .mce-visualblocks pre, .mce-visualblocks figure, .mce-visualblocks figcaption, .mce-visualblocks hgroup, .mce-visualblocks aside, .mce-visualblocks ul, .mce-visualblocks ol, .mce-visualblocks dl { background-repeat: no-repeat; border: 1px dashed #bbb; margin-left: 3px; padding-top: 10px; } .mce-visualblocks p { background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); } .mce-visualblocks h1 { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); } .mce-visualblocks h2 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); } .mce-visualblocks h3 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); } .mce-visualblocks h4 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); } .mce-visualblocks h5 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); } .mce-visualblocks h6 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); } .mce-visualblocks div:not([data-mce-bogus]) { background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); } .mce-visualblocks section { background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); } .mce-visualblocks article { background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); } .mce-visualblocks blockquote { background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); } .mce-visualblocks address { background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); } .mce-visualblocks pre { background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); } .mce-visualblocks figure { background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); } .mce-visualblocks figcaption { border: 1px dashed #bbb; } .mce-visualblocks hgroup { background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); } .mce-visualblocks aside { background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); } .mce-visualblocks ul { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); } .mce-visualblocks ol { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); } .mce-visualblocks dl { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); } .mce-visualblocks:not([dir=rtl]) p, .mce-visualblocks:not([dir=rtl]) h1, .mce-visualblocks:not([dir=rtl]) h2, .mce-visualblocks:not([dir=rtl]) h3, .mce-visualblocks:not([dir=rtl]) h4, .mce-visualblocks:not([dir=rtl]) h5, .mce-visualblocks:not([dir=rtl]) h6, .mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), .mce-visualblocks:not([dir=rtl]) section, .mce-visualblocks:not([dir=rtl]) article, .mce-visualblocks:not([dir=rtl]) blockquote, .mce-visualblocks:not([dir=rtl]) address, .mce-visualblocks:not([dir=rtl]) pre, .mce-visualblocks:not([dir=rtl]) figure, .mce-visualblocks:not([dir=rtl]) figcaption, .mce-visualblocks:not([dir=rtl]) hgroup, .mce-visualblocks:not([dir=rtl]) aside, .mce-visualblocks:not([dir=rtl]) ul, .mce-visualblocks:not([dir=rtl]) ol, .mce-visualblocks:not([dir=rtl]) dl { margin-left: 3px; } .mce-visualblocks[dir=rtl] p, .mce-visualblocks[dir=rtl] h1, .mce-visualblocks[dir=rtl] h2, .mce-visualblocks[dir=rtl] h3, .mce-visualblocks[dir=rtl] h4, .mce-visualblocks[dir=rtl] h5, .mce-visualblocks[dir=rtl] h6, .mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), .mce-visualblocks[dir=rtl] section, .mce-visualblocks[dir=rtl] article, .mce-visualblocks[dir=rtl] blockquote, .mce-visualblocks[dir=rtl] address, .mce-visualblocks[dir=rtl] pre, .mce-visualblocks[dir=rtl] figure, .mce-visualblocks[dir=rtl] figcaption, .mce-visualblocks[dir=rtl] hgroup, .mce-visualblocks[dir=rtl] aside, .mce-visualblocks[dir=rtl] ul, .mce-visualblocks[dir=rtl] ol, .mce-visualblocks[dir=rtl] dl { background-position-x: right; margin-right: 3px; } .mce-nbsp, .mce-shy { background: #aaa; } .mce-shy::after { content: '-'; } body { font-family: sans-serif; } table { border-collapse: collapse; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/oxide-dark/content.inline.css ================================================ .mce-content-body .mce-item-anchor { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; } .mce-content-body .mce-item-anchor:empty { cursor: default; display: inline-block; height: 12px !important; padding: 0 2px; -webkit-user-modify: read-only; -moz-user-modify: read-only; -webkit-user-select: all; -moz-user-select: all; user-select: all; width: 8px !important; } .mce-content-body .mce-item-anchor:not(:empty) { background-position-x: 2px; display: inline-block; padding-left: 12px; } .mce-content-body .mce-item-anchor[data-mce-selected] { outline-offset: 1px; } .tox-comments-visible .tox-comment[contenteditable="false"]:not([data-mce-selected]), .tox-comments-visible span.tox-comment img:not([data-mce-selected]), .tox-comments-visible span.tox-comment > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #ffe89d; } .tox-comments-visible .tox-comment[contenteditable="false"][data-mce-annotation-active="true"]:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] img:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment:not([data-mce-selected]) { background-color: #ffe89d; outline: none; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"]:not([data-mce-selected="inline-boundary"]) { background-color: #fed635; } .tox-checklist > li:not(.tox-checklist--hidden) { list-style: none; margin: 0.25em 0; } .tox-checklist > li:not(.tox-checklist--hidden)::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); cursor: pointer; height: 1em; margin-left: -1.5em; margin-top: 0.125em; position: absolute; width: 1em; } .tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); } [dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { margin-left: 0; margin-right: -1.5em; } /* stylelint-disable */ /* http://prismjs.com/ */ /** * prism.js default theme for JavaScript, CSS and HTML * Based on dabblet (http://dabblet.com) * @author Lea Verou */ code[class*="language-"], pre[class*="language-"] { color: black; background: none; text-shadow: 0 1px white; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; font-size: 1em; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.5; -moz-tab-size: 4; tab-size: 4; -webkit-hyphens: none; hyphens: none; } pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { text-shadow: none; background: #b3d4fc; } pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection { text-shadow: none; background: #b3d4fc; } @media print { code[class*="language-"], pre[class*="language-"] { text-shadow: none; } } /* Code blocks */ pre[class*="language-"] { padding: 1em; margin: 0.5em 0; overflow: auto; } :not(pre) > code[class*="language-"], pre[class*="language-"] { background: #f5f2f0; } /* Inline code */ :not(pre) > code[class*="language-"] { padding: 0.1em; border-radius: 0.3em; white-space: normal; } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: slategray; } .token.punctuation { color: #999; } .token.namespace { opacity: 0.7; } .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: #905; } .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #690; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { color: #9a6e3a; /* This background color was intended by the author of this theme. */ background: hsla(0, 0%, 100%, 0.5); } .token.atrule, .token.attr-value, .token.keyword { color: #07a; } .token.function, .token.class-name { color: #DD4A68; } .token.regex, .token.important, .token.variable { color: #e90; } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } /* stylelint-enable */ .mce-content-body { overflow-wrap: break-word; word-wrap: break-word; } .mce-content-body .mce-visual-caret { background-color: black; background-color: currentColor; position: absolute; } .mce-content-body .mce-visual-caret-hidden { display: none; } .mce-content-body *[data-mce-caret] { left: -1000px; margin: 0; padding: 0; position: absolute; right: auto; top: 0; } .mce-content-body .mce-offscreen-selection { left: -2000000px; max-width: 1000000px; position: absolute; } .mce-content-body *[contentEditable=false] { cursor: default; } .mce-content-body *[contentEditable=true] { cursor: text; } .tox-cursor-format-painter { cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; } div.mce-footnotes hr { margin-inline-end: auto; margin-inline-start: 0; width: 25%; } div.mce-footnotes li > a.mce-footnotes-backlink { text-decoration: none; } @media print { sup.mce-footnote a { color: black; text-decoration: none; } div.mce-footnotes { break-inside: avoid; width: 100%; } div.mce-footnotes li > a.mce-footnotes-backlink { display: none; } } .mce-content-body figure.align-left { float: left; } .mce-content-body figure.align-right { float: right; } .mce-content-body figure.image.align-center { display: table; margin-left: auto; margin-right: auto; } .mce-preview-object { border: 1px solid gray; display: inline-block; line-height: 0; margin: 0 2px 0 2px; position: relative; } .mce-preview-object .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-preview-object[data-mce-selected="2"] .mce-shim { display: none; } .mce-content-body .mce-mergetag { cursor: default !important; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body .mce-mergetag:hover { background-color: rgba(0, 108, 231, 0.1); } .mce-content-body .mce-mergetag-affix { background-color: rgba(0, 108, 231, 0.1); color: #006ce7; } .mce-object { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; border: 1px dashed #aaa; } .mce-pagebreak { border: 1px dashed #aaa; cursor: default; display: block; height: 5px; margin-top: 15px; page-break-before: always; width: 100%; } @media print { .mce-pagebreak { border: 0; } } .tiny-pageembed .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tiny-pageembed[data-mce-selected="2"] .mce-shim { display: none; } .tiny-pageembed { display: inline-block; position: relative; } .tiny-pageembed--21by9, .tiny-pageembed--16by9, .tiny-pageembed--4by3, .tiny-pageembed--1by1 { display: block; overflow: hidden; padding: 0; position: relative; width: 100%; } .tiny-pageembed--21by9 { padding-top: 42.857143%; } .tiny-pageembed--16by9 { padding-top: 56.25%; } .tiny-pageembed--4by3 { padding-top: 75%; } .tiny-pageembed--1by1 { padding-top: 100%; } .tiny-pageembed--21by9 iframe, .tiny-pageembed--16by9 iframe, .tiny-pageembed--4by3 iframe, .tiny-pageembed--1by1 iframe { border: 0; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-content-body[data-mce-placeholder] { position: relative; } .mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { color: rgba(34, 47, 62, 0.7); content: attr(data-mce-placeholder); position: absolute; } .mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { left: 1px; } .mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { right: 1px; } .mce-content-body div.mce-resizehandle { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; height: 10px; position: absolute; width: 10px; z-index: 1298; } .mce-content-body div.mce-resizehandle:hover { background-color: #4099ff; } .mce-content-body div.mce-resizehandle:nth-of-type(1) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(2) { cursor: nesw-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(3) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(4) { cursor: nesw-resize; } .mce-content-body .mce-resize-backdrop { z-index: 10000; } .mce-content-body .mce-clonedresizable { cursor: default; opacity: 0.5; outline: 1px dashed black; position: absolute; z-index: 10001; } .mce-content-body .mce-clonedresizable.mce-resizetable-columns th, .mce-content-body .mce-clonedresizable.mce-resizetable-columns td { border: 0; } .mce-content-body .mce-resize-helper { background: #555; background: rgba(0, 0, 0, 0.75); border: 1px; border-radius: 3px; color: white; display: none; font-family: sans-serif; font-size: 12px; line-height: 14px; margin: 5px 10px; padding: 5px; position: absolute; white-space: nowrap; z-index: 10002; } .tox-rtc-user-selection { position: relative; } .tox-rtc-user-cursor { bottom: 0; cursor: default; position: absolute; top: 0; width: 2px; } .tox-rtc-user-cursor::before { background-color: inherit; border-radius: 50%; content: ''; display: block; height: 8px; position: absolute; right: -3px; top: -3px; width: 8px; } .tox-rtc-user-cursor:hover::after { background-color: inherit; border-radius: 100px; box-sizing: border-box; color: #fff; content: attr(data-user); display: block; font-size: 12px; font-weight: bold; left: -5px; min-height: 8px; min-width: 8px; padding: 0 12px; position: absolute; top: -11px; white-space: nowrap; z-index: 1000; } .tox-rtc-user-selection--1 .tox-rtc-user-cursor { background-color: #2dc26b; } .tox-rtc-user-selection--2 .tox-rtc-user-cursor { background-color: #e03e2d; } .tox-rtc-user-selection--3 .tox-rtc-user-cursor { background-color: #f1c40f; } .tox-rtc-user-selection--4 .tox-rtc-user-cursor { background-color: #3598db; } .tox-rtc-user-selection--5 .tox-rtc-user-cursor { background-color: #b96ad9; } .tox-rtc-user-selection--6 .tox-rtc-user-cursor { background-color: #e67e23; } .tox-rtc-user-selection--7 .tox-rtc-user-cursor { background-color: #aaa69d; } .tox-rtc-user-selection--8 .tox-rtc-user-cursor { background-color: #f368e0; } .tox-rtc-remote-image { background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; border: 1px solid #ccc; min-height: 240px; min-width: 320px; } .mce-match-marker { background: #aaa; color: #fff; } .mce-match-marker-selected { background: #39f; color: #fff; } .mce-match-marker-selected::-moz-selection { background: #39f; color: #fff; } .mce-match-marker-selected::selection { background: #39f; color: #fff; } .mce-content-body img[data-mce-selected], .mce-content-body video[data-mce-selected], .mce-content-body audio[data-mce-selected], .mce-content-body object[data-mce-selected], .mce-content-body embed[data-mce-selected], .mce-content-body table[data-mce-selected], .mce-content-body details[data-mce-selected] { outline: 3px solid #b4d7ff; } .mce-content-body hr[data-mce-selected] { outline: 3px solid #b4d7ff; outline-offset: 1px; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false][data-mce-selected] { cursor: not-allowed; outline: 3px solid #b4d7ff; } .mce-content-body.mce-content-readonly *[contentEditable=true]:focus, .mce-content-body.mce-content-readonly *[contentEditable=true]:hover { outline: none; } .mce-content-body *[data-mce-selected="inline-boundary"] { background-color: #b4d7ff; } .mce-content-body .mce-edit-focus { outline: 3px solid #b4d7ff; } .mce-content-body td[data-mce-selected], .mce-content-body th[data-mce-selected] { position: relative; } .mce-content-body td[data-mce-selected]::-moz-selection, .mce-content-body th[data-mce-selected]::-moz-selection { background: none; } .mce-content-body td[data-mce-selected]::selection, .mce-content-body th[data-mce-selected]::selection { background: none; } .mce-content-body td[data-mce-selected] *, .mce-content-body th[data-mce-selected] * { outline: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { background-color: rgba(180, 215, 255, 0.7); border: 1px solid rgba(180, 215, 255, 0.7); bottom: -1px; content: ''; left: -1px; mix-blend-mode: multiply; position: absolute; right: -1px; top: -1px; } @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { border-color: rgba(0, 84, 180, 0.7); } } .mce-content-body img[data-mce-selected]::-moz-selection { background: none; } .mce-content-body img[data-mce-selected]::selection { background: none; } .ephox-snooker-resizer-bar { background-color: #b4d7ff; opacity: 0; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .ephox-snooker-resizer-cols { cursor: col-resize; } .ephox-snooker-resizer-rows { cursor: row-resize; } .ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { opacity: 1; } .mce-spellchecker-word { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; height: 2rem; } .mce-spellchecker-grammar { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; } .mce-toc { border: 1px solid gray; } .mce-toc h2 { margin: 4px; } .mce-toc li { list-style-type: none; } [data-mce-block] { display: block; } table[style*="border-width: 0px"], .mce-item-table:not([border]), .mce-item-table[border="0"], table[style*="border-width: 0px"] td, .mce-item-table:not([border]) td, .mce-item-table[border="0"] td, table[style*="border-width: 0px"] th, .mce-item-table:not([border]) th, .mce-item-table[border="0"] th, table[style*="border-width: 0px"] caption, .mce-item-table:not([border]) caption, .mce-item-table[border="0"] caption { border: 1px dashed #bbb; } .mce-visualblocks p, .mce-visualblocks h1, .mce-visualblocks h2, .mce-visualblocks h3, .mce-visualblocks h4, .mce-visualblocks h5, .mce-visualblocks h6, .mce-visualblocks div:not([data-mce-bogus]), .mce-visualblocks section, .mce-visualblocks article, .mce-visualblocks blockquote, .mce-visualblocks address, .mce-visualblocks pre, .mce-visualblocks figure, .mce-visualblocks figcaption, .mce-visualblocks hgroup, .mce-visualblocks aside, .mce-visualblocks ul, .mce-visualblocks ol, .mce-visualblocks dl { background-repeat: no-repeat; border: 1px dashed #bbb; margin-left: 3px; padding-top: 10px; } .mce-visualblocks p { background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); } .mce-visualblocks h1 { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); } .mce-visualblocks h2 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); } .mce-visualblocks h3 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); } .mce-visualblocks h4 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); } .mce-visualblocks h5 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); } .mce-visualblocks h6 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); } .mce-visualblocks div:not([data-mce-bogus]) { background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); } .mce-visualblocks section { background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); } .mce-visualblocks article { background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); } .mce-visualblocks blockquote { background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); } .mce-visualblocks address { background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); } .mce-visualblocks pre { background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); } .mce-visualblocks figure { background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); } .mce-visualblocks figcaption { border: 1px dashed #bbb; } .mce-visualblocks hgroup { background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); } .mce-visualblocks aside { background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); } .mce-visualblocks ul { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); } .mce-visualblocks ol { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); } .mce-visualblocks dl { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); } .mce-visualblocks:not([dir=rtl]) p, .mce-visualblocks:not([dir=rtl]) h1, .mce-visualblocks:not([dir=rtl]) h2, .mce-visualblocks:not([dir=rtl]) h3, .mce-visualblocks:not([dir=rtl]) h4, .mce-visualblocks:not([dir=rtl]) h5, .mce-visualblocks:not([dir=rtl]) h6, .mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), .mce-visualblocks:not([dir=rtl]) section, .mce-visualblocks:not([dir=rtl]) article, .mce-visualblocks:not([dir=rtl]) blockquote, .mce-visualblocks:not([dir=rtl]) address, .mce-visualblocks:not([dir=rtl]) pre, .mce-visualblocks:not([dir=rtl]) figure, .mce-visualblocks:not([dir=rtl]) figcaption, .mce-visualblocks:not([dir=rtl]) hgroup, .mce-visualblocks:not([dir=rtl]) aside, .mce-visualblocks:not([dir=rtl]) ul, .mce-visualblocks:not([dir=rtl]) ol, .mce-visualblocks:not([dir=rtl]) dl { margin-left: 3px; } .mce-visualblocks[dir=rtl] p, .mce-visualblocks[dir=rtl] h1, .mce-visualblocks[dir=rtl] h2, .mce-visualblocks[dir=rtl] h3, .mce-visualblocks[dir=rtl] h4, .mce-visualblocks[dir=rtl] h5, .mce-visualblocks[dir=rtl] h6, .mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), .mce-visualblocks[dir=rtl] section, .mce-visualblocks[dir=rtl] article, .mce-visualblocks[dir=rtl] blockquote, .mce-visualblocks[dir=rtl] address, .mce-visualblocks[dir=rtl] pre, .mce-visualblocks[dir=rtl] figure, .mce-visualblocks[dir=rtl] figcaption, .mce-visualblocks[dir=rtl] hgroup, .mce-visualblocks[dir=rtl] aside, .mce-visualblocks[dir=rtl] ul, .mce-visualblocks[dir=rtl] ol, .mce-visualblocks[dir=rtl] dl { background-position-x: right; margin-right: 3px; } .mce-nbsp, .mce-shy { background: #aaa; } .mce-shy::after { content: '-'; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/oxide-dark/skin.css ================================================ .tox { box-shadow: none; box-sizing: content-box; color: #222f3e; cursor: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; font-style: normal; font-weight: normal; line-height: normal; -webkit-tap-highlight-color: transparent; text-decoration: none; text-shadow: none; text-transform: none; vertical-align: initial; white-space: normal; } .tox *:not(svg):not(rect) { box-sizing: inherit; color: inherit; cursor: inherit; direction: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; -webkit-tap-highlight-color: inherit; text-align: inherit; text-decoration: inherit; text-shadow: inherit; text-transform: inherit; vertical-align: inherit; white-space: inherit; } .tox *:not(svg):not(rect) { /* stylelint-disable-line no-duplicate-selectors */ background: transparent; border: 0; box-shadow: none; float: none; height: auto; margin: 0; max-width: none; outline: 0; padding: 0; position: static; width: auto; } .tox:not([dir=rtl]) { direction: ltr; text-align: left; } .tox[dir=rtl] { direction: rtl; text-align: right; } .tox-tinymce { border: 2px solid #161f29; border-radius: 10px; box-shadow: none; box-sizing: border-box; display: flex; flex-direction: column; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; overflow: hidden; position: relative; visibility: inherit !important; } .tox.tox-tinymce-inline { border: none; box-shadow: none; overflow: initial; } .tox.tox-tinymce-inline .tox-editor-container { overflow: initial; } .tox.tox-tinymce-inline .tox-editor-header { background-color: #222F3E; border: 2px solid #161f29; border-radius: 10px; box-shadow: none; overflow: hidden; } .tox-tinymce-aux { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; z-index: 1300; } .tox-tinymce *:focus, .tox-tinymce-aux *:focus { outline: none; } button::-moz-focus-inner { border: 0; } .tox[dir=rtl] .tox-icon--flip svg { transform: rotateY(180deg); } .tox .accessibility-issue__header { align-items: center; display: flex; margin-bottom: 4px; } .tox .accessibility-issue__description { align-items: stretch; border-radius: 6px; display: flex; justify-content: space-between; } .tox .accessibility-issue__description > div { padding-bottom: 4px; } .tox .accessibility-issue__description > div > div { align-items: center; display: flex; margin-bottom: 4px; } .tox .accessibility-issue__description > div > div .tox-icon svg { display: block; } .tox .accessibility-issue__repair { margin-top: 16px; } .tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { background-color: rgba(0, 101, 216, 0.4); color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { fill: #fff; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon { background-color: #006ce7; color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus { background-color: #0060ce; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active { background-color: #0054b4; } .tox .tox-dialog__body-content .accessibility-issue--warn { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { background-color: rgba(255, 165, 0, 0.5); color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { fill: #fff; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon { background-color: #FFE89D; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus { background-color: #F2D574; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active { background-color: #E8C657; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { background-color: rgba(204, 0, 0, 0.5); color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { fill: #fff; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon { background-color: #F2BFBF; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus { background-color: #E9A4A4; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active { background-color: #EE9494; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { background-color: rgba(120, 171, 70, 0.5); color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > *:last-child { display: none; } .tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { fill: #fff; } .tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1, .tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { font-size: 14px; margin-top: 0; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button { margin-left: 4px; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { margin-left: auto; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description { padding: 4px 4px 4px 8px; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button { margin-right: 4px; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { margin-right: auto; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description { padding: 4px 8px 4px 4px; } .tox .tox-advtemplate .tox-form__grid { flex: 1; } .tox .tox-advtemplate .tox-form__grid > div:first-child { display: flex; flex-direction: column; width: 30%; } .tox .tox-advtemplate .tox-form__grid > div:first-child > div:nth-child(2) { flex-basis: 0; flex-grow: 1; overflow: auto; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid > div:first-child { width: 100%; } } .tox .tox-advtemplate iframe { border-color: #161f29; border-radius: 10px; border-style: solid; border-width: 1px; margin: 0 10px; } .tox .tox-anchorbar { display: flex; flex: 0 0 auto; } .tox .tox-bottom-anchorbar { display: flex; flex: 0 0 auto; } .tox .tox-bar { display: flex; flex: 0 0 auto; } .tox .tox-button { background-color: #006ce7; background-image: none; background-position: 0 0; background-repeat: repeat; border-color: #006ce7; border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #fff; cursor: pointer; display: inline-block; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 14px; font-style: normal; font-weight: bold; letter-spacing: normal; line-height: 24px; margin: 0; outline: none; padding: 4px 16px; position: relative; text-align: center; text-decoration: none; text-transform: none; white-space: nowrap; } .tox .tox-button::before { border-radius: 6px; bottom: -1px; box-shadow: inset 0 0 0 2px #fff, 0 0 0 1px #006ce7, 0 0 0 3px rgba(0, 108, 231, 0.25); content: ''; left: -1px; opacity: 0; pointer-events: none; position: absolute; right: -1px; top: -1px; } .tox .tox-button[disabled] { background-color: #006ce7; background-image: none; border-color: #006ce7; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-button:focus:not(:disabled) { background-color: #0060ce; background-image: none; border-color: #0060ce; box-shadow: none; color: #fff; } .tox .tox-button:focus-visible:not(:disabled)::before { opacity: 1; } .tox .tox-button:hover:not(:disabled) { background-color: #0060ce; background-image: none; border-color: #0060ce; box-shadow: none; color: #fff; } .tox .tox-button:active:not(:disabled) { background-color: #0054b4; background-image: none; border-color: #0054b4; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled { background-color: #0054b4; background-image: none; border-color: #0054b4; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled[disabled] { background-color: #0054b4; background-image: none; border-color: #0054b4; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-button.tox-button--enabled:focus:not(:disabled) { background-color: #00489b; background-image: none; border-color: #00489b; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled:hover:not(:disabled) { background-color: #00489b; background-image: none; border-color: #00489b; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled:active:not(:disabled) { background-color: #003c81; background-image: none; border-color: #003c81; box-shadow: none; color: #fff; } .tox .tox-button--icon-and-text, .tox .tox-button.tox-button--icon-and-text, .tox .tox-button.tox-button--secondary.tox-button--icon-and-text { display: flex; padding: 5px 4px; } .tox .tox-button--icon-and-text .tox-icon svg, .tox .tox-button.tox-button--icon-and-text .tox-icon svg, .tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg { display: block; fill: currentColor; } .tox .tox-button--secondary { background-color: #3d546f; background-image: none; background-position: 0 0; background-repeat: repeat; border-color: #3d546f; border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; color: #fff; font-size: 14px; font-style: normal; font-weight: bold; letter-spacing: normal; outline: none; padding: 4px 16px; text-decoration: none; text-transform: none; } .tox .tox-button--secondary[disabled] { background-color: #3d546f; background-image: none; border-color: #3d546f; box-shadow: none; color: rgba(255, 255, 255, 0.5); } .tox .tox-button--secondary:focus:not(:disabled) { background-color: #34485f; background-image: none; border-color: #34485f; box-shadow: none; color: #fff; } .tox .tox-button--secondary:hover:not(:disabled) { background-color: #34485f; background-image: none; border-color: #34485f; box-shadow: none; color: #fff; } .tox .tox-button--secondary:active:not(:disabled) { background-color: #2b3b4e; background-image: none; border-color: #2b3b4e; box-shadow: none; color: #fff; } .tox .tox-button--secondary.tox-button--enabled { background-color: #2b5c93; background-image: none; border-color: #2b5c93; box-shadow: none; color: #fff; } .tox .tox-button--secondary.tox-button--enabled[disabled] { background-color: #2b5c93; background-image: none; border-color: #2b5c93; box-shadow: none; color: rgba(255, 255, 255, 0.5); } .tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled) { background-color: #254f80; background-image: none; border-color: #254f80; box-shadow: none; color: #fff; } .tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled) { background-color: #254f80; background-image: none; border-color: #254f80; box-shadow: none; color: #fff; } .tox .tox-button--secondary.tox-button--enabled:active:not(:disabled) { background-color: #1f436c; background-image: none; border-color: #1f436c; box-shadow: none; color: #fff; } .tox .tox-button--icon, .tox .tox-button.tox-button--icon, .tox .tox-button.tox-button--secondary.tox-button--icon { padding: 4px; } .tox .tox-button--icon .tox-icon svg, .tox .tox-button.tox-button--icon .tox-icon svg, .tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { display: block; fill: currentColor; } .tox .tox-button-link { background: 0; border: none; box-sizing: border-box; cursor: pointer; display: inline-block; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; font-weight: normal; line-height: 1.3; margin: 0; padding: 0; white-space: nowrap; } .tox .tox-button-link--sm { font-size: 14px; } .tox .tox-button--naked { background-color: transparent; border-color: transparent; box-shadow: unset; color: #fff; } .tox .tox-button--naked[disabled] { background-color: rgba(255, 255, 255, 0.2); border-color: transparent; box-shadow: unset; color: rgba(255, 255, 255, 0.5); } .tox .tox-button--naked:hover:not(:disabled) { background-color: rgba(255, 255, 255, 0.2); border-color: transparent; box-shadow: unset; color: #fff; } .tox .tox-button--naked:focus:not(:disabled) { background-color: rgba(255, 255, 255, 0.2); border-color: transparent; box-shadow: unset; color: #fff; } .tox .tox-button--naked:active:not(:disabled) { background-color: rgba(255, 255, 255, 0.3); border-color: transparent; box-shadow: unset; color: #fff; } .tox .tox-button--naked .tox-icon svg { fill: currentColor; } .tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { color: #fff; } .tox .tox-checkbox { align-items: center; border-radius: 6px; cursor: pointer; display: flex; height: 36px; min-width: 36px; } .tox .tox-checkbox__input { /* Hide from view but visible to screen readers */ height: 1px; overflow: hidden; position: absolute; top: auto; width: 1px; } .tox .tox-checkbox__icons { align-items: center; border-radius: 6px; box-shadow: 0 0 0 2px transparent; box-sizing: content-box; display: flex; height: 24px; justify-content: center; padding: calc(4px - 1px); width: 24px; } .tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: block; fill: rgba(255, 255, 255, 0.2); } .tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { display: none; fill: #006ce7; } .tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { display: none; fill: #006ce7; } .tox .tox-checkbox--disabled { color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { fill: rgba(255, 255, 255, 0.5); } .tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: none; } .tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { display: block; } .tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: none; } .tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { display: block; } .tox input.tox-checkbox__input:focus + .tox-checkbox__icons { border-radius: 6px; box-shadow: inset 0 0 0 1px #006ce7; padding: calc(4px - 1px); } .tox:not([dir=rtl]) .tox-checkbox__label { margin-left: 4px; } .tox:not([dir=rtl]) .tox-checkbox__input { left: -10000px; } .tox:not([dir=rtl]) .tox-bar .tox-checkbox { margin-left: 4px; } .tox[dir=rtl] .tox-checkbox__label { margin-right: 4px; } .tox[dir=rtl] .tox-checkbox__input { right: -10000px; } .tox[dir=rtl] .tox-bar .tox-checkbox { margin-right: 4px; } .tox { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-collection--toolbar .tox-collection__group { display: flex; padding: 0; } .tox .tox-collection--grid .tox-collection__group { display: flex; flex-wrap: wrap; max-height: 208px; overflow-x: hidden; overflow-y: auto; padding: 0; } .tox .tox-collection--list .tox-collection__group { border-bottom-width: 0; border-color: rgba(255, 255, 255, 0.15); border-left-width: 0; border-right-width: 0; border-style: solid; border-top-width: 1px; padding: 4px 0; } .tox .tox-collection--list .tox-collection__group:first-child { border-top-width: 0; } .tox .tox-collection__group-heading { background-color: rgba(255, 255, 255, 0.15); color: rgba(255, 255, 255, 0.5); cursor: default; font-size: 12px; font-style: normal; font-weight: normal; margin-bottom: 4px; margin-top: -4px; padding: 4px 8px; text-transform: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .tox .tox-collection__item { align-items: center; border-radius: 3px; color: #fff; display: flex; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .tox .tox-collection--list .tox-collection__item { padding: 4px 8px; } .tox .tox-collection--toolbar .tox-collection__item { border-radius: 3px; padding: 4px; } .tox .tox-collection--grid .tox-collection__item { border-radius: 3px; padding: 4px; } .tox .tox-collection--list .tox-collection__item--enabled { background-color: #2b3b4e; color: #fff; } .tox .tox-collection--list .tox-collection__item--active { background-color: #3389ec; } .tox .tox-collection--toolbar .tox-collection__item--enabled { background-color: #599fef; color: #fff; } .tox .tox-collection--toolbar .tox-collection__item--active { background-color: #3389ec; } .tox .tox-collection--grid .tox-collection__item--enabled { background-color: #599fef; color: #fff; } .tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { background-color: #3389ec; color: #fff; } .tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { color: #fff; } .tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { color: #fff; } .tox .tox-collection__item-icon, .tox .tox-collection__item-checkmark { align-items: center; display: flex; height: 24px; justify-content: center; width: 24px; } .tox .tox-collection__item-icon svg, .tox .tox-collection__item-checkmark svg { fill: currentColor; } .tox .tox-collection--toolbar-lg .tox-collection__item-icon { height: 48px; width: 48px; } .tox .tox-collection__item-label { color: currentColor; display: inline-block; flex: 1; font-size: 14px; font-style: normal; font-weight: normal; line-height: 24px; text-transform: none; word-break: break-all; } .tox .tox-collection__item-accessory { color: rgba(255, 255, 255, 0.5); display: inline-block; font-size: 14px; height: 24px; line-height: 24px; text-transform: none; } .tox .tox-collection__item-caret { align-items: center; display: flex; min-height: 24px; } .tox .tox-collection__item-caret::after { content: ''; font-size: 0; min-height: inherit; } .tox .tox-collection__item-caret svg { fill: #fff; } .tox .tox-collection__item--state-disabled { background-color: transparent; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg { display: none; } .tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory + .tox-collection__item-checkmark { display: none; } .tox .tox-collection--horizontal { background-color: #2b3b4e; border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 6px; box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: nowrap; margin-bottom: 0; overflow-x: auto; padding: 0; } .tox .tox-collection--horizontal .tox-collection__group { align-items: center; display: flex; flex-wrap: nowrap; margin: 0; padding: 0 4px; } .tox .tox-collection--horizontal .tox-collection__item { height: 28px; margin: 6px 1px 5px 0; padding: 0 4px; } .tox .tox-collection--horizontal .tox-collection__item-label { white-space: nowrap; } .tox .tox-collection--horizontal .tox-collection__item-caret { margin-left: 4px; } .tox .tox-collection__item-container { display: flex; } .tox .tox-collection__item-container--row { align-items: center; flex: 1 1 auto; flex-direction: row; } .tox .tox-collection__item-container--row.tox-collection__item-container--align-left { margin-right: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--align-right { justify-content: flex-end; margin-left: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { align-items: flex-start; margin-bottom: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { align-items: center; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { align-items: flex-end; margin-top: auto; } .tox .tox-collection__item-container--column { align-self: center; flex: 1 1 auto; flex-direction: column; } .tox .tox-collection__item-container--column.tox-collection__item-container--align-left { align-items: flex-start; } .tox .tox-collection__item-container--column.tox-collection__item-container--align-right { align-items: flex-end; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { align-self: flex-start; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { align-self: center; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { align-self: flex-end; } .tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { border-right: 1px solid transparent; } .tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > *:not(:first-child) { margin-left: 8px; } .tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { margin-left: 4px; } .tox:not([dir=rtl]) .tox-collection__item-accessory { margin-left: 16px; text-align: right; } .tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret { margin-left: 16px; } .tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { border-left: 1px solid transparent; } .tox[dir=rtl] .tox-collection--list .tox-collection__item > *:not(:first-child) { margin-right: 8px; } .tox[dir=rtl] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { margin-right: 4px; } .tox[dir=rtl] .tox-collection__item-accessory { margin-right: 16px; text-align: left; } .tox[dir=rtl] .tox-collection .tox-collection__item-caret { margin-right: 16px; transform: rotateY(180deg); } .tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret { margin-right: 4px; } .tox .tox-color-picker-container { display: flex; flex-direction: row; height: 225px; margin: 0; } .tox .tox-sv-palette { box-sizing: border-box; display: flex; height: 100%; } .tox .tox-sv-palette-spectrum { height: 100%; } .tox .tox-sv-palette, .tox .tox-sv-palette-spectrum { width: 225px; } .tox .tox-sv-palette-thumb { background: none; border: 1px solid black; border-radius: 50%; box-sizing: content-box; height: 12px; position: absolute; width: 12px; } .tox .tox-sv-palette-inner-thumb { border: 1px solid white; border-radius: 50%; height: 10px; position: absolute; width: 10px; } .tox .tox-hue-slider { box-sizing: border-box; height: 100%; width: 25px; } .tox .tox-hue-slider-spectrum { background: linear-gradient(to bottom, #f00, #ff0080, #f0f, #8000ff, #00f, #0080ff, #0ff, #00ff80, #0f0, #80ff00, #ff0, #ff8000, #f00); height: 100%; width: 100%; } .tox .tox-hue-slider, .tox .tox-hue-slider-spectrum { width: 20px; } .tox .tox-hue-slider-thumb { background: white; border: 1px solid black; box-sizing: content-box; height: 4px; width: 100%; } .tox .tox-rgb-form { display: flex; flex-direction: column; justify-content: space-between; } .tox .tox-rgb-form div { align-items: center; display: flex; justify-content: space-between; margin-bottom: 5px; width: inherit; } .tox .tox-rgb-form input { width: 6em; } .tox .tox-rgb-form input.tox-invalid { /* Need !important to override Chrome's focus styling unfortunately */ border: 1px solid red !important; } .tox .tox-rgb-form .tox-rgba-preview { border: 1px solid black; flex-grow: 2; margin-bottom: 0; } .tox:not([dir=rtl]) .tox-sv-palette { margin-right: 15px; } .tox:not([dir=rtl]) .tox-hue-slider { margin-right: 15px; } .tox:not([dir=rtl]) .tox-hue-slider-thumb { margin-left: -1px; } .tox:not([dir=rtl]) .tox-rgb-form label { margin-right: 0.5em; } .tox[dir=rtl] .tox-sv-palette { margin-left: 15px; } .tox[dir=rtl] .tox-hue-slider { margin-left: 15px; } .tox[dir=rtl] .tox-hue-slider-thumb { margin-right: -1px; } .tox[dir=rtl] .tox-rgb-form label { margin-left: 0.5em; } .tox .tox-toolbar .tox-swatches, .tox .tox-toolbar__primary .tox-swatches, .tox .tox-toolbar__overflow .tox-swatches { margin: 5px 0 6px 11px; } .tox .tox-collection--list .tox-collection__group .tox-swatches-menu { border: 0; margin: -4px -4px; } .tox .tox-swatches__row { display: flex; } .tox .tox-swatch { height: 30px; transition: transform 0.15s, box-shadow 0.15s; width: 30px; } .tox .tox-swatch:hover, .tox .tox-swatch:focus { box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; transform: scale(0.8); } .tox .tox-swatch--remove { align-items: center; display: flex; justify-content: center; } .tox .tox-swatch--remove svg path { stroke: #e74c3c; } .tox .tox-swatches__picker-btn { align-items: center; background-color: transparent; border: 0; cursor: pointer; display: flex; height: 30px; justify-content: center; outline: none; padding: 0; width: 30px; } .tox .tox-swatches__picker-btn svg { fill: #fff; height: 24px; width: 24px; } .tox .tox-swatches__picker-btn:hover { background: #3389ec; } .tox div.tox-swatch:not(.tox-swatch--remove) svg { display: none; fill: #fff; height: 24px; margin: calc((30px - 24px) / 2) calc((30px - 24px) / 2); width: 24px; } .tox div.tox-swatch:not(.tox-swatch--remove) svg path { fill: #fff; paint-order: stroke; stroke: #222f3e; stroke-width: 2px; } .tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg { display: block; } .tox:not([dir=rtl]) .tox-swatches__picker-btn { margin-left: auto; } .tox[dir=rtl] .tox-swatches__picker-btn { margin-right: auto; } .tox .tox-comment-thread { background: #2b3b4e; position: relative; } .tox .tox-comment-thread > *:not(:first-child) { margin-top: 8px; } .tox .tox-comment { background: #2b3b4e; border: 1px solid #161f29; border-radius: 6px; box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); padding: 8px 8px 16px 8px; position: relative; } .tox .tox-comment__header { align-items: center; color: #fff; display: flex; justify-content: space-between; } .tox .tox-comment__date { color: #fff; font-size: 12px; line-height: 18px; } .tox .tox-comment__body { color: #fff; font-size: 14px; font-style: normal; font-weight: normal; line-height: 1.3; margin-top: 8px; position: relative; text-transform: initial; } .tox .tox-comment__body textarea { resize: none; white-space: normal; width: 100%; } .tox .tox-comment__expander { padding-top: 8px; } .tox .tox-comment__expander p { color: rgba(255, 255, 255, 0.5); font-size: 14px; font-style: normal; } .tox .tox-comment__body p { margin: 0; } .tox .tox-comment__buttonspacing { padding-top: 16px; text-align: center; } .tox .tox-comment-thread__overlay::after { background: #2b3b4e; bottom: 0; content: ""; display: flex; left: 0; opacity: 0.9; position: absolute; right: 0; top: 0; z-index: 5; } .tox .tox-comment__reply { display: flex; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; margin-top: 8px; } .tox .tox-comment__reply > *:first-child { margin-bottom: 8px; width: 100%; } .tox .tox-comment__edit { display: flex; flex-wrap: wrap; justify-content: flex-end; margin-top: 16px; } .tox .tox-comment__gradient::after { background: linear-gradient(rgba(43, 59, 78, 0), #2b3b4e); bottom: 0; content: ""; display: block; height: 5em; margin-top: -40px; position: absolute; width: 100%; } .tox .tox-comment__overlay { background: #2b3b4e; bottom: 0; display: flex; flex-direction: column; flex-grow: 1; left: 0; opacity: 0.9; position: absolute; right: 0; text-align: center; top: 0; z-index: 5; } .tox .tox-comment__loading-text { align-items: center; color: #fff; display: flex; flex-direction: column; position: relative; } .tox .tox-comment__loading-text > div { padding-bottom: 16px; } .tox .tox-comment__overlaytext { bottom: 0; flex-direction: column; font-size: 14px; left: 0; padding: 1em; position: absolute; right: 0; top: 0; z-index: 10; } .tox .tox-comment__overlaytext p { background-color: #2b3b4e; box-shadow: 0 0 8px 8px #2b3b4e; color: #fff; text-align: center; } .tox .tox-comment__overlaytext div:nth-of-type(2) { font-size: 0.8em; } .tox .tox-comment__busy-spinner { align-items: center; background-color: #2b3b4e; bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; z-index: 20; } .tox .tox-comment__scroll { display: flex; flex-direction: column; flex-shrink: 1; overflow: auto; } .tox .tox-conversations { margin: 8px; } .tox:not([dir=rtl]) .tox-comment__edit { margin-left: 8px; } .tox:not([dir=rtl]) .tox-comment__buttonspacing > *:last-child, .tox:not([dir=rtl]) .tox-comment__edit > *:last-child, .tox:not([dir=rtl]) .tox-comment__reply > *:last-child { margin-left: 8px; } .tox[dir=rtl] .tox-comment__edit { margin-right: 8px; } .tox[dir=rtl] .tox-comment__buttonspacing > *:last-child, .tox[dir=rtl] .tox-comment__edit > *:last-child, .tox[dir=rtl] .tox-comment__reply > *:last-child { margin-right: 8px; } .tox .tox-user { align-items: center; display: flex; } .tox .tox-user__avatar svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-user__avatar img { border-radius: 50%; height: 36px; object-fit: cover; vertical-align: middle; width: 36px; } .tox .tox-user__name { color: #fff; font-size: 14px; font-style: normal; font-weight: bold; line-height: 18px; text-transform: none; } .tox:not([dir=rtl]) .tox-user__avatar svg, .tox:not([dir=rtl]) .tox-user__avatar img { margin-right: 8px; } .tox:not([dir=rtl]) .tox-user__avatar + .tox-user__name { margin-left: 8px; } .tox[dir=rtl] .tox-user__avatar svg, .tox[dir=rtl] .tox-user__avatar img { margin-left: 8px; } .tox[dir=rtl] .tox-user__avatar + .tox-user__name { margin-right: 8px; } .tox .tox-dialog-wrap { align-items: center; bottom: 0; display: flex; justify-content: center; left: 0; position: fixed; right: 0; top: 0; z-index: 1100; } .tox .tox-dialog-wrap__backdrop { background-color: rgba(34, 47, 62, 0.75); bottom: 0; left: 0; position: absolute; right: 0; top: 0; z-index: 1; } .tox .tox-dialog-wrap__backdrop--opaque { background-color: #222F3E; } .tox .tox-dialog { background-color: #2b3b4e; border-color: #161f29; border-radius: 10px; border-style: solid; border-width: 0px; box-shadow: 0 16px 16px -10px rgba(34, 47, 62, 0.15), 0 0 40px 1px rgba(34, 47, 62, 0.15); display: flex; flex-direction: column; max-height: 100%; max-width: 480px; overflow: hidden; position: relative; width: 95vw; z-index: 2; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog { align-self: flex-start; margin: 8px auto; max-height: calc(100vh - 8px * 2); width: calc(100vw - 16px); } } .tox .tox-dialog-inline { z-index: 1100; } .tox .tox-dialog__header { align-items: center; background-color: #2b3b4e; border-bottom: none; color: #fff; display: flex; font-size: 16px; justify-content: space-between; padding: 8px 16px 0 16px; position: relative; } .tox .tox-dialog__header .tox-button { z-index: 1; } .tox .tox-dialog__draghandle { cursor: grab; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tox .tox-dialog__draghandle:active { cursor: grabbing; } .tox .tox-dialog__dismiss { margin-left: auto; } .tox .tox-dialog__title { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 20px; font-style: normal; font-weight: normal; line-height: 1.3; margin: 0; text-transform: none; } .tox .tox-dialog__body { color: #fff; display: flex; flex: 1; font-size: 16px; font-style: normal; font-weight: normal; line-height: 1.3; min-width: 0; text-align: left; text-transform: none; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog__body { flex-direction: column; } } .tox .tox-dialog__body-nav { align-items: flex-start; display: flex; flex-direction: column; flex-shrink: 0; padding: 16px 16px; } @media only screen and (min-width: 768px ) { .tox .tox-dialog__body-nav { max-width: 11em; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { flex-direction: row; -webkit-overflow-scrolling: touch; overflow-x: auto; padding-bottom: 0; } } .tox .tox-dialog__body-nav-item { border-bottom: 2px solid transparent; color: rgba(255, 255, 255, 0.5); display: inline-block; flex-shrink: 0; font-size: 14px; line-height: 1.3; margin-bottom: 8px; max-width: 13em; text-decoration: none; } .tox .tox-dialog__body-nav-item:focus { background-color: rgba(0, 108, 231, 0.1); } .tox .tox-dialog__body-nav-item--active { border-bottom: 2px solid #006ce7; color: #006ce7; } .tox .tox-dialog__body-content { box-sizing: border-box; display: flex; flex: 1; flex-direction: column; max-height: min(650px, calc(100vh - 110px)); overflow: auto; -webkit-overflow-scrolling: touch; padding: 16px 16px; } .tox .tox-dialog__body-content > * { margin-bottom: 0; margin-top: 16px; } .tox .tox-dialog__body-content > *:first-child { margin-top: 0; } .tox .tox-dialog__body-content > *:last-child { margin-bottom: 0; } .tox .tox-dialog__body-content > *:only-child { margin-bottom: 0; margin-top: 0; } .tox .tox-dialog__body-content a { color: #006ce7; cursor: pointer; text-decoration: none; } .tox .tox-dialog__body-content a:hover, .tox .tox-dialog__body-content a:focus { color: #0054b4; text-decoration: none; } .tox .tox-dialog__body-content a:active { color: #0054b4; text-decoration: none; } .tox .tox-dialog__body-content svg { fill: #fff; } .tox .tox-dialog__body-content strong { font-weight: bold; } .tox .tox-dialog__body-content ul { list-style-type: disc; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dd { padding-inline-start: 2.5rem; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dl { margin-bottom: 16px; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dl, .tox .tox-dialog__body-content dd, .tox .tox-dialog__body-content dt { display: block; margin-inline-end: 0; margin-inline-start: 0; } .tox .tox-dialog__body-content .tox-form__group h1 { color: #fff; font-size: 20px; font-style: normal; font-weight: bold; letter-spacing: normal; margin-bottom: 16px; margin-top: 2rem; text-transform: none; } .tox .tox-dialog__body-content .tox-form__group h2 { color: #fff; font-size: 16px; font-style: normal; font-weight: bold; letter-spacing: normal; margin-bottom: 16px; margin-top: 2rem; text-transform: none; } .tox .tox-dialog__body-content .tox-form__group p { margin-bottom: 16px; } .tox .tox-dialog__body-content .tox-form__group h1:first-child, .tox .tox-dialog__body-content .tox-form__group h2:first-child, .tox .tox-dialog__body-content .tox-form__group p:first-child { margin-top: 0; } .tox .tox-dialog__body-content .tox-form__group h1:last-child, .tox .tox-dialog__body-content .tox-form__group h2:last-child, .tox .tox-dialog__body-content .tox-form__group p:last-child { margin-bottom: 0; } .tox .tox-dialog__body-content .tox-form__group h1:only-child, .tox .tox-dialog__body-content .tox-form__group h2:only-child, .tox .tox-dialog__body-content .tox-form__group p:only-child { margin-bottom: 0; margin-top: 0; } .tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center { text-align: center; } .tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end { text-align: end; } .tox .tox-dialog--width-lg { height: 650px; max-width: 1200px; } .tox .tox-dialog--fullscreen { height: 100%; max-width: 100%; } .tox .tox-dialog--fullscreen .tox-dialog__body-content { max-height: 100%; } .tox .tox-dialog--width-md { max-width: 800px; } .tox .tox-dialog--width-md .tox-dialog__body-content { overflow: auto; } .tox .tox-dialog__body-content--centered { text-align: center; } .tox .tox-dialog__footer { align-items: center; background-color: #2b3b4e; border-top: none; display: flex; justify-content: space-between; padding: 8px 16px; } .tox .tox-dialog__footer-start, .tox .tox-dialog__footer-end { display: flex; } .tox .tox-dialog__busy-spinner { align-items: center; background-color: rgba(34, 47, 62, 0.75); bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; z-index: 3; } .tox .tox-dialog__table { border-collapse: collapse; width: 100%; } .tox .tox-dialog__table thead th { font-weight: bold; padding-bottom: 8px; } .tox .tox-dialog__table thead th:first-child { padding-right: 8px; } .tox .tox-dialog__table tbody tr { border-bottom: 1px solid #000000; } .tox .tox-dialog__table tbody tr:last-child { border-bottom: none; } .tox .tox-dialog__table td { padding-bottom: 8px; padding-top: 8px; } .tox .tox-dialog__table td:first-child { padding-right: 8px; } .tox .tox-dialog__iframe { min-height: 200px; } .tox .tox-dialog__iframe.tox-dialog__iframe--opaque { background: #fff; } .tox .tox-dialog__iframe.tox-dialog__iframe--bordered { border: 1px solid #161f29; border-radius: 6px; } .tox .tox-dialog__popups { position: absolute; width: 100%; z-index: 1100; } .tox .tox-dialog__body-iframe { display: flex; flex: 1; flex-direction: column; } .tox .tox-dialog__body-iframe .tox-navobj { display: flex; flex: 1; } .tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { flex: 1; height: 100%; } .tox .tox-dialog-dock-fadeout { opacity: 0; visibility: hidden; } .tox .tox-dialog-dock-fadein { opacity: 1; visibility: visible; } .tox .tox-dialog-dock-transition { transition: visibility 0s linear 0.3s, opacity 0.3s ease; } .tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { transition-delay: 0s; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav { margin-right: 0; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child) { margin-left: 8px; } } .tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start > *, .tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end > * { margin-left: 8px; } .tox[dir=rtl] .tox-dialog__body { text-align: right; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav { margin-left: 0; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child) { margin-right: 8px; } } .tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start > *, .tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end > * { margin-right: 8px; } body.tox-dialog__disable-scroll { overflow: hidden; } .tox .tox-dropzone-container { display: flex; flex: 1; } .tox .tox-dropzone { align-items: center; background: #fff; border: 2px dashed #161f29; box-sizing: border-box; display: flex; flex-direction: column; flex-grow: 1; justify-content: center; min-height: 100px; padding: 10px; } .tox .tox-dropzone p { color: rgba(255, 255, 255, 0.5); margin: 0 0 16px 0; } .tox .tox-edit-area { display: flex; flex: 1; overflow: hidden; position: relative; } .tox .tox-edit-area::before { border: 2px solid #FFFFFF; border-radius: 4px; content: ''; inset: 0; opacity: 0; pointer-events: none; position: absolute; transition: opacity 0.15s; z-index: 1; } .tox .tox-edit-area__iframe { background-color: #fff; border: 0; box-sizing: border-box; flex: 1; height: 100%; position: absolute; width: 100%; } .tox.tox-edit-focus .tox-edit-area::before { opacity: 1; } .tox.tox-inline-edit-area { border: 1px dotted #161f29; } .tox .tox-editor-container { display: flex; flex: 1 1 auto; flex-direction: column; overflow: hidden; } .tox .tox-editor-header { display: grid; grid-template-columns: 1fr min-content; z-index: 2; } .tox:not(.tox-tinymce-inline) .tox-editor-header { background-color: #222F3E; border-bottom: 1px solid rgba(255, 255, 255, 0.15); box-shadow: none; padding: 4px 0; } .tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition) { transition: box-shadow 0.5s; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { border-top: 1px solid rgba(255, 255, 255, 0.15); box-shadow: none; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { background-color: #222F3E; box-shadow: none; padding: 4px 0; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { box-shadow: none; } .tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty { background: none; border: none; box-shadow: none; padding: 0; } .tox-editor-dock-fadeout { opacity: 0; visibility: hidden; } .tox-editor-dock-fadein { opacity: 1; visibility: visible; } .tox-editor-dock-transition { transition: visibility 0s linear 0.25s, opacity 0.25s ease; } .tox-editor-dock-transition.tox-editor-dock-fadein { transition-delay: 0s; } .tox .tox-control-wrap { flex: 1; position: relative; } .tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, .tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, .tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { display: none; } .tox .tox-control-wrap svg { display: block; } .tox .tox-control-wrap__status-icon-wrap { position: absolute; top: 50%; transform: translateY(-50%); } .tox .tox-control-wrap__status-icon-invalid svg { fill: #c00; } .tox .tox-control-wrap__status-icon-unknown svg { fill: orange; } .tox .tox-control-wrap__status-icon-valid svg { fill: green; } .tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield, .tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield, .tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield { padding-right: 32px; } .tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap { right: 4px; } .tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield, .tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield, .tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield { padding-left: 32px; } .tox[dir=rtl] .tox-control-wrap__status-icon-wrap { left: 4px; } .tox .tox-autocompleter { max-width: 25em; } .tox .tox-autocompleter .tox-menu { box-sizing: border-box; max-width: 25em; } .tox .tox-autocompleter .tox-autocompleter-highlight { font-weight: bold; } .tox .tox-color-input { display: flex; position: relative; z-index: 1; } .tox .tox-color-input .tox-textfield { z-index: -1; } .tox .tox-color-input span { border-color: rgba(34, 47, 62, 0.2); border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; height: 24px; position: absolute; top: 6px; width: 24px; } .tox .tox-color-input span:hover:not([aria-disabled=true]), .tox .tox-color-input span:focus:not([aria-disabled=true]) { border-color: #006ce7; cursor: pointer; } .tox .tox-color-input span::before { background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), linear-gradient(-45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%), linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%); background-position: 0 0, 0 6px, 6px -6px, -6px 0; background-size: 12px 12px; border: 1px solid #2b3b4e; border-radius: 6px; box-sizing: border-box; content: ''; height: 24px; left: -1px; position: absolute; top: -1px; width: 24px; z-index: -1; } .tox .tox-color-input span[aria-disabled=true] { cursor: not-allowed; } .tox:not([dir=rtl]) .tox-color-input { /* stylelint-disable-next-line no-descending-specificity */ } .tox:not([dir=rtl]) .tox-color-input .tox-textfield { padding-left: 36px; } .tox:not([dir=rtl]) .tox-color-input span { left: 6px; } .tox[dir="rtl"] .tox-color-input { /* stylelint-disable-next-line no-descending-specificity */ } .tox[dir="rtl"] .tox-color-input .tox-textfield { padding-right: 36px; } .tox[dir="rtl"] .tox-color-input span { right: 6px; } .tox .tox-label, .tox .tox-toolbar-label { color: rgba(255, 255, 255, 0.5); display: block; font-size: 14px; font-style: normal; font-weight: normal; line-height: 1.3; padding: 0 8px 0 0; text-transform: none; white-space: nowrap; } .tox .tox-toolbar-label { padding: 0 8px; } .tox[dir=rtl] .tox-label { padding: 0 0 0 8px; } .tox .tox-form { display: flex; flex: 1; flex-direction: column; } .tox .tox-form__group { box-sizing: border-box; margin-bottom: 4px; } .tox .tox-form-group--maximize { flex: 1; } .tox .tox-form__group--error { color: #c00; } .tox .tox-form__group--collection { display: flex; } .tox .tox-form__grid { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-between; } .tox .tox-form__grid--2col > .tox-form__group { width: calc(50% - (8px / 2)); } .tox .tox-form__grid--3col > .tox-form__group { width: calc(100% / 3 - (8px / 2)); } .tox .tox-form__grid--4col > .tox-form__group { width: calc(25% - (8px / 2)); } .tox .tox-form__controls-h-stack { align-items: center; display: flex; } .tox .tox-form__group--inline { align-items: center; display: flex; } .tox .tox-form__group--stretched { display: flex; flex: 1; flex-direction: column; } .tox .tox-form__group--stretched .tox-textarea { flex: 1; } .tox .tox-form__group--stretched .tox-navobj { display: flex; flex: 1; } .tox .tox-form__group--stretched .tox-navobj :nth-child(2) { flex: 1; height: 100%; } .tox:not([dir=rtl]) .tox-form__controls-h-stack > *:not(:first-child) { margin-left: 4px; } .tox[dir=rtl] .tox-form__controls-h-stack > *:not(:first-child) { margin-right: 4px; } .tox .tox-lock.tox-locked .tox-lock-icon__unlock, .tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { display: none; } .tox .tox-textfield, .tox .tox-toolbar-textfield, .tox .tox-listboxfield .tox-listbox--select, .tox .tox-textarea, .tox .tox-textarea-wrap .tox-textarea:focus { -webkit-appearance: none; -moz-appearance: none; appearance: none; background-color: #2b3b4e; border-color: #161f29; border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #fff; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; line-height: 24px; margin: 0; min-height: 34px; outline: none; padding: 5px 5.5px; resize: none; width: 100%; } .tox .tox-textfield[disabled], .tox .tox-textarea[disabled] { background-color: #222f3e; color: rgba(255, 255, 255, 0.85); cursor: not-allowed; } .tox .tox-textfield:focus, .tox .tox-dialog__iframe.tox-dialog__iframe--bordered:focus-within, .tox .tox-listboxfield .tox-listbox--select:focus, .tox .tox-textarea-wrap:focus-within, .tox .tox-textarea:focus, .tox .tox-custom-editor:focus-within { background-color: #2b3b4e; border-color: #006ce7; box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); outline: none; } .tox .tox-toolbar-textfield { border-width: 0; margin-bottom: 3px; margin-top: 2px; max-width: 250px; } .tox .tox-naked-btn { background-color: transparent; border: 0; border-color: transparent; box-shadow: unset; color: #006ce7; cursor: pointer; display: block; margin: 0; padding: 0; } .tox .tox-naked-btn svg { display: block; fill: #fff; } .tox:not([dir=rtl]) .tox-toolbar-textfield + * { margin-left: 4px; } .tox[dir=rtl] .tox-toolbar-textfield + * { margin-right: 4px; } .tox .tox-listboxfield { cursor: pointer; position: relative; } .tox .tox-listboxfield .tox-listbox--select[disabled] { background-color: #19232e; color: rgba(255, 255, 255, 0.85); cursor: not-allowed; } .tox .tox-listbox__select-label { cursor: default; flex: 1; margin: 0 4px; } .tox .tox-listbox__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; } .tox .tox-listbox__select-chevron svg { fill: #fff; } .tox .tox-listboxfield .tox-listbox--select { align-items: center; display: flex; } .tox:not([dir=rtl]) .tox-listboxfield svg { right: 8px; } .tox[dir=rtl] .tox-listboxfield svg { left: 8px; } .tox .tox-selectfield { cursor: pointer; position: relative; } .tox .tox-selectfield select { -webkit-appearance: none; -moz-appearance: none; appearance: none; background-color: #2b3b4e; border-color: #161f29; border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #fff; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; line-height: 24px; margin: 0; min-height: 34px; outline: none; padding: 5px 5.5px; resize: none; width: 100%; } .tox .tox-selectfield select[disabled] { background-color: #19232e; color: rgba(255, 255, 255, 0.85); cursor: not-allowed; } .tox .tox-selectfield select::-ms-expand { display: none; } .tox .tox-selectfield select:focus { background-color: #2b3b4e; border-color: #006ce7; box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); outline: none; } .tox .tox-selectfield svg { pointer-events: none; position: absolute; top: 50%; transform: translateY(-50%); } .tox:not([dir=rtl]) .tox-selectfield select[size="0"], .tox:not([dir=rtl]) .tox-selectfield select[size="1"] { padding-right: 24px; } .tox:not([dir=rtl]) .tox-selectfield svg { right: 8px; } .tox[dir=rtl] .tox-selectfield select[size="0"], .tox[dir=rtl] .tox-selectfield select[size="1"] { padding-left: 24px; } .tox[dir=rtl] .tox-selectfield svg { left: 8px; } .tox .tox-textarea-wrap { border-color: #161f29; border-radius: 6px; border-style: solid; border-width: 1px; display: flex; flex: 1; overflow: hidden; } .tox .tox-textarea { -webkit-appearance: textarea; -moz-appearance: textarea; appearance: textarea; white-space: pre-wrap; } .tox .tox-textarea-wrap .tox-textarea { border: none; } .tox .tox-textarea-wrap .tox-textarea:focus { border: none; } .tox-fullscreen { border: 0; height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; padding: 0; touch-action: pinch-zoom; width: 100%; } .tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { display: none; } .tox.tox-tinymce.tox-fullscreen, .tox-shadowhost.tox-fullscreen { left: 0; position: fixed; top: 0; z-index: 1200; } .tox.tox-tinymce.tox-fullscreen { background-color: transparent; } .tox-fullscreen .tox.tox-tinymce-aux, .tox-fullscreen ~ .tox.tox-tinymce-aux { z-index: 1201; } .tox .tox-help__more-link { list-style: none; margin-top: 1em; } .tox .tox-imagepreview { background-color: #666; height: 380px; overflow: hidden; position: relative; width: 100%; } .tox .tox-imagepreview.tox-imagepreview__loaded { overflow: auto; } .tox .tox-imagepreview__container { display: flex; left: 100vw; position: absolute; top: 100vw; } .tox .tox-imagepreview__image { background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); } .tox .tox-image-tools .tox-spacer { flex: 1; } .tox .tox-image-tools .tox-bar { align-items: center; display: flex; height: 60px; justify-content: center; } .tox .tox-image-tools .tox-imagepreview, .tox .tox-image-tools .tox-imagepreview + .tox-bar { margin-top: 8px; } .tox .tox-image-tools .tox-croprect-block { background: black; filter: alpha(opacity=50); opacity: 0.5; position: absolute; zoom: 1; } .tox .tox-image-tools .tox-croprect-handle { border: 2px solid white; height: 20px; left: 0; position: absolute; top: 0; width: 20px; } .tox .tox-image-tools .tox-croprect-handle-move { border: 0; cursor: move; position: absolute; } .tox .tox-image-tools .tox-croprect-handle-nw { border-width: 2px 0 0 2px; cursor: nw-resize; left: 100px; margin: -2px 0 0 -2px; top: 100px; } .tox .tox-image-tools .tox-croprect-handle-ne { border-width: 2px 2px 0 0; cursor: ne-resize; left: 200px; margin: -2px 0 0 -20px; top: 100px; } .tox .tox-image-tools .tox-croprect-handle-sw { border-width: 0 0 2px 2px; cursor: sw-resize; left: 100px; margin: -20px 2px 0 -2px; top: 200px; } .tox .tox-image-tools .tox-croprect-handle-se { border-width: 0 2px 2px 0; cursor: se-resize; left: 200px; margin: -20px 0 0 -20px; top: 200px; } .tox .tox-insert-table-picker { display: flex; flex-wrap: wrap; width: 170px; } .tox .tox-insert-table-picker > div { border-color: rgba(255, 255, 255, 0.15); border-style: solid; border-width: 0 1px 1px 0; box-sizing: border-box; height: 17px; width: 17px; } .tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { margin: -4px -4px; } .tox .tox-insert-table-picker .tox-insert-table-picker__selected { background-color: rgba(0, 108, 231, 0.5); border-color: rgba(0, 108, 231, 0.5); } .tox .tox-insert-table-picker__label { color: #fff; display: block; font-size: 14px; padding: 4px; text-align: center; width: 100%; } .tox:not([dir=rtl]) { /* stylelint-disable-next-line no-descending-specificity */ } .tox:not([dir=rtl]) .tox-insert-table-picker > div:nth-child(10n) { border-right: 0; } .tox[dir=rtl] { /* stylelint-disable-next-line no-descending-specificity */ } .tox[dir=rtl] .tox-insert-table-picker > div:nth-child(10n+1) { border-right: 0; } .tox { /* stylelint-disable */ /* stylelint-enable */ } .tox .tox-menu { background-color: #2b3b4e; border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 6px; box-shadow: none; display: inline-block; overflow: hidden; vertical-align: top; z-index: 1150; } .tox .tox-menu.tox-collection.tox-collection--list { padding: 0 4px; } .tox .tox-menu.tox-collection.tox-collection--toolbar { padding: 8px; } .tox .tox-menu.tox-collection.tox-collection--grid { padding: 8px; } @media only screen and (min-width: 768px ) { .tox .tox-menu .tox-collection__item-label { overflow-wrap: break-word; word-break: normal; } } .tox .tox-menu__label h1, .tox .tox-menu__label h2, .tox .tox-menu__label h3, .tox .tox-menu__label h4, .tox .tox-menu__label h5, .tox .tox-menu__label h6, .tox .tox-menu__label p, .tox .tox-menu__label blockquote, .tox .tox-menu__label code { margin: 0; } .tox .tox-menubar { background: repeating-linear-gradient(transparent 0px 1px, transparent 1px 39px) center top 39px / 100% calc(100% - 39px) no-repeat; background-color: #222F3E; display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: wrap; grid-column: 1 / -1; grid-row: 1; padding: 0 11px 0 12px; } .tox .tox-promotion + .tox-menubar { grid-column: 1; } .tox .tox-promotion { background: repeating-linear-gradient(transparent 0px 1px, transparent 1px 39px) center top 39px / 100% calc(100% - 39px) no-repeat; background-color: #222F3E; grid-column: 2; grid-row: 1; padding-inline-end: 8px; padding-inline-start: 4px; padding-top: 5px; } .tox .tox-promotion-link { align-items: unsafe center; background-color: #E8F1F8; border-radius: 5px; color: #086BE6; cursor: pointer; display: flex; font-size: 14px; height: 26.6px; padding: 4px 8px; white-space: nowrap; } .tox .tox-promotion-link:hover { background-color: #B4D7FF; } .tox .tox-promotion-link:focus { background-color: #D9EDF7; } /* Deprecated. Remove in next major release */ .tox .tox-mbtn { align-items: center; background: transparent; border: 0; border-radius: 3px; box-shadow: none; color: #fff; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 28px; justify-content: center; margin: 5px 1px 6px 0; outline: none; overflow: hidden; padding: 0 4px; text-transform: none; width: auto; } .tox .tox-mbtn[disabled] { background-color: transparent; border: 0; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-mbtn:focus:not(:disabled) { background: #3389ec; border: 0; box-shadow: none; color: #fff; } .tox .tox-mbtn--active { background: #599fef; border: 0; box-shadow: none; color: #fff; } .tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { background: #3389ec; border: 0; box-shadow: none; color: #fff; } .tox .tox-mbtn__select-label { cursor: default; font-weight: normal; margin: 0 4px; } .tox .tox-mbtn[disabled] .tox-mbtn__select-label { cursor: not-allowed; } .tox .tox-mbtn__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; display: none; } .tox .tox-notification { border-radius: 6px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; display: grid; font-size: 14px; font-weight: normal; grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); margin-top: 4px; opacity: 0; padding: 4px; transition: transform 100ms ease-in, opacity 150ms ease-in; } .tox .tox-notification p { font-size: 14px; font-weight: normal; } .tox .tox-notification a { cursor: pointer; text-decoration: underline; } .tox .tox-notification--in { opacity: 1; } .tox .tox-notification--success { background-color: #334840; border-color: #3c5440; color: #fff; } .tox .tox-notification--success p { color: #fff; } .tox .tox-notification--success a { color: #b5d199; } .tox .tox-notification--success svg { fill: #fff; } .tox .tox-notification--error { background-color: #442632; border-color: #55212b; color: #fff; } .tox .tox-notification--error p { color: #fff; } .tox .tox-notification--error a { color: #e68080; } .tox .tox-notification--error svg { fill: #fff; } .tox .tox-notification--warn, .tox .tox-notification--warning { background-color: #222F3E; border-color: rgba(255, 255, 255, 0.15); color: #fff0b3; } .tox .tox-notification--warn p, .tox .tox-notification--warning p { color: #fff0b3; } .tox .tox-notification--warn a, .tox .tox-notification--warning a { color: #ffcc00; } .tox .tox-notification--warn svg, .tox .tox-notification--warning svg { fill: #fff0b3; } .tox .tox-notification--info { background-color: #254161; border-color: #264972; color: #fff; } .tox .tox-notification--info p { color: #fff; } .tox .tox-notification--info a { color: #83b7f3; } .tox .tox-notification--info svg { fill: #fff; } .tox .tox-notification__body { align-self: center; color: #fff; font-size: 14px; grid-column-end: 3; grid-column-start: 2; grid-row-end: 2; grid-row-start: 1; text-align: center; white-space: normal; word-break: break-all; word-break: break-word; } .tox .tox-notification__body > * { margin: 0; } .tox .tox-notification__body > * + * { margin-top: 1rem; } .tox .tox-notification__icon { align-self: center; grid-column-end: 2; grid-column-start: 1; grid-row-end: 2; grid-row-start: 1; justify-self: end; } .tox .tox-notification__icon svg { display: block; } .tox .tox-notification__dismiss { align-self: start; grid-column-end: 4; grid-column-start: 3; grid-row-end: 2; grid-row-start: 1; justify-self: end; } .tox .tox-notification .tox-progress-bar { grid-column-end: 4; grid-column-start: 1; grid-row-end: 3; grid-row-start: 2; justify-self: center; } .tox .tox-pop { display: inline-block; position: relative; } .tox .tox-pop--resizing { transition: width 0.1s ease; } .tox .tox-pop--resizing .tox-toolbar, .tox .tox-pop--resizing .tox-toolbar__group { flex-wrap: nowrap; } .tox .tox-pop--transition { transition: 0.15s ease; transition-property: left, right, top, bottom; } .tox .tox-pop--transition::before, .tox .tox-pop--transition::after { transition: all 0.15s, visibility 0s, opacity 0.075s ease 0.075s; } .tox .tox-pop__dialog { background-color: #222F3E; border: 1px solid #161f29; border-radius: 6px; box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); min-width: 0; overflow: hidden; } .tox .tox-pop__dialog > *:not(.tox-toolbar) { margin: 4px 4px 4px 8px; } .tox .tox-pop__dialog .tox-toolbar { background-color: transparent; margin-bottom: -1px; } .tox .tox-pop::before, .tox .tox-pop::after { border-style: solid; content: ''; display: block; height: 0; opacity: 1; position: absolute; width: 0; } .tox .tox-pop.tox-pop--inset::before, .tox .tox-pop.tox-pop--inset::after { opacity: 0; transition: all 0s 0.15s, visibility 0s, opacity 0.075s ease; } .tox .tox-pop.tox-pop--bottom::before, .tox .tox-pop.tox-pop--bottom::after { left: 50%; top: 100%; } .tox .tox-pop.tox-pop--bottom::after { border-color: #222F3E transparent transparent transparent; border-width: 8px; margin-left: -8px; margin-top: -1px; } .tox .tox-pop.tox-pop--bottom::before { border-color: #161f29 transparent transparent transparent; border-width: 9px; margin-left: -9px; } .tox .tox-pop.tox-pop--top::before, .tox .tox-pop.tox-pop--top::after { left: 50%; top: 0; transform: translateY(-100%); } .tox .tox-pop.tox-pop--top::after { border-color: transparent transparent #222F3E transparent; border-width: 8px; margin-left: -8px; margin-top: 1px; } .tox .tox-pop.tox-pop--top::before { border-color: transparent transparent #161f29 transparent; border-width: 9px; margin-left: -9px; } .tox .tox-pop.tox-pop--left::before, .tox .tox-pop.tox-pop--left::after { left: 0; top: calc(50% - 1px); transform: translateY(-50%); } .tox .tox-pop.tox-pop--left::after { border-color: transparent #222F3E transparent transparent; border-width: 8px; margin-left: -15px; } .tox .tox-pop.tox-pop--left::before { border-color: transparent #161f29 transparent transparent; border-width: 10px; margin-left: -19px; } .tox .tox-pop.tox-pop--right::before, .tox .tox-pop.tox-pop--right::after { left: 100%; top: calc(50% + 1px); transform: translateY(-50%); } .tox .tox-pop.tox-pop--right::after { border-color: transparent transparent transparent #222F3E; border-width: 8px; margin-left: -1px; } .tox .tox-pop.tox-pop--right::before { border-color: transparent transparent transparent #161f29; border-width: 10px; margin-left: -1px; } .tox .tox-pop.tox-pop--align-left::before, .tox .tox-pop.tox-pop--align-left::after { left: 20px; } .tox .tox-pop.tox-pop--align-right::before, .tox .tox-pop.tox-pop--align-right::after { left: calc(100% - 20px); } .tox .tox-sidebar-wrap { display: flex; flex-direction: row; flex-grow: 1; min-height: 0; } .tox .tox-sidebar { background-color: #222F3E; display: flex; flex-direction: row; justify-content: flex-end; } .tox .tox-sidebar__slider { display: flex; overflow: hidden; } .tox .tox-sidebar__pane-container { display: flex; } .tox .tox-sidebar__pane { display: flex; } .tox .tox-sidebar--sliding-closed { opacity: 0; } .tox .tox-sidebar--sliding-open { opacity: 1; } .tox .tox-sidebar--sliding-growing, .tox .tox-sidebar--sliding-shrinking { transition: width 0.5s ease, opacity 0.5s ease; } .tox .tox-selector { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; display: inline-block; height: 10px; position: absolute; width: 10px; } .tox.tox-platform-touch .tox-selector { height: 12px; width: 12px; } .tox .tox-slider { align-items: center; display: flex; flex: 1; height: 24px; justify-content: center; position: relative; } .tox .tox-slider__rail { background-color: transparent; border: 1px solid #161f29; border-radius: 6px; height: 10px; min-width: 120px; width: 100%; } .tox .tox-slider__handle { background-color: #006ce7; border: 2px solid #0054b4; border-radius: 6px; box-shadow: none; height: 24px; left: 50%; position: absolute; top: 50%; transform: translateX(-50%) translateY(-50%); width: 14px; } .tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { margin-inline-start: 8px; } .tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { margin-inline-start: 32px; } .tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { margin-inline-start: 32px; } .tox .tox-source-code { overflow: auto; } .tox .tox-spinner { display: flex; } .tox .tox-spinner > div { animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; background-color: rgba(255, 255, 255, 0.5); border-radius: 100%; height: 8px; width: 8px; } .tox .tox-spinner > div:nth-child(1) { animation-delay: -0.32s; } .tox .tox-spinner > div:nth-child(2) { animation-delay: -0.16s; } @keyframes tam-bouncing-dots { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } } .tox:not([dir=rtl]) .tox-spinner > div:not(:first-child) { margin-left: 4px; } .tox[dir=rtl] .tox-spinner > div:not(:first-child) { margin-right: 4px; } .tox .tox-statusbar { align-items: center; background-color: #222F3E; border-top: 1px solid rgba(255, 255, 255, 0.15); color: rgba(255, 255, 255, 0.75); display: flex; flex: 0 0 auto; font-size: 14px; font-weight: normal; height: 25px; overflow: hidden; padding: 0 8px; position: relative; text-transform: none; } .tox .tox-statusbar__text-container { display: flex; flex: 1 1 auto; justify-content: flex-end; overflow: hidden; } .tox .tox-statusbar__path { display: flex; flex: 1 1 auto; margin-right: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-statusbar__path > * { display: inline; white-space: nowrap; } .tox .tox-statusbar__wordcount { flex: 0 0 auto; margin-left: 1ch; } .tox .tox-statusbar a, .tox .tox-statusbar__path-item, .tox .tox-statusbar__wordcount { color: rgba(255, 255, 255, 0.75); text-decoration: none; } .tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]) { color: #fff; cursor: pointer; } .tox .tox-statusbar__branding svg { fill: rgba(255, 255, 255, 0.8); height: 1.14em; vertical-align: -0.28em; width: 3.6em; } .tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg, .tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg { fill: #fff; } .tox .tox-statusbar__resize-handle { align-items: flex-end; align-self: stretch; cursor: nwse-resize; display: flex; flex: 0 0 auto; justify-content: flex-end; margin-left: auto; margin-right: -8px; padding-bottom: 3px; padding-left: 1ch; padding-right: 3px; } .tox .tox-statusbar__resize-handle svg { display: block; fill: rgba(255, 255, 255, 0.5); } .tox .tox-statusbar__resize-handle:focus svg { background-color: #434e5b; border-radius: 1px 1px 5px 1px; box-shadow: 0 0 0 2px #434e5b; } .tox:not([dir=rtl]) .tox-statusbar__path > * { margin-right: 4px; } .tox:not([dir=rtl]) .tox-statusbar__branding { margin-left: 2ch; } .tox[dir=rtl] .tox-statusbar { flex-direction: row-reverse; } .tox[dir=rtl] .tox-statusbar__path > * { margin-left: 4px; } .tox .tox-throbber { z-index: 1299; } .tox .tox-throbber__busy-spinner { align-items: center; background-color: rgba(34, 47, 62, 0.6); bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; } .tox .tox-tbtn { align-items: center; background: transparent; border: 0; border-radius: 3px; box-shadow: none; color: #fff; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 28px; justify-content: center; margin: 6px 1px 5px 0; outline: none; overflow: hidden; padding: 0; text-transform: none; width: 34px; } .tox .tox-tbtn svg { display: block; fill: #fff; } .tox .tox-tbtn.tox-tbtn-more { padding-left: 5px; padding-right: 5px; width: inherit; } .tox .tox-tbtn:focus { background: #3389ec; border: 0; box-shadow: none; } .tox .tox-tbtn:hover { background: #3389ec; border: 0; box-shadow: none; color: #fff; } .tox .tox-tbtn:hover svg { fill: #fff; } .tox .tox-tbtn:active { background: #599fef; border: 0; box-shadow: none; color: #fff; } .tox .tox-tbtn:active svg { fill: #fff; } .tox .tox-tbtn--disabled .tox-tbtn--enabled svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-tbtn--disabled, .tox .tox-tbtn--disabled:hover, .tox .tox-tbtn:disabled, .tox .tox-tbtn:disabled:hover { background: transparent; border: 0; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-tbtn--disabled svg, .tox .tox-tbtn--disabled:hover svg, .tox .tox-tbtn:disabled svg, .tox .tox-tbtn:disabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: rgba(255, 255, 255, 0.5); } .tox .tox-tbtn--enabled, .tox .tox-tbtn--enabled:hover { background: #599fef; border: 0; box-shadow: none; color: #fff; } .tox .tox-tbtn--enabled > *, .tox .tox-tbtn--enabled:hover > * { transform: none; } .tox .tox-tbtn--enabled svg, .tox .tox-tbtn--enabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: #fff; } .tox .tox-tbtn--enabled.tox-tbtn--disabled svg, .tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { color: #fff; } .tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { fill: #fff; } .tox .tox-tbtn:active > * { transform: none; } .tox .tox-tbtn--md { height: 42px; width: 51px; } .tox .tox-tbtn--lg { flex-direction: column; height: 56px; width: 68px; } .tox .tox-tbtn--return { align-self: stretch; height: unset; width: 16px; } .tox .tox-tbtn--labeled { padding: 0 4px; width: unset; } .tox .tox-tbtn__vlabel { display: block; font-size: 10px; font-weight: normal; letter-spacing: -0.025em; margin-bottom: 4px; white-space: nowrap; } .tox .tox-number-input { border-radius: 3px; display: flex; margin: 6px 1px 5px 0; padding: 0 4px; width: auto; } .tox .tox-number-input .tox-input-wrapper { background: #2f4055; display: flex; pointer-events: none; text-align: center; } .tox .tox-number-input .tox-input-wrapper:focus { background: #3389ec; } .tox .tox-number-input input { border-radius: 3px; color: #fff; font-size: 14px; margin: 2px 0; pointer-events: all; width: 60px; } .tox .tox-number-input input:hover { background: #3389ec; color: #fff; } .tox .tox-number-input input:focus { background: #fff; color: #222f3e; } .tox .tox-number-input input:disabled { background: transparent; border: 0; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-number-input button { background: #2f4055; color: #fff; height: 28px; text-align: center; width: 24px; } .tox .tox-number-input button svg { display: block; fill: #fff; margin: 0 auto; transform: scale(0.67); } .tox .tox-number-input button:focus { background: #3389ec; } .tox .tox-number-input button:hover { background: #3389ec; border: 0; box-shadow: none; color: #fff; } .tox .tox-number-input button:hover svg { fill: #fff; } .tox .tox-number-input button:active { background: #599fef; border: 0; box-shadow: none; color: #fff; } .tox .tox-number-input button:active svg { fill: #fff; } .tox .tox-number-input button:disabled { background: transparent; border: 0; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-number-input button:disabled svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-number-input button.minus { border-radius: 3px 0 0 3px; } .tox .tox-number-input button.plus { border-radius: 0 3px 3px 0; } .tox .tox-number-input:focus:not(:active) > button, .tox .tox-number-input:focus:not(:active) > .tox-input-wrapper { background: #3389ec; } .tox .tox-tbtn--select { margin: 6px 1px 5px 0; padding: 0 4px; width: auto; } .tox .tox-tbtn__select-label { cursor: default; font-weight: normal; height: initial; margin: 0 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-tbtn__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; } .tox .tox-tbtn__select-chevron svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-tbtn--bespoke { background: #2f4055; } .tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { margin-inline-start: 4px; } .tox .tox-tbtn--bespoke .tox-tbtn__select-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 7em; } .tox .tox-tbtn--disabled .tox-tbtn__select-label, .tox .tox-tbtn--select:disabled .tox-tbtn__select-label { cursor: not-allowed; } .tox .tox-split-button { border: 0; border-radius: 3px; box-sizing: border-box; display: flex; margin: 6px 1px 5px 0; overflow: hidden; } .tox .tox-split-button:hover { box-shadow: 0 0 0 1px #3389ec inset; } .tox .tox-split-button:focus { background: #3389ec; box-shadow: none; color: #fff; } .tox .tox-split-button > * { border-radius: 0; } .tox .tox-split-button__chevron { width: 16px; } .tox .tox-split-button__chevron svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-split-button .tox-tbtn { margin: 0; } .tox .tox-split-button.tox-tbtn--disabled:hover, .tox .tox-split-button.tox-tbtn--disabled:focus, .tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, .tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus { background: transparent; box-shadow: none; color: rgba(255, 255, 255, 0.5); } .tox.tox-platform-touch .tox-split-button .tox-tbtn--select { padding: 0 0px; } .tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { width: 30px; } .tox.tox-platform-touch .tox-split-button__chevron { width: 20px; } .tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color, .tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color { opacity: 0.6; } .tox .tox-toolbar-overlord { background-color: #222F3E; } .tox .tox-toolbar, .tox .tox-toolbar__primary, .tox .tox-toolbar__overflow { background-attachment: local; background-color: #222F3E; background-image: repeating-linear-gradient(rgba(255, 255, 255, 0.15) 0px 1px, transparent 1px 39px); background-position: center top 40px; background-repeat: no-repeat; background-size: calc(100% - 11px * 2) calc(100% - 41px); display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: wrap; padding: 0 0px; transform: perspective(1px); } .tox .tox-toolbar-overlord > .tox-toolbar, .tox .tox-toolbar-overlord > .tox-toolbar__primary, .tox .tox-toolbar-overlord > .tox-toolbar__overflow { background-position: center top 0px; background-size: calc(100% - 11px * 2) calc(100% - 0px); } .tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { height: 0; opacity: 0; padding-bottom: 0; padding-top: 0; visibility: hidden; } .tox .tox-toolbar__overflow--growing { transition: height 0.3s ease, opacity 0.2s linear 0.1s; } .tox .tox-toolbar__overflow--shrinking { transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; } .tox .tox-toolbar-overlord, .tox .tox-anchorbar { grid-column: 1 / -1; } .tox .tox-menubar + .tox-toolbar, .tox .tox-menubar + .tox-toolbar-overlord { border-top: 1px solid transparent; margin-top: -1px; padding-bottom: 1px; padding-top: 1px; } .tox .tox-toolbar--scrolling { flex-wrap: nowrap; overflow-x: auto; } .tox .tox-pop .tox-toolbar { border-width: 0; } .tox .tox-toolbar--no-divider { background-image: none; } .tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, .tox .tox-toolbar-overlord .tox-toolbar__primary { background-position: center top 39px; } .tox .tox-editor-header > .tox-toolbar--scrolling, .tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { background-image: none; } .tox.tox-tinymce-aux .tox-toolbar__overflow { background-color: #222F3E; background-position: center top 43px; background-size: calc(100% - 8px * 2) calc(100% - 51px); border: none; border-radius: 6px; box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); overscroll-behavior: none; padding: 4px 0; } .tox-pop .tox-pop__dialog { /* stylelint-disable-next-line no-descending-specificity */ } .tox-pop .tox-pop__dialog .tox-toolbar { background-position: center top 43px; background-size: calc(100% - 11px * 2) calc(100% - 51px); padding: 4px 0; } .tox .tox-toolbar__group { align-items: center; display: flex; flex-wrap: wrap; margin: 0 0; padding: 0 11px 0 12px; } .tox .tox-toolbar__group--pull-right { margin-left: auto; } .tox .tox-toolbar--scrolling .tox-toolbar__group { flex-shrink: 0; flex-wrap: nowrap; } .tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type) { border-right: 1px solid transparent; } .tox[dir=rtl] .tox-toolbar__group:not(:last-of-type) { border-left: 1px solid transparent; } .tox .tox-tooltip { display: inline-block; padding: 8px; position: relative; } .tox .tox-tooltip__body { background-color: #3d546f; border-radius: 6px; box-shadow: 0 2px 4px rgba(34, 47, 62, 0.3); color: rgba(255, 255, 255, 0.75); font-size: 14px; font-style: normal; font-weight: normal; padding: 4px 8px; text-transform: none; } .tox .tox-tooltip__arrow { position: absolute; } .tox .tox-tooltip--down .tox-tooltip__arrow { border-left: 8px solid transparent; border-right: 8px solid transparent; border-top: 8px solid #3d546f; bottom: 0; left: 50%; position: absolute; transform: translateX(-50%); } .tox .tox-tooltip--up .tox-tooltip__arrow { border-bottom: 8px solid #3d546f; border-left: 8px solid transparent; border-right: 8px solid transparent; left: 50%; position: absolute; top: 0; transform: translateX(-50%); } .tox .tox-tooltip--right .tox-tooltip__arrow { border-bottom: 8px solid transparent; border-left: 8px solid #3d546f; border-top: 8px solid transparent; position: absolute; right: 0; top: 50%; transform: translateY(-50%); } .tox .tox-tooltip--left .tox-tooltip__arrow { border-bottom: 8px solid transparent; border-right: 8px solid #3d546f; border-top: 8px solid transparent; left: 0; position: absolute; top: 50%; transform: translateY(-50%); } .tox .tox-tree { display: flex; flex-direction: column; } .tox .tox-tree .tox-trbtn { align-items: center; background: transparent; border: 0; border-radius: 4px; box-shadow: none; color: #fff; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 28px; margin-bottom: 4px; margin-top: 4px; outline: none; overflow: hidden; padding: 0; padding-left: 8px; text-transform: none; } .tox .tox-tree .tox-trbtn .tox-tree__label { cursor: default; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-tree .tox-trbtn svg { display: block; fill: #fff; } .tox .tox-tree .tox-trbtn:focus { background: #3389ec; border: 0; box-shadow: none; } .tox .tox-tree .tox-trbtn:hover { background: #3389ec; border: 0; box-shadow: none; color: #fff; } .tox .tox-tree .tox-trbtn:hover svg { fill: #fff; } .tox .tox-tree .tox-trbtn:active { background: #599fef; border: 0; box-shadow: none; color: #fff; } .tox .tox-tree .tox-trbtn:active svg { fill: #fff; } .tox .tox-tree .tox-trbtn--disabled, .tox .tox-tree .tox-trbtn--disabled:hover, .tox .tox-tree .tox-trbtn:disabled, .tox .tox-tree .tox-trbtn:disabled:hover { background: transparent; border: 0; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-tree .tox-trbtn--disabled svg, .tox .tox-tree .tox-trbtn--disabled:hover svg, .tox .tox-tree .tox-trbtn:disabled svg, .tox .tox-tree .tox-trbtn:disabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: rgba(255, 255, 255, 0.5); } .tox .tox-tree .tox-trbtn--enabled, .tox .tox-tree .tox-trbtn--enabled:hover { background: #599fef; border: 0; box-shadow: none; color: #fff; } .tox .tox-tree .tox-trbtn--enabled > *, .tox .tox-tree .tox-trbtn--enabled:hover > * { transform: none; } .tox .tox-tree .tox-trbtn--enabled svg, .tox .tox-tree .tox-trbtn--enabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: #fff; } .tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) { color: #fff; } .tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg { fill: #fff; } .tox .tox-tree .tox-trbtn:active > * { transform: none; } .tox .tox-tree .tox-trbtn--return { align-self: stretch; height: unset; width: 16px; } .tox .tox-tree .tox-trbtn--labeled { padding: 0 4px; width: unset; } .tox .tox-tree .tox-trbtn__vlabel { display: block; font-size: 10px; font-weight: normal; letter-spacing: -0.025em; margin-bottom: 4px; white-space: nowrap; } .tox .tox-tree .tox-tree--directory { display: flex; flex-direction: column; /* stylelint-disable no-descending-specificity */ } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label { font-weight: bold; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn { margin-left: auto; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg { fill: transparent; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg { fill: #fff; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg { fill: #fff; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) { background-color: transparent; color: #fff; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg { fill: #fff; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron { margin-right: 6px; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--growing) .tox-chevron, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--shrinking) .tox-chevron { transition: transform 0.5s ease-in-out; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--growing) .tox-chevron, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--open) .tox-chevron { transform: rotate(90deg); } .tox .tox-tree .tox-tree--leaf__label { font-weight: normal; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn { margin-left: auto; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg { fill: transparent; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg, .tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg { fill: #fff; } .tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg { fill: #fff; } .tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) { background-color: transparent; color: #fff; } .tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg { fill: #fff; } .tox .tox-tree .tox-tree--directory__children { overflow: hidden; padding-left: 16px; } .tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing, .tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking { transition: height 0.5s ease-in-out; } .tox .tox-tree .tox-trbtn.tox-tree--leaf__label { display: flex; justify-content: space-between; } .tox .tox-view-wrap, .tox .tox-view-wrap__slot-container { background-color: #222F3E; display: flex; flex: 1; flex-direction: column; } .tox .tox-view { display: flex; flex: 1 1 auto; flex-direction: column; overflow: hidden; } .tox .tox-view__header { align-items: center; display: flex; font-size: 16px; justify-content: space-between; padding: 8px 8px 0 8px; position: relative; } .tox .tox-view--mobile.tox-view__header, .tox .tox-view--mobile.tox-view__toolbar { padding: 8px; } .tox .tox-view--scrolling { flex-wrap: nowrap; overflow-x: auto; } .tox .tox-view__toolbar { display: flex; flex-direction: row; gap: 8px; justify-content: space-between; padding: 8px 8px 0 8px; } .tox .tox-view__toolbar__group { display: flex; flex-direction: row; gap: 12px; } .tox .tox-view__header-start, .tox .tox-view__header-end { display: flex; } .tox .tox-view__pane { height: 100%; padding: 8px; width: 100%; } .tox .tox-view__pane_panel { border: 1px solid #161f29; border-radius: 6px; } .tox:not([dir=rtl]) .tox-view__header .tox-view__header-start > *, .tox:not([dir=rtl]) .tox-view__header .tox-view__header-end > * { margin-left: 8px; } .tox[dir=rtl] .tox-view__header .tox-view__header-start > *, .tox[dir=rtl] .tox-view__header .tox-view__header-end > * { margin-right: 8px; } .tox .tox-well { border: 1px solid #161f29; border-radius: 6px; padding: 8px; width: 100%; } .tox .tox-well > *:first-child { margin-top: 0; } .tox .tox-well > *:last-child { margin-bottom: 0; } .tox .tox-well > *:only-child { margin: 0; } .tox .tox-custom-editor { border: 1px solid #161f29; border-radius: 6px; display: flex; flex: 1; overflow: hidden; position: relative; } /* stylelint-disable */ .tox { /* stylelint-enable */ } .tox .tox-dialog-loading::before { background-color: rgba(0, 0, 0, 0.5); content: ""; height: 100%; position: absolute; width: 100%; z-index: 1000; } .tox .tox-tab { cursor: pointer; } .tox .tox-dialog__content-js { display: flex; flex: 1; } .tox .tox-dialog__body-content .tox-collection { display: flex; flex: 1; } .tox.tox-tinymce-aux .tox-toolbar__overflow { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.15); } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.css ================================================ body.tox-dialog__disable-scroll { overflow: hidden; } .tox-fullscreen { border: 0; height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; padding: 0; touch-action: pinch-zoom; width: 100%; } .tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { display: none; } .tox.tox-tinymce.tox-fullscreen, .tox-shadowhost.tox-fullscreen { left: 0; position: fixed; top: 0; z-index: 1200; } .tox.tox-tinymce.tox-fullscreen { background-color: transparent; } .tox-fullscreen .tox.tox-tinymce-aux, .tox-fullscreen ~ .tox.tox-tinymce-aux { z-index: 1201; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/tinymce-5/content.css ================================================ .mce-content-body .mce-item-anchor { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; } .mce-content-body .mce-item-anchor:empty { cursor: default; display: inline-block; height: 12px !important; padding: 0 2px; -webkit-user-modify: read-only; -moz-user-modify: read-only; -webkit-user-select: all; -moz-user-select: all; user-select: all; width: 8px !important; } .mce-content-body .mce-item-anchor:not(:empty) { background-position-x: 2px; display: inline-block; padding-left: 12px; } .mce-content-body .mce-item-anchor[data-mce-selected] { outline-offset: 1px; } .tox-comments-visible .tox-comment[contenteditable="false"]:not([data-mce-selected]), .tox-comments-visible span.tox-comment img:not([data-mce-selected]), .tox-comments-visible span.tox-comment > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #ffe89d; } .tox-comments-visible .tox-comment[contenteditable="false"][data-mce-annotation-active="true"]:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] img:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment:not([data-mce-selected]) { background-color: #ffe89d; outline: none; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"]:not([data-mce-selected="inline-boundary"]) { background-color: #fed635; } .tox-checklist > li:not(.tox-checklist--hidden) { list-style: none; margin: 0.25em 0; } .tox-checklist > li:not(.tox-checklist--hidden)::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); cursor: pointer; height: 1em; margin-left: -1.5em; margin-top: 0.125em; position: absolute; width: 1em; } .tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); } [dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { margin-left: 0; margin-right: -1.5em; } /* stylelint-disable */ /* http://prismjs.com/ */ /** * prism.js default theme for JavaScript, CSS and HTML * Based on dabblet (http://dabblet.com) * @author Lea Verou */ code[class*="language-"], pre[class*="language-"] { color: black; background: none; text-shadow: 0 1px white; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; font-size: 1em; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.5; -moz-tab-size: 4; tab-size: 4; -webkit-hyphens: none; hyphens: none; } pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { text-shadow: none; background: #b3d4fc; } pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection { text-shadow: none; background: #b3d4fc; } @media print { code[class*="language-"], pre[class*="language-"] { text-shadow: none; } } /* Code blocks */ pre[class*="language-"] { padding: 1em; margin: 0.5em 0; overflow: auto; } :not(pre) > code[class*="language-"], pre[class*="language-"] { background: #f5f2f0; } /* Inline code */ :not(pre) > code[class*="language-"] { padding: 0.1em; border-radius: 0.3em; white-space: normal; } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: slategray; } .token.punctuation { color: #999; } .token.namespace { opacity: 0.7; } .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: #905; } .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #690; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { color: #9a6e3a; /* This background color was intended by the author of this theme. */ background: hsla(0, 0%, 100%, 0.5); } .token.atrule, .token.attr-value, .token.keyword { color: #07a; } .token.function, .token.class-name { color: #DD4A68; } .token.regex, .token.important, .token.variable { color: #e90; } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } /* stylelint-enable */ .mce-content-body { overflow-wrap: break-word; word-wrap: break-word; } .mce-content-body .mce-visual-caret { background-color: black; background-color: currentColor; position: absolute; } .mce-content-body .mce-visual-caret-hidden { display: none; } .mce-content-body *[data-mce-caret] { left: -1000px; margin: 0; padding: 0; position: absolute; right: auto; top: 0; } .mce-content-body .mce-offscreen-selection { left: -2000000px; max-width: 1000000px; position: absolute; } .mce-content-body *[contentEditable=false] { cursor: default; } .mce-content-body *[contentEditable=true] { cursor: text; } .tox-cursor-format-painter { cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; } div.mce-footnotes hr { margin-inline-end: auto; margin-inline-start: 0; width: 25%; } div.mce-footnotes li > a.mce-footnotes-backlink { text-decoration: none; } @media print { sup.mce-footnote a { color: black; text-decoration: none; } div.mce-footnotes { break-inside: avoid; width: 100%; } div.mce-footnotes li > a.mce-footnotes-backlink { display: none; } } .mce-content-body figure.align-left { float: left; } .mce-content-body figure.align-right { float: right; } .mce-content-body figure.image.align-center { display: table; margin-left: auto; margin-right: auto; } .mce-preview-object { border: 1px solid gray; display: inline-block; line-height: 0; margin: 0 2px 0 2px; position: relative; } .mce-preview-object .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-preview-object[data-mce-selected="2"] .mce-shim { display: none; } .mce-content-body .mce-mergetag { cursor: default !important; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body .mce-mergetag:hover { background-color: rgba(0, 108, 231, 0.1); } .mce-content-body .mce-mergetag-affix { background-color: rgba(0, 108, 231, 0.1); color: #006ce7; } .mce-object { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; border: 1px dashed #aaa; } .mce-pagebreak { border: 1px dashed #aaa; cursor: default; display: block; height: 5px; margin-top: 15px; page-break-before: always; width: 100%; } @media print { .mce-pagebreak { border: 0; } } .tiny-pageembed .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tiny-pageembed[data-mce-selected="2"] .mce-shim { display: none; } .tiny-pageembed { display: inline-block; position: relative; } .tiny-pageembed--21by9, .tiny-pageembed--16by9, .tiny-pageembed--4by3, .tiny-pageembed--1by1 { display: block; overflow: hidden; padding: 0; position: relative; width: 100%; } .tiny-pageembed--21by9 { padding-top: 42.857143%; } .tiny-pageembed--16by9 { padding-top: 56.25%; } .tiny-pageembed--4by3 { padding-top: 75%; } .tiny-pageembed--1by1 { padding-top: 100%; } .tiny-pageembed--21by9 iframe, .tiny-pageembed--16by9 iframe, .tiny-pageembed--4by3 iframe, .tiny-pageembed--1by1 iframe { border: 0; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-content-body[data-mce-placeholder] { position: relative; } .mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { color: rgba(34, 47, 62, 0.7); content: attr(data-mce-placeholder); position: absolute; } .mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { left: 1px; } .mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { right: 1px; } .mce-content-body div.mce-resizehandle { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; height: 10px; position: absolute; width: 10px; z-index: 1298; } .mce-content-body div.mce-resizehandle:hover { background-color: #4099ff; } .mce-content-body div.mce-resizehandle:nth-of-type(1) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(2) { cursor: nesw-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(3) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(4) { cursor: nesw-resize; } .mce-content-body .mce-resize-backdrop { z-index: 10000; } .mce-content-body .mce-clonedresizable { cursor: default; opacity: 0.5; outline: 1px dashed black; position: absolute; z-index: 10001; } .mce-content-body .mce-clonedresizable.mce-resizetable-columns th, .mce-content-body .mce-clonedresizable.mce-resizetable-columns td { border: 0; } .mce-content-body .mce-resize-helper { background: #555; background: rgba(0, 0, 0, 0.75); border: 1px; border-radius: 3px; color: white; display: none; font-family: sans-serif; font-size: 12px; line-height: 14px; margin: 5px 10px; padding: 5px; position: absolute; white-space: nowrap; z-index: 10002; } .tox-rtc-user-selection { position: relative; } .tox-rtc-user-cursor { bottom: 0; cursor: default; position: absolute; top: 0; width: 2px; } .tox-rtc-user-cursor::before { background-color: inherit; border-radius: 50%; content: ''; display: block; height: 8px; position: absolute; right: -3px; top: -3px; width: 8px; } .tox-rtc-user-cursor:hover::after { background-color: inherit; border-radius: 100px; box-sizing: border-box; color: #fff; content: attr(data-user); display: block; font-size: 12px; font-weight: bold; left: -5px; min-height: 8px; min-width: 8px; padding: 0 12px; position: absolute; top: -11px; white-space: nowrap; z-index: 1000; } .tox-rtc-user-selection--1 .tox-rtc-user-cursor { background-color: #2dc26b; } .tox-rtc-user-selection--2 .tox-rtc-user-cursor { background-color: #e03e2d; } .tox-rtc-user-selection--3 .tox-rtc-user-cursor { background-color: #f1c40f; } .tox-rtc-user-selection--4 .tox-rtc-user-cursor { background-color: #3598db; } .tox-rtc-user-selection--5 .tox-rtc-user-cursor { background-color: #b96ad9; } .tox-rtc-user-selection--6 .tox-rtc-user-cursor { background-color: #e67e23; } .tox-rtc-user-selection--7 .tox-rtc-user-cursor { background-color: #aaa69d; } .tox-rtc-user-selection--8 .tox-rtc-user-cursor { background-color: #f368e0; } .tox-rtc-remote-image { background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; border: 1px solid #ccc; min-height: 240px; min-width: 320px; } .mce-match-marker { background: #aaa; color: #fff; } .mce-match-marker-selected { background: #39f; color: #fff; } .mce-match-marker-selected::-moz-selection { background: #39f; color: #fff; } .mce-match-marker-selected::selection { background: #39f; color: #fff; } .mce-content-body img[data-mce-selected], .mce-content-body video[data-mce-selected], .mce-content-body audio[data-mce-selected], .mce-content-body object[data-mce-selected], .mce-content-body embed[data-mce-selected], .mce-content-body table[data-mce-selected], .mce-content-body details[data-mce-selected] { outline: 3px solid #b4d7ff; } .mce-content-body hr[data-mce-selected] { outline: 3px solid #b4d7ff; outline-offset: 1px; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false][data-mce-selected] { cursor: not-allowed; outline: 3px solid #b4d7ff; } .mce-content-body.mce-content-readonly *[contentEditable=true]:focus, .mce-content-body.mce-content-readonly *[contentEditable=true]:hover { outline: none; } .mce-content-body *[data-mce-selected="inline-boundary"] { background-color: #b4d7ff; } .mce-content-body .mce-edit-focus { outline: 3px solid #b4d7ff; } .mce-content-body td[data-mce-selected], .mce-content-body th[data-mce-selected] { position: relative; } .mce-content-body td[data-mce-selected]::-moz-selection, .mce-content-body th[data-mce-selected]::-moz-selection { background: none; } .mce-content-body td[data-mce-selected]::selection, .mce-content-body th[data-mce-selected]::selection { background: none; } .mce-content-body td[data-mce-selected] *, .mce-content-body th[data-mce-selected] * { outline: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { background-color: rgba(180, 215, 255, 0.7); border: 1px solid rgba(180, 215, 255, 0.7); bottom: -1px; content: ''; left: -1px; mix-blend-mode: multiply; position: absolute; right: -1px; top: -1px; } @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { border-color: rgba(0, 84, 180, 0.7); } } .mce-content-body img[data-mce-selected]::-moz-selection { background: none; } .mce-content-body img[data-mce-selected]::selection { background: none; } .ephox-snooker-resizer-bar { background-color: #b4d7ff; opacity: 0; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .ephox-snooker-resizer-cols { cursor: col-resize; } .ephox-snooker-resizer-rows { cursor: row-resize; } .ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { opacity: 1; } .mce-spellchecker-word { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; height: 2rem; } .mce-spellchecker-grammar { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; } .mce-toc { border: 1px solid gray; } .mce-toc h2 { margin: 4px; } .mce-toc li { list-style-type: none; } [data-mce-block] { display: block; } table[style*="border-width: 0px"], .mce-item-table:not([border]), .mce-item-table[border="0"], table[style*="border-width: 0px"] td, .mce-item-table:not([border]) td, .mce-item-table[border="0"] td, table[style*="border-width: 0px"] th, .mce-item-table:not([border]) th, .mce-item-table[border="0"] th, table[style*="border-width: 0px"] caption, .mce-item-table:not([border]) caption, .mce-item-table[border="0"] caption { border: 1px dashed #bbb; } .mce-visualblocks p, .mce-visualblocks h1, .mce-visualblocks h2, .mce-visualblocks h3, .mce-visualblocks h4, .mce-visualblocks h5, .mce-visualblocks h6, .mce-visualblocks div:not([data-mce-bogus]), .mce-visualblocks section, .mce-visualblocks article, .mce-visualblocks blockquote, .mce-visualblocks address, .mce-visualblocks pre, .mce-visualblocks figure, .mce-visualblocks figcaption, .mce-visualblocks hgroup, .mce-visualblocks aside, .mce-visualblocks ul, .mce-visualblocks ol, .mce-visualblocks dl { background-repeat: no-repeat; border: 1px dashed #bbb; margin-left: 3px; padding-top: 10px; } .mce-visualblocks p { background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); } .mce-visualblocks h1 { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); } .mce-visualblocks h2 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); } .mce-visualblocks h3 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); } .mce-visualblocks h4 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); } .mce-visualblocks h5 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); } .mce-visualblocks h6 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); } .mce-visualblocks div:not([data-mce-bogus]) { background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); } .mce-visualblocks section { background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); } .mce-visualblocks article { background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); } .mce-visualblocks blockquote { background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); } .mce-visualblocks address { background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); } .mce-visualblocks pre { background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); } .mce-visualblocks figure { background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); } .mce-visualblocks figcaption { border: 1px dashed #bbb; } .mce-visualblocks hgroup { background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); } .mce-visualblocks aside { background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); } .mce-visualblocks ul { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); } .mce-visualblocks ol { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); } .mce-visualblocks dl { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); } .mce-visualblocks:not([dir=rtl]) p, .mce-visualblocks:not([dir=rtl]) h1, .mce-visualblocks:not([dir=rtl]) h2, .mce-visualblocks:not([dir=rtl]) h3, .mce-visualblocks:not([dir=rtl]) h4, .mce-visualblocks:not([dir=rtl]) h5, .mce-visualblocks:not([dir=rtl]) h6, .mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), .mce-visualblocks:not([dir=rtl]) section, .mce-visualblocks:not([dir=rtl]) article, .mce-visualblocks:not([dir=rtl]) blockquote, .mce-visualblocks:not([dir=rtl]) address, .mce-visualblocks:not([dir=rtl]) pre, .mce-visualblocks:not([dir=rtl]) figure, .mce-visualblocks:not([dir=rtl]) figcaption, .mce-visualblocks:not([dir=rtl]) hgroup, .mce-visualblocks:not([dir=rtl]) aside, .mce-visualblocks:not([dir=rtl]) ul, .mce-visualblocks:not([dir=rtl]) ol, .mce-visualblocks:not([dir=rtl]) dl { margin-left: 3px; } .mce-visualblocks[dir=rtl] p, .mce-visualblocks[dir=rtl] h1, .mce-visualblocks[dir=rtl] h2, .mce-visualblocks[dir=rtl] h3, .mce-visualblocks[dir=rtl] h4, .mce-visualblocks[dir=rtl] h5, .mce-visualblocks[dir=rtl] h6, .mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), .mce-visualblocks[dir=rtl] section, .mce-visualblocks[dir=rtl] article, .mce-visualblocks[dir=rtl] blockquote, .mce-visualblocks[dir=rtl] address, .mce-visualblocks[dir=rtl] pre, .mce-visualblocks[dir=rtl] figure, .mce-visualblocks[dir=rtl] figcaption, .mce-visualblocks[dir=rtl] hgroup, .mce-visualblocks[dir=rtl] aside, .mce-visualblocks[dir=rtl] ul, .mce-visualblocks[dir=rtl] ol, .mce-visualblocks[dir=rtl] dl { background-position-x: right; margin-right: 3px; } .mce-nbsp, .mce-shy { background: #aaa; } .mce-shy::after { content: '-'; } body { font-family: sans-serif; } table { border-collapse: collapse; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/tinymce-5/content.inline.css ================================================ .mce-content-body .mce-item-anchor { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; } .mce-content-body .mce-item-anchor:empty { cursor: default; display: inline-block; height: 12px !important; padding: 0 2px; -webkit-user-modify: read-only; -moz-user-modify: read-only; -webkit-user-select: all; -moz-user-select: all; user-select: all; width: 8px !important; } .mce-content-body .mce-item-anchor:not(:empty) { background-position-x: 2px; display: inline-block; padding-left: 12px; } .mce-content-body .mce-item-anchor[data-mce-selected] { outline-offset: 1px; } .tox-comments-visible .tox-comment[contenteditable="false"]:not([data-mce-selected]), .tox-comments-visible span.tox-comment img:not([data-mce-selected]), .tox-comments-visible span.tox-comment > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #ffe89d; } .tox-comments-visible .tox-comment[contenteditable="false"][data-mce-annotation-active="true"]:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] img:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment:not([data-mce-selected]) { background-color: #ffe89d; outline: none; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"]:not([data-mce-selected="inline-boundary"]) { background-color: #fed635; } .tox-checklist > li:not(.tox-checklist--hidden) { list-style: none; margin: 0.25em 0; } .tox-checklist > li:not(.tox-checklist--hidden)::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); cursor: pointer; height: 1em; margin-left: -1.5em; margin-top: 0.125em; position: absolute; width: 1em; } .tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); } [dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { margin-left: 0; margin-right: -1.5em; } /* stylelint-disable */ /* http://prismjs.com/ */ /** * prism.js default theme for JavaScript, CSS and HTML * Based on dabblet (http://dabblet.com) * @author Lea Verou */ code[class*="language-"], pre[class*="language-"] { color: black; background: none; text-shadow: 0 1px white; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; font-size: 1em; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.5; -moz-tab-size: 4; tab-size: 4; -webkit-hyphens: none; hyphens: none; } pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { text-shadow: none; background: #b3d4fc; } pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection { text-shadow: none; background: #b3d4fc; } @media print { code[class*="language-"], pre[class*="language-"] { text-shadow: none; } } /* Code blocks */ pre[class*="language-"] { padding: 1em; margin: 0.5em 0; overflow: auto; } :not(pre) > code[class*="language-"], pre[class*="language-"] { background: #f5f2f0; } /* Inline code */ :not(pre) > code[class*="language-"] { padding: 0.1em; border-radius: 0.3em; white-space: normal; } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: slategray; } .token.punctuation { color: #999; } .token.namespace { opacity: 0.7; } .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: #905; } .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #690; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { color: #9a6e3a; /* This background color was intended by the author of this theme. */ background: hsla(0, 0%, 100%, 0.5); } .token.atrule, .token.attr-value, .token.keyword { color: #07a; } .token.function, .token.class-name { color: #DD4A68; } .token.regex, .token.important, .token.variable { color: #e90; } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } /* stylelint-enable */ .mce-content-body { overflow-wrap: break-word; word-wrap: break-word; } .mce-content-body .mce-visual-caret { background-color: black; background-color: currentColor; position: absolute; } .mce-content-body .mce-visual-caret-hidden { display: none; } .mce-content-body *[data-mce-caret] { left: -1000px; margin: 0; padding: 0; position: absolute; right: auto; top: 0; } .mce-content-body .mce-offscreen-selection { left: -2000000px; max-width: 1000000px; position: absolute; } .mce-content-body *[contentEditable=false] { cursor: default; } .mce-content-body *[contentEditable=true] { cursor: text; } .tox-cursor-format-painter { cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; } div.mce-footnotes hr { margin-inline-end: auto; margin-inline-start: 0; width: 25%; } div.mce-footnotes li > a.mce-footnotes-backlink { text-decoration: none; } @media print { sup.mce-footnote a { color: black; text-decoration: none; } div.mce-footnotes { break-inside: avoid; width: 100%; } div.mce-footnotes li > a.mce-footnotes-backlink { display: none; } } .mce-content-body figure.align-left { float: left; } .mce-content-body figure.align-right { float: right; } .mce-content-body figure.image.align-center { display: table; margin-left: auto; margin-right: auto; } .mce-preview-object { border: 1px solid gray; display: inline-block; line-height: 0; margin: 0 2px 0 2px; position: relative; } .mce-preview-object .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-preview-object[data-mce-selected="2"] .mce-shim { display: none; } .mce-content-body .mce-mergetag { cursor: default !important; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body .mce-mergetag:hover { background-color: rgba(0, 108, 231, 0.1); } .mce-content-body .mce-mergetag-affix { background-color: rgba(0, 108, 231, 0.1); color: #006ce7; } .mce-object { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; border: 1px dashed #aaa; } .mce-pagebreak { border: 1px dashed #aaa; cursor: default; display: block; height: 5px; margin-top: 15px; page-break-before: always; width: 100%; } @media print { .mce-pagebreak { border: 0; } } .tiny-pageembed .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tiny-pageembed[data-mce-selected="2"] .mce-shim { display: none; } .tiny-pageembed { display: inline-block; position: relative; } .tiny-pageembed--21by9, .tiny-pageembed--16by9, .tiny-pageembed--4by3, .tiny-pageembed--1by1 { display: block; overflow: hidden; padding: 0; position: relative; width: 100%; } .tiny-pageembed--21by9 { padding-top: 42.857143%; } .tiny-pageembed--16by9 { padding-top: 56.25%; } .tiny-pageembed--4by3 { padding-top: 75%; } .tiny-pageembed--1by1 { padding-top: 100%; } .tiny-pageembed--21by9 iframe, .tiny-pageembed--16by9 iframe, .tiny-pageembed--4by3 iframe, .tiny-pageembed--1by1 iframe { border: 0; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-content-body[data-mce-placeholder] { position: relative; } .mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { color: rgba(34, 47, 62, 0.7); content: attr(data-mce-placeholder); position: absolute; } .mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { left: 1px; } .mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { right: 1px; } .mce-content-body div.mce-resizehandle { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; height: 10px; position: absolute; width: 10px; z-index: 1298; } .mce-content-body div.mce-resizehandle:hover { background-color: #4099ff; } .mce-content-body div.mce-resizehandle:nth-of-type(1) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(2) { cursor: nesw-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(3) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(4) { cursor: nesw-resize; } .mce-content-body .mce-resize-backdrop { z-index: 10000; } .mce-content-body .mce-clonedresizable { cursor: default; opacity: 0.5; outline: 1px dashed black; position: absolute; z-index: 10001; } .mce-content-body .mce-clonedresizable.mce-resizetable-columns th, .mce-content-body .mce-clonedresizable.mce-resizetable-columns td { border: 0; } .mce-content-body .mce-resize-helper { background: #555; background: rgba(0, 0, 0, 0.75); border: 1px; border-radius: 3px; color: white; display: none; font-family: sans-serif; font-size: 12px; line-height: 14px; margin: 5px 10px; padding: 5px; position: absolute; white-space: nowrap; z-index: 10002; } .tox-rtc-user-selection { position: relative; } .tox-rtc-user-cursor { bottom: 0; cursor: default; position: absolute; top: 0; width: 2px; } .tox-rtc-user-cursor::before { background-color: inherit; border-radius: 50%; content: ''; display: block; height: 8px; position: absolute; right: -3px; top: -3px; width: 8px; } .tox-rtc-user-cursor:hover::after { background-color: inherit; border-radius: 100px; box-sizing: border-box; color: #fff; content: attr(data-user); display: block; font-size: 12px; font-weight: bold; left: -5px; min-height: 8px; min-width: 8px; padding: 0 12px; position: absolute; top: -11px; white-space: nowrap; z-index: 1000; } .tox-rtc-user-selection--1 .tox-rtc-user-cursor { background-color: #2dc26b; } .tox-rtc-user-selection--2 .tox-rtc-user-cursor { background-color: #e03e2d; } .tox-rtc-user-selection--3 .tox-rtc-user-cursor { background-color: #f1c40f; } .tox-rtc-user-selection--4 .tox-rtc-user-cursor { background-color: #3598db; } .tox-rtc-user-selection--5 .tox-rtc-user-cursor { background-color: #b96ad9; } .tox-rtc-user-selection--6 .tox-rtc-user-cursor { background-color: #e67e23; } .tox-rtc-user-selection--7 .tox-rtc-user-cursor { background-color: #aaa69d; } .tox-rtc-user-selection--8 .tox-rtc-user-cursor { background-color: #f368e0; } .tox-rtc-remote-image { background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; border: 1px solid #ccc; min-height: 240px; min-width: 320px; } .mce-match-marker { background: #aaa; color: #fff; } .mce-match-marker-selected { background: #39f; color: #fff; } .mce-match-marker-selected::-moz-selection { background: #39f; color: #fff; } .mce-match-marker-selected::selection { background: #39f; color: #fff; } .mce-content-body img[data-mce-selected], .mce-content-body video[data-mce-selected], .mce-content-body audio[data-mce-selected], .mce-content-body object[data-mce-selected], .mce-content-body embed[data-mce-selected], .mce-content-body table[data-mce-selected], .mce-content-body details[data-mce-selected] { outline: 3px solid #b4d7ff; } .mce-content-body hr[data-mce-selected] { outline: 3px solid #b4d7ff; outline-offset: 1px; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false][data-mce-selected] { cursor: not-allowed; outline: 3px solid #b4d7ff; } .mce-content-body.mce-content-readonly *[contentEditable=true]:focus, .mce-content-body.mce-content-readonly *[contentEditable=true]:hover { outline: none; } .mce-content-body *[data-mce-selected="inline-boundary"] { background-color: #b4d7ff; } .mce-content-body .mce-edit-focus { outline: 3px solid #b4d7ff; } .mce-content-body td[data-mce-selected], .mce-content-body th[data-mce-selected] { position: relative; } .mce-content-body td[data-mce-selected]::-moz-selection, .mce-content-body th[data-mce-selected]::-moz-selection { background: none; } .mce-content-body td[data-mce-selected]::selection, .mce-content-body th[data-mce-selected]::selection { background: none; } .mce-content-body td[data-mce-selected] *, .mce-content-body th[data-mce-selected] * { outline: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { background-color: rgba(180, 215, 255, 0.7); border: 1px solid rgba(180, 215, 255, 0.7); bottom: -1px; content: ''; left: -1px; mix-blend-mode: multiply; position: absolute; right: -1px; top: -1px; } @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { border-color: rgba(0, 84, 180, 0.7); } } .mce-content-body img[data-mce-selected]::-moz-selection { background: none; } .mce-content-body img[data-mce-selected]::selection { background: none; } .ephox-snooker-resizer-bar { background-color: #b4d7ff; opacity: 0; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .ephox-snooker-resizer-cols { cursor: col-resize; } .ephox-snooker-resizer-rows { cursor: row-resize; } .ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { opacity: 1; } .mce-spellchecker-word { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; height: 2rem; } .mce-spellchecker-grammar { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; } .mce-toc { border: 1px solid gray; } .mce-toc h2 { margin: 4px; } .mce-toc li { list-style-type: none; } [data-mce-block] { display: block; } table[style*="border-width: 0px"], .mce-item-table:not([border]), .mce-item-table[border="0"], table[style*="border-width: 0px"] td, .mce-item-table:not([border]) td, .mce-item-table[border="0"] td, table[style*="border-width: 0px"] th, .mce-item-table:not([border]) th, .mce-item-table[border="0"] th, table[style*="border-width: 0px"] caption, .mce-item-table:not([border]) caption, .mce-item-table[border="0"] caption { border: 1px dashed #bbb; } .mce-visualblocks p, .mce-visualblocks h1, .mce-visualblocks h2, .mce-visualblocks h3, .mce-visualblocks h4, .mce-visualblocks h5, .mce-visualblocks h6, .mce-visualblocks div:not([data-mce-bogus]), .mce-visualblocks section, .mce-visualblocks article, .mce-visualblocks blockquote, .mce-visualblocks address, .mce-visualblocks pre, .mce-visualblocks figure, .mce-visualblocks figcaption, .mce-visualblocks hgroup, .mce-visualblocks aside, .mce-visualblocks ul, .mce-visualblocks ol, .mce-visualblocks dl { background-repeat: no-repeat; border: 1px dashed #bbb; margin-left: 3px; padding-top: 10px; } .mce-visualblocks p { background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); } .mce-visualblocks h1 { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); } .mce-visualblocks h2 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); } .mce-visualblocks h3 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); } .mce-visualblocks h4 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); } .mce-visualblocks h5 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); } .mce-visualblocks h6 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); } .mce-visualblocks div:not([data-mce-bogus]) { background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); } .mce-visualblocks section { background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); } .mce-visualblocks article { background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); } .mce-visualblocks blockquote { background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); } .mce-visualblocks address { background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); } .mce-visualblocks pre { background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); } .mce-visualblocks figure { background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); } .mce-visualblocks figcaption { border: 1px dashed #bbb; } .mce-visualblocks hgroup { background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); } .mce-visualblocks aside { background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); } .mce-visualblocks ul { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); } .mce-visualblocks ol { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); } .mce-visualblocks dl { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); } .mce-visualblocks:not([dir=rtl]) p, .mce-visualblocks:not([dir=rtl]) h1, .mce-visualblocks:not([dir=rtl]) h2, .mce-visualblocks:not([dir=rtl]) h3, .mce-visualblocks:not([dir=rtl]) h4, .mce-visualblocks:not([dir=rtl]) h5, .mce-visualblocks:not([dir=rtl]) h6, .mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), .mce-visualblocks:not([dir=rtl]) section, .mce-visualblocks:not([dir=rtl]) article, .mce-visualblocks:not([dir=rtl]) blockquote, .mce-visualblocks:not([dir=rtl]) address, .mce-visualblocks:not([dir=rtl]) pre, .mce-visualblocks:not([dir=rtl]) figure, .mce-visualblocks:not([dir=rtl]) figcaption, .mce-visualblocks:not([dir=rtl]) hgroup, .mce-visualblocks:not([dir=rtl]) aside, .mce-visualblocks:not([dir=rtl]) ul, .mce-visualblocks:not([dir=rtl]) ol, .mce-visualblocks:not([dir=rtl]) dl { margin-left: 3px; } .mce-visualblocks[dir=rtl] p, .mce-visualblocks[dir=rtl] h1, .mce-visualblocks[dir=rtl] h2, .mce-visualblocks[dir=rtl] h3, .mce-visualblocks[dir=rtl] h4, .mce-visualblocks[dir=rtl] h5, .mce-visualblocks[dir=rtl] h6, .mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), .mce-visualblocks[dir=rtl] section, .mce-visualblocks[dir=rtl] article, .mce-visualblocks[dir=rtl] blockquote, .mce-visualblocks[dir=rtl] address, .mce-visualblocks[dir=rtl] pre, .mce-visualblocks[dir=rtl] figure, .mce-visualblocks[dir=rtl] figcaption, .mce-visualblocks[dir=rtl] hgroup, .mce-visualblocks[dir=rtl] aside, .mce-visualblocks[dir=rtl] ul, .mce-visualblocks[dir=rtl] ol, .mce-visualblocks[dir=rtl] dl { background-position-x: right; margin-right: 3px; } .mce-nbsp, .mce-shy { background: #aaa; } .mce-shy::after { content: '-'; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/tinymce-5/skin.css ================================================ .tox { box-shadow: none; box-sizing: content-box; color: #222f3e; cursor: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; font-style: normal; font-weight: normal; line-height: normal; -webkit-tap-highlight-color: transparent; text-decoration: none; text-shadow: none; text-transform: none; vertical-align: initial; white-space: normal; } .tox *:not(svg):not(rect) { box-sizing: inherit; color: inherit; cursor: inherit; direction: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; -webkit-tap-highlight-color: inherit; text-align: inherit; text-decoration: inherit; text-shadow: inherit; text-transform: inherit; vertical-align: inherit; white-space: inherit; } .tox *:not(svg):not(rect) { /* stylelint-disable-line no-duplicate-selectors */ background: transparent; border: 0; box-shadow: none; float: none; height: auto; margin: 0; max-width: none; outline: 0; padding: 0; position: static; width: auto; } .tox:not([dir=rtl]) { direction: ltr; text-align: left; } .tox[dir=rtl] { direction: rtl; text-align: right; } .tox-tinymce { border: 1px solid #cccccc; border-radius: 0; box-shadow: none; box-sizing: border-box; display: flex; flex-direction: column; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; overflow: hidden; position: relative; visibility: inherit !important; } .tox.tox-tinymce-inline { border: none; box-shadow: none; overflow: initial; } .tox.tox-tinymce-inline .tox-editor-container { overflow: initial; } .tox.tox-tinymce-inline .tox-editor-header { background-color: #fff; border: 1px solid #cccccc; border-radius: 0; box-shadow: none; overflow: hidden; } .tox-tinymce-aux { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; z-index: 1300; } .tox-tinymce *:focus, .tox-tinymce-aux *:focus { outline: none; } button::-moz-focus-inner { border: 0; } .tox[dir=rtl] .tox-icon--flip svg { transform: rotateY(180deg); } .tox .accessibility-issue__header { align-items: center; display: flex; margin-bottom: 4px; } .tox .accessibility-issue__description { align-items: stretch; border-radius: 3px; display: flex; justify-content: space-between; } .tox .accessibility-issue__description > div { padding-bottom: 4px; } .tox .accessibility-issue__description > div > div { align-items: center; display: flex; margin-bottom: 4px; } .tox .accessibility-issue__description > div > div .tox-icon svg { display: block; } .tox .accessibility-issue__repair { margin-top: 16px; } .tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { background-color: rgba(30, 113, 170, 0.1); color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { color: #207ab7; } .tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { fill: #207ab7; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon { background-color: #207ab7; color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus { background-color: #1c6ca1; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active { background-color: #185d8c; } .tox .tox-dialog__body-content .accessibility-issue--warn { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { background-color: rgba(255, 165, 0, 0.08); color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { color: #8f5d00; } .tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { fill: #8f5d00; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon { background-color: #FFE89D; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus { background-color: #F2D574; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active { background-color: #E8C657; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { background-color: rgba(204, 0, 0, 0.1); color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { color: #c00; } .tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { fill: #c00; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon { background-color: #F2BFBF; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus { background-color: #E9A4A4; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active { background-color: #EE9494; color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { background-color: rgba(120, 171, 70, 0.1); color: #222f3e; } .tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > *:last-child { display: none; } .tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { color: #527530; } .tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { fill: #527530; } .tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1, .tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { font-size: 14px; margin-top: 0; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button { margin-left: 4px; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { margin-left: auto; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description { padding: 4px 4px 4px 8px; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button { margin-right: 4px; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { margin-right: auto; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description { padding: 4px 8px 4px 4px; } .tox .tox-advtemplate .tox-form__grid { flex: 1; } .tox .tox-advtemplate .tox-form__grid > div:first-child { display: flex; flex-direction: column; width: 30%; } .tox .tox-advtemplate .tox-form__grid > div:first-child > div:nth-child(2) { flex-basis: 0; flex-grow: 1; overflow: auto; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid > div:first-child { width: 100%; } } .tox .tox-advtemplate iframe { border-color: #cccccc; border-radius: 0; border-style: solid; border-width: 1px; margin: 0 10px; } .tox .tox-anchorbar { display: flex; flex: 0 0 auto; } .tox .tox-bottom-anchorbar { display: flex; flex: 0 0 auto; } .tox .tox-bar { display: flex; flex: 0 0 auto; } .tox .tox-button { background-color: #207ab7; background-image: none; background-position: 0 0; background-repeat: repeat; border-color: #207ab7; border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #fff; cursor: pointer; display: inline-block; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 14px; font-style: normal; font-weight: bold; letter-spacing: normal; line-height: 24px; margin: 0; outline: none; padding: 4px 16px; position: relative; text-align: center; text-decoration: none; text-transform: none; white-space: nowrap; } .tox .tox-button::before { border-radius: 3px; bottom: -1px; box-shadow: inset 0 0 0 2px #fff, 0 0 0 1px #207ab7, 0 0 0 3px rgba(32, 122, 183, 0.25); content: ''; left: -1px; opacity: 0; pointer-events: none; position: absolute; right: -1px; top: -1px; } .tox .tox-button[disabled] { background-color: #207ab7; background-image: none; border-color: #207ab7; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-button:focus:not(:disabled) { background-color: #1c6ca1; background-image: none; border-color: #1c6ca1; box-shadow: none; color: #fff; } .tox .tox-button:focus-visible:not(:disabled)::before { opacity: 1; } .tox .tox-button:hover:not(:disabled) { background-color: #1c6ca1; background-image: none; border-color: #1c6ca1; box-shadow: none; color: #fff; } .tox .tox-button:active:not(:disabled) { background-color: #185d8c; background-image: none; border-color: #185d8c; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled { background-color: #185d8c; background-image: none; border-color: #185d8c; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled[disabled] { background-color: #185d8c; background-image: none; border-color: #185d8c; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-button.tox-button--enabled:focus:not(:disabled) { background-color: #154f76; background-image: none; border-color: #154f76; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled:hover:not(:disabled) { background-color: #154f76; background-image: none; border-color: #154f76; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled:active:not(:disabled) { background-color: #114060; background-image: none; border-color: #114060; box-shadow: none; color: #fff; } .tox .tox-button--icon-and-text, .tox .tox-button.tox-button--icon-and-text, .tox .tox-button.tox-button--secondary.tox-button--icon-and-text { display: flex; padding: 5px 4px; } .tox .tox-button--icon-and-text .tox-icon svg, .tox .tox-button.tox-button--icon-and-text .tox-icon svg, .tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg { display: block; fill: currentColor; } .tox .tox-button--secondary { background-color: #f0f0f0; background-image: none; background-position: 0 0; background-repeat: repeat; border-color: #f0f0f0; border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; color: #222f3e; font-size: 14px; font-style: normal; font-weight: bold; letter-spacing: normal; outline: none; padding: 4px 16px; text-decoration: none; text-transform: none; } .tox .tox-button--secondary[disabled] { background-color: #f0f0f0; background-image: none; border-color: #f0f0f0; box-shadow: none; color: rgba(34, 47, 62, 0.5); } .tox .tox-button--secondary:focus:not(:disabled) { background-color: #e3e3e3; background-image: none; border-color: #e3e3e3; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary:hover:not(:disabled) { background-color: #e3e3e3; background-image: none; border-color: #e3e3e3; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary:active:not(:disabled) { background-color: #d6d6d6; background-image: none; border-color: #d6d6d6; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary.tox-button--enabled { background-color: #b1ccdf; background-image: none; border-color: #b1ccdf; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary.tox-button--enabled[disabled] { background-color: #b1ccdf; background-image: none; border-color: #b1ccdf; box-shadow: none; color: rgba(34, 47, 62, 0.5); } .tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled) { background-color: #9fc1d7; background-image: none; border-color: #9fc1d7; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled) { background-color: #9fc1d7; background-image: none; border-color: #9fc1d7; box-shadow: none; color: #222f3e; } .tox .tox-button--secondary.tox-button--enabled:active:not(:disabled) { background-color: #8db5d0; background-image: none; border-color: #8db5d0; box-shadow: none; color: #222f3e; } .tox .tox-button--icon, .tox .tox-button.tox-button--icon, .tox .tox-button.tox-button--secondary.tox-button--icon { padding: 4px; } .tox .tox-button--icon .tox-icon svg, .tox .tox-button.tox-button--icon .tox-icon svg, .tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { display: block; fill: currentColor; } .tox .tox-button-link { background: 0; border: none; box-sizing: border-box; cursor: pointer; display: inline-block; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; font-weight: normal; line-height: 1.3; margin: 0; padding: 0; white-space: nowrap; } .tox .tox-button-link--sm { font-size: 14px; } .tox .tox-button--naked { background-color: transparent; border-color: transparent; box-shadow: unset; color: #222f3e; } .tox .tox-button--naked[disabled] { background-color: #f0f0f0; border-color: #f0f0f0; box-shadow: none; color: rgba(34, 47, 62, 0.5); } .tox .tox-button--naked:hover:not(:disabled) { background-color: #e3e3e3; border-color: #e3e3e3; box-shadow: none; color: #222f3e; } .tox .tox-button--naked:focus:not(:disabled) { background-color: #e3e3e3; border-color: #e3e3e3; box-shadow: none; color: #222f3e; } .tox .tox-button--naked:active:not(:disabled) { background-color: #d6d6d6; border-color: #d6d6d6; box-shadow: none; color: #222f3e; } .tox .tox-button--naked .tox-icon svg { fill: currentColor; } .tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { color: #222f3e; } .tox .tox-checkbox { align-items: center; border-radius: 3px; cursor: pointer; display: flex; height: 36px; min-width: 36px; } .tox .tox-checkbox__input { /* Hide from view but visible to screen readers */ height: 1px; overflow: hidden; position: absolute; top: auto; width: 1px; } .tox .tox-checkbox__icons { align-items: center; border-radius: 3px; box-shadow: 0 0 0 2px transparent; box-sizing: content-box; display: flex; height: 24px; justify-content: center; padding: calc(4px - 1px); width: 24px; } .tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: block; fill: rgba(34, 47, 62, 0.3); } .tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { display: none; fill: #207ab7; } .tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { display: none; fill: #207ab7; } .tox .tox-checkbox--disabled { color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { fill: rgba(34, 47, 62, 0.5); } .tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: none; } .tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { display: block; } .tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: none; } .tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { display: block; } .tox input.tox-checkbox__input:focus + .tox-checkbox__icons { border-radius: 3px; box-shadow: inset 0 0 0 1px #207ab7; padding: calc(4px - 1px); } .tox:not([dir=rtl]) .tox-checkbox__label { margin-left: 4px; } .tox:not([dir=rtl]) .tox-checkbox__input { left: -10000px; } .tox:not([dir=rtl]) .tox-bar .tox-checkbox { margin-left: 4px; } .tox[dir=rtl] .tox-checkbox__label { margin-right: 4px; } .tox[dir=rtl] .tox-checkbox__input { right: -10000px; } .tox[dir=rtl] .tox-bar .tox-checkbox { margin-right: 4px; } .tox { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-collection--toolbar .tox-collection__group { display: flex; padding: 0; } .tox .tox-collection--grid .tox-collection__group { display: flex; flex-wrap: wrap; max-height: 208px; overflow-x: hidden; overflow-y: auto; padding: 0; } .tox .tox-collection--list .tox-collection__group { border-bottom-width: 0; border-color: #cccccc; border-left-width: 0; border-right-width: 0; border-style: solid; border-top-width: 1px; padding: 4px 0; } .tox .tox-collection--list .tox-collection__group:first-child { border-top-width: 0; } .tox .tox-collection__group-heading { background-color: #e6e6e6; color: rgba(34, 47, 62, 0.7); cursor: default; font-size: 12px; font-style: normal; font-weight: normal; margin-bottom: 4px; margin-top: -4px; padding: 4px 8px; text-transform: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .tox .tox-collection__item { align-items: center; border-radius: 3px; color: #222f3e; display: flex; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .tox .tox-collection--list .tox-collection__item { padding: 4px 8px; } .tox .tox-collection--toolbar .tox-collection__item { border-radius: 3px; padding: 4px; } .tox .tox-collection--grid .tox-collection__item { border-radius: 3px; padding: 4px; } .tox .tox-collection--list .tox-collection__item--enabled { background-color: #fff; color: #222f3e; } .tox .tox-collection--list .tox-collection__item--active { background-color: #dee0e2; } .tox .tox-collection--toolbar .tox-collection__item--enabled { background-color: #c8cbcf; color: #222f3e; } .tox .tox-collection--toolbar .tox-collection__item--active { background-color: #dee0e2; } .tox .tox-collection--grid .tox-collection__item--enabled { background-color: #c8cbcf; color: #222f3e; } .tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { background-color: #dee0e2; color: #222f3e; } .tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { color: #222f3e; } .tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { color: #222f3e; } .tox .tox-collection__item-icon, .tox .tox-collection__item-checkmark { align-items: center; display: flex; height: 24px; justify-content: center; width: 24px; } .tox .tox-collection__item-icon svg, .tox .tox-collection__item-checkmark svg { fill: currentColor; } .tox .tox-collection--toolbar-lg .tox-collection__item-icon { height: 48px; width: 48px; } .tox .tox-collection__item-label { color: currentColor; display: inline-block; flex: 1; font-size: 14px; font-style: normal; font-weight: normal; line-height: 24px; text-transform: none; word-break: break-all; } .tox .tox-collection__item-accessory { color: rgba(34, 47, 62, 0.7); display: inline-block; font-size: 14px; height: 24px; line-height: 24px; text-transform: none; } .tox .tox-collection__item-caret { align-items: center; display: flex; min-height: 24px; } .tox .tox-collection__item-caret::after { content: ''; font-size: 0; min-height: inherit; } .tox .tox-collection__item-caret svg { fill: #222f3e; } .tox .tox-collection__item--state-disabled { background-color: transparent; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg { display: none; } .tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory + .tox-collection__item-checkmark { display: none; } .tox .tox-collection--horizontal { background-color: #fff; border: 1px solid #cccccc; border-radius: 3px; box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: nowrap; margin-bottom: 0; overflow-x: auto; padding: 0; } .tox .tox-collection--horizontal .tox-collection__group { align-items: center; display: flex; flex-wrap: nowrap; margin: 0; padding: 0 4px; } .tox .tox-collection--horizontal .tox-collection__item { height: 34px; margin: 3px 0 2px 0; padding: 0 4px; } .tox .tox-collection--horizontal .tox-collection__item-label { white-space: nowrap; } .tox .tox-collection--horizontal .tox-collection__item-caret { margin-left: 4px; } .tox .tox-collection__item-container { display: flex; } .tox .tox-collection__item-container--row { align-items: center; flex: 1 1 auto; flex-direction: row; } .tox .tox-collection__item-container--row.tox-collection__item-container--align-left { margin-right: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--align-right { justify-content: flex-end; margin-left: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { align-items: flex-start; margin-bottom: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { align-items: center; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { align-items: flex-end; margin-top: auto; } .tox .tox-collection__item-container--column { align-self: center; flex: 1 1 auto; flex-direction: column; } .tox .tox-collection__item-container--column.tox-collection__item-container--align-left { align-items: flex-start; } .tox .tox-collection__item-container--column.tox-collection__item-container--align-right { align-items: flex-end; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { align-self: flex-start; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { align-self: center; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { align-self: flex-end; } .tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { border-right: 1px solid #cccccc; } .tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > *:not(:first-child) { margin-left: 8px; } .tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { margin-left: 4px; } .tox:not([dir=rtl]) .tox-collection__item-accessory { margin-left: 16px; text-align: right; } .tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret { margin-left: 16px; } .tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { border-left: 1px solid #cccccc; } .tox[dir=rtl] .tox-collection--list .tox-collection__item > *:not(:first-child) { margin-right: 8px; } .tox[dir=rtl] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { margin-right: 4px; } .tox[dir=rtl] .tox-collection__item-accessory { margin-right: 16px; text-align: left; } .tox[dir=rtl] .tox-collection .tox-collection__item-caret { margin-right: 16px; transform: rotateY(180deg); } .tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret { margin-right: 4px; } .tox .tox-color-picker-container { display: flex; flex-direction: row; height: 225px; margin: 0; } .tox .tox-sv-palette { box-sizing: border-box; display: flex; height: 100%; } .tox .tox-sv-palette-spectrum { height: 100%; } .tox .tox-sv-palette, .tox .tox-sv-palette-spectrum { width: 225px; } .tox .tox-sv-palette-thumb { background: none; border: 1px solid black; border-radius: 50%; box-sizing: content-box; height: 12px; position: absolute; width: 12px; } .tox .tox-sv-palette-inner-thumb { border: 1px solid white; border-radius: 50%; height: 10px; position: absolute; width: 10px; } .tox .tox-hue-slider { box-sizing: border-box; height: 100%; width: 25px; } .tox .tox-hue-slider-spectrum { background: linear-gradient(to bottom, #f00, #ff0080, #f0f, #8000ff, #00f, #0080ff, #0ff, #00ff80, #0f0, #80ff00, #ff0, #ff8000, #f00); height: 100%; width: 100%; } .tox .tox-hue-slider, .tox .tox-hue-slider-spectrum { width: 20px; } .tox .tox-hue-slider-thumb { background: white; border: 1px solid black; box-sizing: content-box; height: 4px; width: 100%; } .tox .tox-rgb-form { display: flex; flex-direction: column; justify-content: space-between; } .tox .tox-rgb-form div { align-items: center; display: flex; justify-content: space-between; margin-bottom: 5px; width: inherit; } .tox .tox-rgb-form input { width: 6em; } .tox .tox-rgb-form input.tox-invalid { /* Need !important to override Chrome's focus styling unfortunately */ border: 1px solid red !important; } .tox .tox-rgb-form .tox-rgba-preview { border: 1px solid black; flex-grow: 2; margin-bottom: 0; } .tox:not([dir=rtl]) .tox-sv-palette { margin-right: 15px; } .tox:not([dir=rtl]) .tox-hue-slider { margin-right: 15px; } .tox:not([dir=rtl]) .tox-hue-slider-thumb { margin-left: -1px; } .tox:not([dir=rtl]) .tox-rgb-form label { margin-right: 0.5em; } .tox[dir=rtl] .tox-sv-palette { margin-left: 15px; } .tox[dir=rtl] .tox-hue-slider { margin-left: 15px; } .tox[dir=rtl] .tox-hue-slider-thumb { margin-right: -1px; } .tox[dir=rtl] .tox-rgb-form label { margin-left: 0.5em; } .tox .tox-toolbar .tox-swatches, .tox .tox-toolbar__primary .tox-swatches, .tox .tox-toolbar__overflow .tox-swatches { margin: 2px 0 3px 4px; } .tox .tox-collection--list .tox-collection__group .tox-swatches-menu { border: 0; margin: -4px 0; } .tox .tox-swatches__row { display: flex; } .tox .tox-swatch { height: 30px; transition: transform 0.15s, box-shadow 0.15s; width: 30px; } .tox .tox-swatch:hover, .tox .tox-swatch:focus { box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; transform: scale(0.8); } .tox .tox-swatch--remove { align-items: center; display: flex; justify-content: center; } .tox .tox-swatch--remove svg path { stroke: #e74c3c; } .tox .tox-swatches__picker-btn { align-items: center; background-color: transparent; border: 0; cursor: pointer; display: flex; height: 30px; justify-content: center; outline: none; padding: 0; width: 30px; } .tox .tox-swatches__picker-btn svg { fill: #222f3e; height: 24px; width: 24px; } .tox .tox-swatches__picker-btn:hover { background: #dee0e2; } .tox div.tox-swatch:not(.tox-swatch--remove) svg { display: none; fill: #222f3e; height: 24px; margin: calc((30px - 24px) / 2) calc((30px - 24px) / 2); width: 24px; } .tox div.tox-swatch:not(.tox-swatch--remove) svg path { fill: #fff; paint-order: stroke; stroke: #222f3e; stroke-width: 2px; } .tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg { display: block; } .tox:not([dir=rtl]) .tox-swatches__picker-btn { margin-left: auto; } .tox[dir=rtl] .tox-swatches__picker-btn { margin-right: auto; } .tox .tox-comment-thread { background: #fff; position: relative; } .tox .tox-comment-thread > *:not(:first-child) { margin-top: 8px; } .tox .tox-comment { background: #fff; border: 1px solid #cccccc; border-radius: 3px; box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); padding: 8px 8px 16px 8px; position: relative; } .tox .tox-comment__header { align-items: center; color: #222f3e; display: flex; justify-content: space-between; } .tox .tox-comment__date { color: #222f3e; font-size: 12px; line-height: 18px; } .tox .tox-comment__body { color: #222f3e; font-size: 14px; font-style: normal; font-weight: normal; line-height: 1.3; margin-top: 8px; position: relative; text-transform: initial; } .tox .tox-comment__body textarea { resize: none; white-space: normal; width: 100%; } .tox .tox-comment__expander { padding-top: 8px; } .tox .tox-comment__expander p { color: rgba(34, 47, 62, 0.7); font-size: 14px; font-style: normal; } .tox .tox-comment__body p { margin: 0; } .tox .tox-comment__buttonspacing { padding-top: 16px; text-align: center; } .tox .tox-comment-thread__overlay::after { background: #fff; bottom: 0; content: ""; display: flex; left: 0; opacity: 0.9; position: absolute; right: 0; top: 0; z-index: 5; } .tox .tox-comment__reply { display: flex; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; margin-top: 8px; } .tox .tox-comment__reply > *:first-child { margin-bottom: 8px; width: 100%; } .tox .tox-comment__edit { display: flex; flex-wrap: wrap; justify-content: flex-end; margin-top: 16px; } .tox .tox-comment__gradient::after { background: linear-gradient(rgba(255, 255, 255, 0), #fff); bottom: 0; content: ""; display: block; height: 5em; margin-top: -40px; position: absolute; width: 100%; } .tox .tox-comment__overlay { background: #fff; bottom: 0; display: flex; flex-direction: column; flex-grow: 1; left: 0; opacity: 0.9; position: absolute; right: 0; text-align: center; top: 0; z-index: 5; } .tox .tox-comment__loading-text { align-items: center; color: #222f3e; display: flex; flex-direction: column; position: relative; } .tox .tox-comment__loading-text > div { padding-bottom: 16px; } .tox .tox-comment__overlaytext { bottom: 0; flex-direction: column; font-size: 14px; left: 0; padding: 1em; position: absolute; right: 0; top: 0; z-index: 10; } .tox .tox-comment__overlaytext p { background-color: #fff; box-shadow: 0 0 8px 8px #fff; color: #222f3e; text-align: center; } .tox .tox-comment__overlaytext div:nth-of-type(2) { font-size: 0.8em; } .tox .tox-comment__busy-spinner { align-items: center; background-color: #fff; bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; z-index: 20; } .tox .tox-comment__scroll { display: flex; flex-direction: column; flex-shrink: 1; overflow: auto; } .tox .tox-conversations { margin: 8px; } .tox:not([dir=rtl]) .tox-comment__edit { margin-left: 8px; } .tox:not([dir=rtl]) .tox-comment__buttonspacing > *:last-child, .tox:not([dir=rtl]) .tox-comment__edit > *:last-child, .tox:not([dir=rtl]) .tox-comment__reply > *:last-child { margin-left: 8px; } .tox[dir=rtl] .tox-comment__edit { margin-right: 8px; } .tox[dir=rtl] .tox-comment__buttonspacing > *:last-child, .tox[dir=rtl] .tox-comment__edit > *:last-child, .tox[dir=rtl] .tox-comment__reply > *:last-child { margin-right: 8px; } .tox .tox-user { align-items: center; display: flex; } .tox .tox-user__avatar svg { fill: rgba(34, 47, 62, 0.7); } .tox .tox-user__avatar img { border-radius: 50%; height: 36px; object-fit: cover; vertical-align: middle; width: 36px; } .tox .tox-user__name { color: #222f3e; font-size: 14px; font-style: normal; font-weight: bold; line-height: 18px; text-transform: none; } .tox:not([dir=rtl]) .tox-user__avatar svg, .tox:not([dir=rtl]) .tox-user__avatar img { margin-right: 8px; } .tox:not([dir=rtl]) .tox-user__avatar + .tox-user__name { margin-left: 8px; } .tox[dir=rtl] .tox-user__avatar svg, .tox[dir=rtl] .tox-user__avatar img { margin-left: 8px; } .tox[dir=rtl] .tox-user__avatar + .tox-user__name { margin-right: 8px; } .tox .tox-dialog-wrap { align-items: center; bottom: 0; display: flex; justify-content: center; left: 0; position: fixed; right: 0; top: 0; z-index: 1100; } .tox .tox-dialog-wrap__backdrop { background-color: rgba(255, 255, 255, 0.75); bottom: 0; left: 0; position: absolute; right: 0; top: 0; z-index: 1; } .tox .tox-dialog-wrap__backdrop--opaque { background-color: #fff; } .tox .tox-dialog { background-color: #fff; border-color: #cccccc; border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: 0 16px 16px -10px rgba(34, 47, 62, 0.15), 0 0 40px 1px rgba(34, 47, 62, 0.15); display: flex; flex-direction: column; max-height: 100%; max-width: 480px; overflow: hidden; position: relative; width: 95vw; z-index: 2; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog { align-self: flex-start; margin: 8px auto; max-height: calc(100vh - 8px * 2); width: calc(100vw - 16px); } } .tox .tox-dialog-inline { z-index: 1100; } .tox .tox-dialog__header { align-items: center; background-color: #fff; border-bottom: none; color: #222f3e; display: flex; font-size: 16px; justify-content: space-between; padding: 8px 16px 0 16px; position: relative; } .tox .tox-dialog__header .tox-button { z-index: 1; } .tox .tox-dialog__draghandle { cursor: grab; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tox .tox-dialog__draghandle:active { cursor: grabbing; } .tox .tox-dialog__dismiss { margin-left: auto; } .tox .tox-dialog__title { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 20px; font-style: normal; font-weight: normal; line-height: 1.3; margin: 0; text-transform: none; } .tox .tox-dialog__body { color: #222f3e; display: flex; flex: 1; font-size: 16px; font-style: normal; font-weight: normal; line-height: 1.3; min-width: 0; text-align: left; text-transform: none; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog__body { flex-direction: column; } } .tox .tox-dialog__body-nav { align-items: flex-start; display: flex; flex-direction: column; flex-shrink: 0; padding: 16px 16px; } @media only screen and (min-width: 768px ) { .tox .tox-dialog__body-nav { max-width: 11em; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { flex-direction: row; -webkit-overflow-scrolling: touch; overflow-x: auto; padding-bottom: 0; } } .tox .tox-dialog__body-nav-item { border-bottom: 2px solid transparent; color: rgba(34, 47, 62, 0.7); display: inline-block; flex-shrink: 0; font-size: 14px; line-height: 1.3; margin-bottom: 8px; max-width: 13em; text-decoration: none; } .tox .tox-dialog__body-nav-item:focus { background-color: rgba(32, 122, 183, 0.1); } .tox .tox-dialog__body-nav-item--active { border-bottom: 2px solid #207ab7; color: #207ab7; } .tox .tox-dialog__body-content { box-sizing: border-box; display: flex; flex: 1; flex-direction: column; max-height: min(650px, calc(100vh - 110px)); overflow: auto; -webkit-overflow-scrolling: touch; padding: 16px 16px; } .tox .tox-dialog__body-content > * { margin-bottom: 0; margin-top: 16px; } .tox .tox-dialog__body-content > *:first-child { margin-top: 0; } .tox .tox-dialog__body-content > *:last-child { margin-bottom: 0; } .tox .tox-dialog__body-content > *:only-child { margin-bottom: 0; margin-top: 0; } .tox .tox-dialog__body-content a { color: #207ab7; cursor: pointer; text-decoration: none; } .tox .tox-dialog__body-content a:hover, .tox .tox-dialog__body-content a:focus { color: #185d8c; text-decoration: none; } .tox .tox-dialog__body-content a:active { color: #185d8c; text-decoration: none; } .tox .tox-dialog__body-content svg { fill: #222f3e; } .tox .tox-dialog__body-content strong { font-weight: bold; } .tox .tox-dialog__body-content ul { list-style-type: disc; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dd { padding-inline-start: 2.5rem; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dl { margin-bottom: 16px; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dl, .tox .tox-dialog__body-content dd, .tox .tox-dialog__body-content dt { display: block; margin-inline-end: 0; margin-inline-start: 0; } .tox .tox-dialog__body-content .tox-form__group h1 { color: #222f3e; font-size: 20px; font-style: normal; font-weight: bold; letter-spacing: normal; margin-bottom: 16px; margin-top: 2rem; text-transform: none; } .tox .tox-dialog__body-content .tox-form__group h2 { color: #222f3e; font-size: 16px; font-style: normal; font-weight: bold; letter-spacing: normal; margin-bottom: 16px; margin-top: 2rem; text-transform: none; } .tox .tox-dialog__body-content .tox-form__group p { margin-bottom: 16px; } .tox .tox-dialog__body-content .tox-form__group h1:first-child, .tox .tox-dialog__body-content .tox-form__group h2:first-child, .tox .tox-dialog__body-content .tox-form__group p:first-child { margin-top: 0; } .tox .tox-dialog__body-content .tox-form__group h1:last-child, .tox .tox-dialog__body-content .tox-form__group h2:last-child, .tox .tox-dialog__body-content .tox-form__group p:last-child { margin-bottom: 0; } .tox .tox-dialog__body-content .tox-form__group h1:only-child, .tox .tox-dialog__body-content .tox-form__group h2:only-child, .tox .tox-dialog__body-content .tox-form__group p:only-child { margin-bottom: 0; margin-top: 0; } .tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center { text-align: center; } .tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end { text-align: end; } .tox .tox-dialog--width-lg { height: 650px; max-width: 1200px; } .tox .tox-dialog--fullscreen { height: 100%; max-width: 100%; } .tox .tox-dialog--fullscreen .tox-dialog__body-content { max-height: 100%; } .tox .tox-dialog--width-md { max-width: 800px; } .tox .tox-dialog--width-md .tox-dialog__body-content { overflow: auto; } .tox .tox-dialog__body-content--centered { text-align: center; } .tox .tox-dialog__footer { align-items: center; background-color: #fff; border-top: 1px solid #cccccc; display: flex; justify-content: space-between; padding: 8px 16px; } .tox .tox-dialog__footer-start, .tox .tox-dialog__footer-end { display: flex; } .tox .tox-dialog__busy-spinner { align-items: center; background-color: rgba(255, 255, 255, 0.75); bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; z-index: 3; } .tox .tox-dialog__table { border-collapse: collapse; width: 100%; } .tox .tox-dialog__table thead th { font-weight: bold; padding-bottom: 8px; } .tox .tox-dialog__table thead th:first-child { padding-right: 8px; } .tox .tox-dialog__table tbody tr { border-bottom: 1px solid #404040; } .tox .tox-dialog__table tbody tr:last-child { border-bottom: none; } .tox .tox-dialog__table td { padding-bottom: 8px; padding-top: 8px; } .tox .tox-dialog__table td:first-child { padding-right: 8px; } .tox .tox-dialog__iframe { min-height: 200px; } .tox .tox-dialog__iframe.tox-dialog__iframe--opaque { background: #fff; } .tox .tox-dialog__iframe.tox-dialog__iframe--bordered { border: 1px solid #cccccc; border-radius: 3px; } .tox .tox-dialog__popups { position: absolute; width: 100%; z-index: 1100; } .tox .tox-dialog__body-iframe { display: flex; flex: 1; flex-direction: column; } .tox .tox-dialog__body-iframe .tox-navobj { display: flex; flex: 1; } .tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { flex: 1; height: 100%; } .tox .tox-dialog-dock-fadeout { opacity: 0; visibility: hidden; } .tox .tox-dialog-dock-fadein { opacity: 1; visibility: visible; } .tox .tox-dialog-dock-transition { transition: visibility 0s linear 0.3s, opacity 0.3s ease; } .tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { transition-delay: 0s; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav { margin-right: 0; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child) { margin-left: 8px; } } .tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start > *, .tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end > * { margin-left: 8px; } .tox[dir=rtl] .tox-dialog__body { text-align: right; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav { margin-left: 0; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child) { margin-right: 8px; } } .tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start > *, .tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end > * { margin-right: 8px; } body.tox-dialog__disable-scroll { overflow: hidden; } .tox .tox-dropzone-container { display: flex; flex: 1; } .tox .tox-dropzone { align-items: center; background: #fff; border: 2px dashed #cccccc; box-sizing: border-box; display: flex; flex-direction: column; flex-grow: 1; justify-content: center; min-height: 100px; padding: 10px; } .tox .tox-dropzone p { color: rgba(34, 47, 62, 0.7); margin: 0 0 16px 0; } .tox .tox-edit-area { display: flex; flex: 1; overflow: hidden; position: relative; } .tox .tox-edit-area::before { border: 2px solid #2D6ADF; border-radius: 4px; content: ''; inset: 0; opacity: 0; pointer-events: none; position: absolute; transition: opacity 0.15s; z-index: 1; } .tox .tox-edit-area__iframe { background-color: #fff; border: 0; box-sizing: border-box; flex: 1; height: 100%; position: absolute; width: 100%; } .tox.tox-edit-focus .tox-edit-area::before { opacity: 1; } .tox.tox-inline-edit-area { border: 1px dotted #cccccc; } .tox .tox-editor-container { display: flex; flex: 1 1 auto; flex-direction: column; overflow: hidden; } .tox .tox-editor-header { display: grid; grid-template-columns: 1fr min-content; z-index: 2; } .tox:not(.tox-tinymce-inline) .tox-editor-header { background-color: #fff; border-bottom: none; box-shadow: none; padding: 4px 0; } .tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition) { transition: box-shadow 0.5s; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { border-top: 1px solid #cccccc; box-shadow: none; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { background-color: #fff; box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); padding: 4px 0; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); } .tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty { background: none; border: none; box-shadow: none; padding: 0; } .tox-editor-dock-fadeout { opacity: 0; visibility: hidden; } .tox-editor-dock-fadein { opacity: 1; visibility: visible; } .tox-editor-dock-transition { transition: visibility 0s linear 0.25s, opacity 0.25s ease; } .tox-editor-dock-transition.tox-editor-dock-fadein { transition-delay: 0s; } .tox .tox-control-wrap { flex: 1; position: relative; } .tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, .tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, .tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { display: none; } .tox .tox-control-wrap svg { display: block; } .tox .tox-control-wrap__status-icon-wrap { position: absolute; top: 50%; transform: translateY(-50%); } .tox .tox-control-wrap__status-icon-invalid svg { fill: #c00; } .tox .tox-control-wrap__status-icon-unknown svg { fill: orange; } .tox .tox-control-wrap__status-icon-valid svg { fill: green; } .tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield, .tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield, .tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield { padding-right: 32px; } .tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap { right: 4px; } .tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield, .tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield, .tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield { padding-left: 32px; } .tox[dir=rtl] .tox-control-wrap__status-icon-wrap { left: 4px; } .tox .tox-autocompleter { max-width: 25em; } .tox .tox-autocompleter .tox-menu { box-sizing: border-box; max-width: 25em; } .tox .tox-autocompleter .tox-autocompleter-highlight { font-weight: bold; } .tox .tox-color-input { display: flex; position: relative; z-index: 1; } .tox .tox-color-input .tox-textfield { z-index: -1; } .tox .tox-color-input span { border-color: rgba(34, 47, 62, 0.2); border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; height: 24px; position: absolute; top: 6px; width: 24px; } .tox .tox-color-input span:hover:not([aria-disabled=true]), .tox .tox-color-input span:focus:not([aria-disabled=true]) { border-color: #207ab7; cursor: pointer; } .tox .tox-color-input span::before { background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), linear-gradient(-45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%), linear-gradient(-45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%); background-position: 0 0, 0 6px, 6px -6px, -6px 0; background-size: 12px 12px; border: 1px solid #fff; border-radius: 3px; box-sizing: border-box; content: ''; height: 24px; left: -1px; position: absolute; top: -1px; width: 24px; z-index: -1; } .tox .tox-color-input span[aria-disabled=true] { cursor: not-allowed; } .tox:not([dir=rtl]) .tox-color-input { /* stylelint-disable-next-line no-descending-specificity */ } .tox:not([dir=rtl]) .tox-color-input .tox-textfield { padding-left: 36px; } .tox:not([dir=rtl]) .tox-color-input span { left: 6px; } .tox[dir="rtl"] .tox-color-input { /* stylelint-disable-next-line no-descending-specificity */ } .tox[dir="rtl"] .tox-color-input .tox-textfield { padding-right: 36px; } .tox[dir="rtl"] .tox-color-input span { right: 6px; } .tox .tox-label, .tox .tox-toolbar-label { color: rgba(34, 47, 62, 0.7); display: block; font-size: 14px; font-style: normal; font-weight: normal; line-height: 1.3; padding: 0 8px 0 0; text-transform: none; white-space: nowrap; } .tox .tox-toolbar-label { padding: 0 8px; } .tox[dir=rtl] .tox-label { padding: 0 0 0 8px; } .tox .tox-form { display: flex; flex: 1; flex-direction: column; } .tox .tox-form__group { box-sizing: border-box; margin-bottom: 4px; } .tox .tox-form-group--maximize { flex: 1; } .tox .tox-form__group--error { color: #c00; } .tox .tox-form__group--collection { display: flex; } .tox .tox-form__grid { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-between; } .tox .tox-form__grid--2col > .tox-form__group { width: calc(50% - (8px / 2)); } .tox .tox-form__grid--3col > .tox-form__group { width: calc(100% / 3 - (8px / 2)); } .tox .tox-form__grid--4col > .tox-form__group { width: calc(25% - (8px / 2)); } .tox .tox-form__controls-h-stack { align-items: center; display: flex; } .tox .tox-form__group--inline { align-items: center; display: flex; } .tox .tox-form__group--stretched { display: flex; flex: 1; flex-direction: column; } .tox .tox-form__group--stretched .tox-textarea { flex: 1; } .tox .tox-form__group--stretched .tox-navobj { display: flex; flex: 1; } .tox .tox-form__group--stretched .tox-navobj :nth-child(2) { flex: 1; height: 100%; } .tox:not([dir=rtl]) .tox-form__controls-h-stack > *:not(:first-child) { margin-left: 4px; } .tox[dir=rtl] .tox-form__controls-h-stack > *:not(:first-child) { margin-right: 4px; } .tox .tox-lock.tox-locked .tox-lock-icon__unlock, .tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { display: none; } .tox .tox-textfield, .tox .tox-toolbar-textfield, .tox .tox-listboxfield .tox-listbox--select, .tox .tox-textarea, .tox .tox-textarea-wrap .tox-textarea:focus { -webkit-appearance: none; -moz-appearance: none; appearance: none; background-color: #fff; border-color: #cccccc; border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #222f3e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; line-height: 24px; margin: 0; min-height: 34px; outline: none; padding: 5px 4.75px; resize: none; width: 100%; } .tox .tox-textfield[disabled], .tox .tox-textarea[disabled] { background-color: #f2f2f2; color: rgba(34, 47, 62, 0.85); cursor: not-allowed; } .tox .tox-textfield:focus, .tox .tox-dialog__iframe.tox-dialog__iframe--bordered:focus-within, .tox .tox-listboxfield .tox-listbox--select:focus, .tox .tox-textarea-wrap:focus-within, .tox .tox-textarea:focus, .tox .tox-custom-editor:focus-within { background-color: #fff; border-color: #207ab7; box-shadow: none; outline: 2px solid rgba(32, 122, 183, 0.25); } .tox .tox-toolbar-textfield { border-width: 0; margin-bottom: 3px; margin-top: 2px; max-width: 250px; } .tox .tox-naked-btn { background-color: transparent; border: 0; border-color: transparent; box-shadow: unset; color: #207ab7; cursor: pointer; display: block; margin: 0; padding: 0; } .tox .tox-naked-btn svg { display: block; fill: #222f3e; } .tox:not([dir=rtl]) .tox-toolbar-textfield + * { margin-left: 4px; } .tox[dir=rtl] .tox-toolbar-textfield + * { margin-right: 4px; } .tox .tox-listboxfield { cursor: pointer; position: relative; } .tox .tox-listboxfield .tox-listbox--select[disabled] { background-color: #f2f2f2; color: rgba(34, 47, 62, 0.85); cursor: not-allowed; } .tox .tox-listbox__select-label { cursor: default; flex: 1; margin: 0 4px; } .tox .tox-listbox__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; } .tox .tox-listbox__select-chevron svg { fill: #222f3e; } .tox .tox-listboxfield .tox-listbox--select { align-items: center; display: flex; } .tox:not([dir=rtl]) .tox-listboxfield svg { right: 8px; } .tox[dir=rtl] .tox-listboxfield svg { left: 8px; } .tox .tox-selectfield { cursor: pointer; position: relative; } .tox .tox-selectfield select { -webkit-appearance: none; -moz-appearance: none; appearance: none; background-color: #fff; border-color: #cccccc; border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #222f3e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; line-height: 24px; margin: 0; min-height: 34px; outline: none; padding: 5px 4.75px; resize: none; width: 100%; } .tox .tox-selectfield select[disabled] { background-color: #f2f2f2; color: rgba(34, 47, 62, 0.85); cursor: not-allowed; } .tox .tox-selectfield select::-ms-expand { display: none; } .tox .tox-selectfield select:focus { background-color: #fff; border-color: #207ab7; box-shadow: none; outline: 2px solid rgba(32, 122, 183, 0.25); } .tox .tox-selectfield svg { pointer-events: none; position: absolute; top: 50%; transform: translateY(-50%); } .tox:not([dir=rtl]) .tox-selectfield select[size="0"], .tox:not([dir=rtl]) .tox-selectfield select[size="1"] { padding-right: 24px; } .tox:not([dir=rtl]) .tox-selectfield svg { right: 8px; } .tox[dir=rtl] .tox-selectfield select[size="0"], .tox[dir=rtl] .tox-selectfield select[size="1"] { padding-left: 24px; } .tox[dir=rtl] .tox-selectfield svg { left: 8px; } .tox .tox-textarea-wrap { border-color: #cccccc; border-radius: 3px; border-style: solid; border-width: 1px; display: flex; flex: 1; overflow: hidden; } .tox .tox-textarea { -webkit-appearance: textarea; -moz-appearance: textarea; appearance: textarea; white-space: pre-wrap; } .tox .tox-textarea-wrap .tox-textarea { border: none; } .tox .tox-textarea-wrap .tox-textarea:focus { border: none; } .tox-fullscreen { border: 0; height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; padding: 0; touch-action: pinch-zoom; width: 100%; } .tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { display: none; } .tox.tox-tinymce.tox-fullscreen, .tox-shadowhost.tox-fullscreen { left: 0; position: fixed; top: 0; z-index: 1200; } .tox.tox-tinymce.tox-fullscreen { background-color: transparent; } .tox-fullscreen .tox.tox-tinymce-aux, .tox-fullscreen ~ .tox.tox-tinymce-aux { z-index: 1201; } .tox .tox-help__more-link { list-style: none; margin-top: 1em; } .tox .tox-imagepreview { background-color: #666; height: 380px; overflow: hidden; position: relative; width: 100%; } .tox .tox-imagepreview.tox-imagepreview__loaded { overflow: auto; } .tox .tox-imagepreview__container { display: flex; left: 100vw; position: absolute; top: 100vw; } .tox .tox-imagepreview__image { background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); } .tox .tox-image-tools .tox-spacer { flex: 1; } .tox .tox-image-tools .tox-bar { align-items: center; display: flex; height: 60px; justify-content: center; } .tox .tox-image-tools .tox-imagepreview, .tox .tox-image-tools .tox-imagepreview + .tox-bar { margin-top: 8px; } .tox .tox-image-tools .tox-croprect-block { background: black; filter: alpha(opacity=50); opacity: 0.5; position: absolute; zoom: 1; } .tox .tox-image-tools .tox-croprect-handle { border: 2px solid white; height: 20px; left: 0; position: absolute; top: 0; width: 20px; } .tox .tox-image-tools .tox-croprect-handle-move { border: 0; cursor: move; position: absolute; } .tox .tox-image-tools .tox-croprect-handle-nw { border-width: 2px 0 0 2px; cursor: nw-resize; left: 100px; margin: -2px 0 0 -2px; top: 100px; } .tox .tox-image-tools .tox-croprect-handle-ne { border-width: 2px 2px 0 0; cursor: ne-resize; left: 200px; margin: -2px 0 0 -20px; top: 100px; } .tox .tox-image-tools .tox-croprect-handle-sw { border-width: 0 0 2px 2px; cursor: sw-resize; left: 100px; margin: -20px 2px 0 -2px; top: 200px; } .tox .tox-image-tools .tox-croprect-handle-se { border-width: 0 2px 2px 0; cursor: se-resize; left: 200px; margin: -20px 0 0 -20px; top: 200px; } .tox .tox-insert-table-picker { display: flex; flex-wrap: wrap; width: 170px; } .tox .tox-insert-table-picker > div { border-color: #cccccc; border-style: solid; border-width: 0 1px 1px 0; box-sizing: border-box; height: 17px; width: 17px; } .tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { margin: 0 -4px; } .tox .tox-insert-table-picker .tox-insert-table-picker__selected { background-color: rgba(32, 122, 183, 0.5); border-color: rgba(32, 122, 183, 0.5); } .tox .tox-insert-table-picker__label { color: rgba(34, 47, 62, 0.7); display: block; font-size: 14px; padding: 4px; text-align: center; width: 100%; } .tox:not([dir=rtl]) { /* stylelint-disable-next-line no-descending-specificity */ } .tox:not([dir=rtl]) .tox-insert-table-picker > div:nth-child(10n) { border-right: 0; } .tox[dir=rtl] { /* stylelint-disable-next-line no-descending-specificity */ } .tox[dir=rtl] .tox-insert-table-picker > div:nth-child(10n+1) { border-right: 0; } .tox { /* stylelint-disable */ /* stylelint-enable */ } .tox .tox-menu { background-color: #fff; border: 1px solid #cccccc; border-radius: 3px; box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); display: inline-block; overflow: hidden; vertical-align: top; z-index: 1150; } .tox .tox-menu.tox-collection.tox-collection--list { padding: 0 0; } .tox .tox-menu.tox-collection.tox-collection--toolbar { padding: 4px; } .tox .tox-menu.tox-collection.tox-collection--grid { padding: 4px; } @media only screen and (min-width: 768px ) { .tox .tox-menu .tox-collection__item-label { overflow-wrap: break-word; word-break: normal; } } .tox .tox-menu__label h1, .tox .tox-menu__label h2, .tox .tox-menu__label h3, .tox .tox-menu__label h4, .tox .tox-menu__label h5, .tox .tox-menu__label h6, .tox .tox-menu__label p, .tox .tox-menu__label blockquote, .tox .tox-menu__label code { margin: 0; } .tox .tox-menubar { background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0 #fff; background-color: #fff; display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: wrap; grid-column: 1 / -1; grid-row: 1; padding: 0 4px 0 4px; } .tox .tox-promotion + .tox-menubar { grid-column: 1; } .tox .tox-promotion { background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0 #fff; background-color: #fff; grid-column: 2; grid-row: 1; padding-inline-end: 8px; padding-inline-start: 4px; padding-top: 5px; } .tox .tox-promotion-link { align-items: unsafe center; background-color: #E8F1F8; border-radius: 5px; color: #086BE6; cursor: pointer; display: flex; font-size: 14px; height: 26.6px; padding: 4px 8px; white-space: nowrap; } .tox .tox-promotion-link:hover { background-color: #B4D7FF; } .tox .tox-promotion-link:focus { background-color: #D9EDF7; } /* Deprecated. Remove in next major release */ .tox .tox-mbtn { align-items: center; background: transparent; border: 0; border-radius: 3px; box-shadow: none; color: #222f3e; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 34px; justify-content: center; margin: 2px 0 3px 0; outline: none; overflow: hidden; padding: 0 4px; text-transform: none; width: auto; } .tox .tox-mbtn[disabled] { background-color: transparent; border: 0; box-shadow: none; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-mbtn:focus:not(:disabled) { background: #dee0e2; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-mbtn--active { background: #c8cbcf; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { background: #dee0e2; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-mbtn__select-label { cursor: default; font-weight: normal; margin: 0 4px; } .tox .tox-mbtn[disabled] .tox-mbtn__select-label { cursor: not-allowed; } .tox .tox-mbtn__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; display: none; } .tox .tox-notification { border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; display: grid; font-size: 14px; font-weight: normal; grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); margin-top: 4px; opacity: 0; padding: 4px; transition: transform 100ms ease-in, opacity 150ms ease-in; } .tox .tox-notification p { font-size: 14px; font-weight: normal; } .tox .tox-notification a { cursor: pointer; text-decoration: underline; } .tox .tox-notification--in { opacity: 1; } .tox .tox-notification--success { background-color: #e4eeda; border-color: #d7e6c8; color: #222f3e; } .tox .tox-notification--success p { color: #222f3e; } .tox .tox-notification--success a { color: #517342; } .tox .tox-notification--success svg { fill: #222f3e; } .tox .tox-notification--error { background-color: #f5cccc; border-color: #f0b3b3; color: #222f3e; } .tox .tox-notification--error p { color: #222f3e; } .tox .tox-notification--error a { color: #77181f; } .tox .tox-notification--error svg { fill: #222f3e; } .tox .tox-notification--warn, .tox .tox-notification--warning { background-color: #fff5cc; border-color: #fff0b3; color: #222f3e; } .tox .tox-notification--warn p, .tox .tox-notification--warning p { color: #222f3e; } .tox .tox-notification--warn a, .tox .tox-notification--warning a { color: #7a6e25; } .tox .tox-notification--warn svg, .tox .tox-notification--warning svg { fill: #222f3e; } .tox .tox-notification--info { background-color: #d6e7fb; border-color: #c1dbf9; color: #222f3e; } .tox .tox-notification--info p { color: #222f3e; } .tox .tox-notification--info a { color: #2a64a6; } .tox .tox-notification--info svg { fill: #222f3e; } .tox .tox-notification__body { align-self: center; color: #222f3e; font-size: 14px; grid-column-end: 3; grid-column-start: 2; grid-row-end: 2; grid-row-start: 1; text-align: center; white-space: normal; word-break: break-all; word-break: break-word; } .tox .tox-notification__body > * { margin: 0; } .tox .tox-notification__body > * + * { margin-top: 1rem; } .tox .tox-notification__icon { align-self: center; grid-column-end: 2; grid-column-start: 1; grid-row-end: 2; grid-row-start: 1; justify-self: end; } .tox .tox-notification__icon svg { display: block; } .tox .tox-notification__dismiss { align-self: start; grid-column-end: 4; grid-column-start: 3; grid-row-end: 2; grid-row-start: 1; justify-self: end; } .tox .tox-notification .tox-progress-bar { grid-column-end: 4; grid-column-start: 1; grid-row-end: 3; grid-row-start: 2; justify-self: center; } .tox .tox-pop { display: inline-block; position: relative; } .tox .tox-pop--resizing { transition: width 0.1s ease; } .tox .tox-pop--resizing .tox-toolbar, .tox .tox-pop--resizing .tox-toolbar__group { flex-wrap: nowrap; } .tox .tox-pop--transition { transition: 0.15s ease; transition-property: left, right, top, bottom; } .tox .tox-pop--transition::before, .tox .tox-pop--transition::after { transition: all 0.15s, visibility 0s, opacity 0.075s ease 0.075s; } .tox .tox-pop__dialog { background-color: #fff; border: 1px solid #cccccc; border-radius: 3px; box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); min-width: 0; overflow: hidden; } .tox .tox-pop__dialog > *:not(.tox-toolbar) { margin: 4px 4px 4px 8px; } .tox .tox-pop__dialog .tox-toolbar { background-color: transparent; margin-bottom: -1px; } .tox .tox-pop::before, .tox .tox-pop::after { border-style: solid; content: ''; display: block; height: 0; opacity: 1; position: absolute; width: 0; } .tox .tox-pop.tox-pop--inset::before, .tox .tox-pop.tox-pop--inset::after { opacity: 0; transition: all 0s 0.15s, visibility 0s, opacity 0.075s ease; } .tox .tox-pop.tox-pop--bottom::before, .tox .tox-pop.tox-pop--bottom::after { left: 50%; top: 100%; } .tox .tox-pop.tox-pop--bottom::after { border-color: #fff transparent transparent transparent; border-width: 8px; margin-left: -8px; margin-top: -1px; } .tox .tox-pop.tox-pop--bottom::before { border-color: #cccccc transparent transparent transparent; border-width: 9px; margin-left: -9px; } .tox .tox-pop.tox-pop--top::before, .tox .tox-pop.tox-pop--top::after { left: 50%; top: 0; transform: translateY(-100%); } .tox .tox-pop.tox-pop--top::after { border-color: transparent transparent #fff transparent; border-width: 8px; margin-left: -8px; margin-top: 1px; } .tox .tox-pop.tox-pop--top::before { border-color: transparent transparent #cccccc transparent; border-width: 9px; margin-left: -9px; } .tox .tox-pop.tox-pop--left::before, .tox .tox-pop.tox-pop--left::after { left: 0; top: calc(50% - 1px); transform: translateY(-50%); } .tox .tox-pop.tox-pop--left::after { border-color: transparent #fff transparent transparent; border-width: 8px; margin-left: -15px; } .tox .tox-pop.tox-pop--left::before { border-color: transparent #cccccc transparent transparent; border-width: 10px; margin-left: -19px; } .tox .tox-pop.tox-pop--right::before, .tox .tox-pop.tox-pop--right::after { left: 100%; top: calc(50% + 1px); transform: translateY(-50%); } .tox .tox-pop.tox-pop--right::after { border-color: transparent transparent transparent #fff; border-width: 8px; margin-left: -1px; } .tox .tox-pop.tox-pop--right::before { border-color: transparent transparent transparent #cccccc; border-width: 10px; margin-left: -1px; } .tox .tox-pop.tox-pop--align-left::before, .tox .tox-pop.tox-pop--align-left::after { left: 20px; } .tox .tox-pop.tox-pop--align-right::before, .tox .tox-pop.tox-pop--align-right::after { left: calc(100% - 20px); } .tox .tox-sidebar-wrap { display: flex; flex-direction: row; flex-grow: 1; min-height: 0; } .tox .tox-sidebar { background-color: #fff; display: flex; flex-direction: row; justify-content: flex-end; } .tox .tox-sidebar__slider { display: flex; overflow: hidden; } .tox .tox-sidebar__pane-container { display: flex; } .tox .tox-sidebar__pane { display: flex; } .tox .tox-sidebar--sliding-closed { opacity: 0; } .tox .tox-sidebar--sliding-open { opacity: 1; } .tox .tox-sidebar--sliding-growing, .tox .tox-sidebar--sliding-shrinking { transition: width 0.5s ease, opacity 0.5s ease; } .tox .tox-selector { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; display: inline-block; height: 10px; position: absolute; width: 10px; } .tox.tox-platform-touch .tox-selector { height: 12px; width: 12px; } .tox .tox-slider { align-items: center; display: flex; flex: 1; height: 24px; justify-content: center; position: relative; } .tox .tox-slider__rail { background-color: transparent; border: 1px solid #cccccc; border-radius: 3px; height: 10px; min-width: 120px; width: 100%; } .tox .tox-slider__handle { background-color: #207ab7; border: 2px solid #185d8c; border-radius: 3px; box-shadow: none; height: 24px; left: 50%; position: absolute; top: 50%; transform: translateX(-50%) translateY(-50%); width: 14px; } .tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { margin-inline-start: 8px; } .tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { margin-inline-start: 32px; } .tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { margin-inline-start: 32px; } .tox .tox-source-code { overflow: auto; } .tox .tox-spinner { display: flex; } .tox .tox-spinner > div { animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; background-color: rgba(34, 47, 62, 0.7); border-radius: 100%; height: 8px; width: 8px; } .tox .tox-spinner > div:nth-child(1) { animation-delay: -0.32s; } .tox .tox-spinner > div:nth-child(2) { animation-delay: -0.16s; } @keyframes tam-bouncing-dots { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } } .tox:not([dir=rtl]) .tox-spinner > div:not(:first-child) { margin-left: 4px; } .tox[dir=rtl] .tox-spinner > div:not(:first-child) { margin-right: 4px; } .tox .tox-statusbar { align-items: center; background-color: #fff; border-top: 1px solid #cccccc; color: rgba(34, 47, 62, 0.7); display: flex; flex: 0 0 auto; font-size: 12px; font-weight: normal; height: 18px; overflow: hidden; padding: 0 8px; position: relative; text-transform: uppercase; } .tox .tox-statusbar__text-container { display: flex; flex: 1 1 auto; justify-content: flex-end; overflow: hidden; } .tox .tox-statusbar__path { display: flex; flex: 1 1 auto; margin-right: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-statusbar__path > * { display: inline; white-space: nowrap; } .tox .tox-statusbar__wordcount { flex: 0 0 auto; margin-left: 1ch; } .tox .tox-statusbar a, .tox .tox-statusbar__path-item, .tox .tox-statusbar__wordcount { color: rgba(34, 47, 62, 0.7); text-decoration: none; } .tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]) { color: #222f3e; cursor: pointer; } .tox .tox-statusbar__branding svg { fill: rgba(34, 47, 62, 0.8); height: 1.14em; vertical-align: -0.28em; width: 3.6em; } .tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg, .tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg { fill: #222f3e; } .tox .tox-statusbar__resize-handle { align-items: flex-end; align-self: stretch; cursor: nwse-resize; display: flex; flex: 0 0 auto; justify-content: flex-end; margin-left: auto; margin-right: -8px; padding-bottom: 3px; padding-left: 1ch; padding-right: 3px; } .tox .tox-statusbar__resize-handle svg { display: block; fill: rgba(34, 47, 62, 0.5); } .tox .tox-statusbar__resize-handle:focus svg { background-color: #dee0e2; border-radius: 1px 1px -4px 1px; box-shadow: 0 0 0 2px #dee0e2; } .tox:not([dir=rtl]) .tox-statusbar__path > * { margin-right: 4px; } .tox:not([dir=rtl]) .tox-statusbar__branding { margin-left: 2ch; } .tox[dir=rtl] .tox-statusbar { flex-direction: row-reverse; } .tox[dir=rtl] .tox-statusbar__path > * { margin-left: 4px; } .tox .tox-throbber { z-index: 1299; } .tox .tox-throbber__busy-spinner { align-items: center; background-color: rgba(255, 255, 255, 0.6); bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; } .tox .tox-tbtn { align-items: center; background: transparent; border: 0; border-radius: 3px; box-shadow: none; color: #222f3e; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 34px; justify-content: center; margin: 3px 0 2px 0; outline: none; overflow: hidden; padding: 0; text-transform: none; width: 34px; } .tox .tox-tbtn svg { display: block; fill: #222f3e; } .tox .tox-tbtn.tox-tbtn-more { padding-left: 5px; padding-right: 5px; width: inherit; } .tox .tox-tbtn:focus { background: #dee0e2; border: 0; box-shadow: none; } .tox .tox-tbtn:hover { background: #dee0e2; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tbtn:hover svg { fill: #222f3e; } .tox .tox-tbtn:active { background: #c8cbcf; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tbtn:active svg { fill: #222f3e; } .tox .tox-tbtn--disabled .tox-tbtn--enabled svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-tbtn--disabled, .tox .tox-tbtn--disabled:hover, .tox .tox-tbtn:disabled, .tox .tox-tbtn:disabled:hover { background: transparent; border: 0; box-shadow: none; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-tbtn--disabled svg, .tox .tox-tbtn--disabled:hover svg, .tox .tox-tbtn:disabled svg, .tox .tox-tbtn:disabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: rgba(34, 47, 62, 0.5); } .tox .tox-tbtn--enabled, .tox .tox-tbtn--enabled:hover { background: #c8cbcf; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tbtn--enabled > *, .tox .tox-tbtn--enabled:hover > * { transform: none; } .tox .tox-tbtn--enabled svg, .tox .tox-tbtn--enabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: #222f3e; } .tox .tox-tbtn--enabled.tox-tbtn--disabled svg, .tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { color: #222f3e; } .tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { fill: #222f3e; } .tox .tox-tbtn:active > * { transform: none; } .tox .tox-tbtn--md { height: 51px; width: 51px; } .tox .tox-tbtn--lg { flex-direction: column; height: 68px; width: 68px; } .tox .tox-tbtn--return { align-self: stretch; height: unset; width: 16px; } .tox .tox-tbtn--labeled { padding: 0 4px; width: unset; } .tox .tox-tbtn__vlabel { display: block; font-size: 10px; font-weight: normal; letter-spacing: -0.025em; margin-bottom: 4px; white-space: nowrap; } .tox .tox-number-input { border-radius: 3px; display: flex; margin: 3px 0 2px 0; padding: 0 4px; width: auto; } .tox .tox-number-input .tox-input-wrapper { background: transparent; display: flex; pointer-events: none; text-align: center; } .tox .tox-number-input .tox-input-wrapper:focus { background: #dee0e2; } .tox .tox-number-input input { border-radius: 3px; color: #222f3e; font-size: 14px; margin: 2px 0; pointer-events: all; width: 60px; } .tox .tox-number-input input:hover { background: #dee0e2; color: #222f3e; } .tox .tox-number-input input:focus { background: #fff; color: #222f3e; } .tox .tox-number-input input:disabled { background: transparent; border: 0; box-shadow: none; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-number-input button { background: transparent; color: #222f3e; height: 34px; text-align: center; width: 24px; } .tox .tox-number-input button svg { display: block; fill: #222f3e; margin: 0 auto; transform: scale(0.67); } .tox .tox-number-input button:focus { background: #dee0e2; } .tox .tox-number-input button:hover { background: #dee0e2; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-number-input button:hover svg { fill: #222f3e; } .tox .tox-number-input button:active { background: #c8cbcf; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-number-input button:active svg { fill: #222f3e; } .tox .tox-number-input button:disabled { background: transparent; border: 0; box-shadow: none; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-number-input button:disabled svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-number-input button.minus { border-radius: 3px 0 0 3px; } .tox .tox-number-input button.plus { border-radius: 0 3px 3px 0; } .tox .tox-number-input:focus:not(:active) > button, .tox .tox-number-input:focus:not(:active) > .tox-input-wrapper { background: #dee0e2; } .tox .tox-tbtn--select { margin: 3px 0 2px 0; padding: 0 4px; width: auto; } .tox .tox-tbtn__select-label { cursor: default; font-weight: normal; height: initial; margin: 0 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-tbtn__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; } .tox .tox-tbtn__select-chevron svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-tbtn--bespoke { background: transparent; } .tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { margin-inline-start: 0; } .tox .tox-tbtn--bespoke .tox-tbtn__select-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 7em; } .tox .tox-tbtn--disabled .tox-tbtn__select-label, .tox .tox-tbtn--select:disabled .tox-tbtn__select-label { cursor: not-allowed; } .tox .tox-split-button { border: 0; border-radius: 3px; box-sizing: border-box; display: flex; margin: 3px 0 2px 0; overflow: hidden; } .tox .tox-split-button:hover { box-shadow: 0 0 0 1px #dee0e2 inset; } .tox .tox-split-button:focus { background: #dee0e2; box-shadow: none; color: #222f3e; } .tox .tox-split-button > * { border-radius: 0; } .tox .tox-split-button__chevron { width: 16px; } .tox .tox-split-button__chevron svg { fill: rgba(34, 47, 62, 0.5); } .tox .tox-split-button .tox-tbtn { margin: 0; } .tox .tox-split-button.tox-tbtn--disabled:hover, .tox .tox-split-button.tox-tbtn--disabled:focus, .tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, .tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus { background: transparent; box-shadow: none; color: rgba(34, 47, 62, 0.5); } .tox.tox-platform-touch .tox-split-button .tox-tbtn--select { padding: 0 0px; } .tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { width: 30px; } .tox.tox-platform-touch .tox-split-button__chevron { width: 20px; } .tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color, .tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color { opacity: 0.6; } .tox .tox-toolbar-overlord { background-color: #fff; } .tox .tox-toolbar, .tox .tox-toolbar__primary, .tox .tox-toolbar__overflow { background-attachment: local; background-color: #fff; background-image: repeating-linear-gradient(#cccccc 0px 1px, transparent 1px 39px); background-position: center top 39px; background-repeat: no-repeat; background-size: calc(100% - 4px * 2) calc(100% - 39px); display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: wrap; padding: 0 0px; transform: perspective(1px); } .tox .tox-toolbar-overlord > .tox-toolbar, .tox .tox-toolbar-overlord > .tox-toolbar__primary, .tox .tox-toolbar-overlord > .tox-toolbar__overflow { background-position: center top 0px; background-size: calc(100% - 4px * 2) calc(100% - 0px); } .tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { height: 0; opacity: 0; padding-bottom: 0; padding-top: 0; visibility: hidden; } .tox .tox-toolbar__overflow--growing { transition: height 0.3s ease, opacity 0.2s linear 0.1s; } .tox .tox-toolbar__overflow--shrinking { transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; } .tox .tox-toolbar-overlord, .tox .tox-anchorbar { grid-column: 1 / -1; } .tox .tox-menubar + .tox-toolbar, .tox .tox-menubar + .tox-toolbar-overlord { border-top: 1px solid #cccccc; margin-top: -1px; padding-bottom: 0px; padding-top: 0px; } .tox .tox-toolbar--scrolling { flex-wrap: nowrap; overflow-x: auto; } .tox .tox-pop .tox-toolbar { border-width: 0; } .tox .tox-toolbar--no-divider { background-image: none; } .tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, .tox .tox-toolbar-overlord .tox-toolbar__primary { background-position: center top 39px; } .tox .tox-editor-header > .tox-toolbar--scrolling, .tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { background-image: none; } .tox.tox-tinymce-aux .tox-toolbar__overflow { background-color: #fff; background-position: center top 43px; background-size: calc(100% - 8px * 2) calc(100% - 51px); border: none; border-radius: 3px; box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); overscroll-behavior: none; padding: 4px 0; } .tox-pop .tox-pop__dialog { /* stylelint-disable-next-line no-descending-specificity */ } .tox-pop .tox-pop__dialog .tox-toolbar { background-position: center top 43px; background-size: calc(100% - 4px * 2) calc(100% - 51px); padding: 4px 0; } .tox .tox-toolbar__group { align-items: center; display: flex; flex-wrap: wrap; margin: 0 0; padding: 0 4px 0 4px; } .tox .tox-toolbar__group--pull-right { margin-left: auto; } .tox .tox-toolbar--scrolling .tox-toolbar__group { flex-shrink: 0; flex-wrap: nowrap; } .tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type) { border-right: 1px solid #cccccc; } .tox[dir=rtl] .tox-toolbar__group:not(:last-of-type) { border-left: 1px solid #cccccc; } .tox .tox-tooltip { display: inline-block; padding: 8px; position: relative; } .tox .tox-tooltip__body { background-color: #222f3e; border-radius: 3px; box-shadow: 0 2px 4px rgba(34, 47, 62, 0.3); color: rgba(255, 255, 255, 0.75); font-size: 14px; font-style: normal; font-weight: normal; padding: 4px 8px; text-transform: none; } .tox .tox-tooltip__arrow { position: absolute; } .tox .tox-tooltip--down .tox-tooltip__arrow { border-left: 8px solid transparent; border-right: 8px solid transparent; border-top: 8px solid #222f3e; bottom: 0; left: 50%; position: absolute; transform: translateX(-50%); } .tox .tox-tooltip--up .tox-tooltip__arrow { border-bottom: 8px solid #222f3e; border-left: 8px solid transparent; border-right: 8px solid transparent; left: 50%; position: absolute; top: 0; transform: translateX(-50%); } .tox .tox-tooltip--right .tox-tooltip__arrow { border-bottom: 8px solid transparent; border-left: 8px solid #222f3e; border-top: 8px solid transparent; position: absolute; right: 0; top: 50%; transform: translateY(-50%); } .tox .tox-tooltip--left .tox-tooltip__arrow { border-bottom: 8px solid transparent; border-right: 8px solid #222f3e; border-top: 8px solid transparent; left: 0; position: absolute; top: 50%; transform: translateY(-50%); } .tox .tox-tree { display: flex; flex-direction: column; } .tox .tox-tree .tox-trbtn { align-items: center; background: transparent; border: 0; border-radius: 4px; box-shadow: none; color: #222f3e; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 28px; margin-bottom: 4px; margin-top: 4px; outline: none; overflow: hidden; padding: 0; padding-left: 8px; text-transform: none; } .tox .tox-tree .tox-trbtn .tox-tree__label { cursor: default; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-tree .tox-trbtn svg { display: block; fill: #222f3e; } .tox .tox-tree .tox-trbtn:focus { background: #dee0e2; border: 0; box-shadow: none; } .tox .tox-tree .tox-trbtn:hover { background: #dee0e2; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tree .tox-trbtn:hover svg { fill: #222f3e; } .tox .tox-tree .tox-trbtn:active { background: #b1d0e6; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tree .tox-trbtn:active svg { fill: #222f3e; } .tox .tox-tree .tox-trbtn--disabled, .tox .tox-tree .tox-trbtn--disabled:hover, .tox .tox-tree .tox-trbtn:disabled, .tox .tox-tree .tox-trbtn:disabled:hover { background: transparent; border: 0; box-shadow: none; color: rgba(34, 47, 62, 0.5); cursor: not-allowed; } .tox .tox-tree .tox-trbtn--disabled svg, .tox .tox-tree .tox-trbtn--disabled:hover svg, .tox .tox-tree .tox-trbtn:disabled svg, .tox .tox-tree .tox-trbtn:disabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: rgba(34, 47, 62, 0.5); } .tox .tox-tree .tox-trbtn--enabled, .tox .tox-tree .tox-trbtn--enabled:hover { background: #b1d0e6; border: 0; box-shadow: none; color: #222f3e; } .tox .tox-tree .tox-trbtn--enabled > *, .tox .tox-tree .tox-trbtn--enabled:hover > * { transform: none; } .tox .tox-tree .tox-trbtn--enabled svg, .tox .tox-tree .tox-trbtn--enabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: #222f3e; } .tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) { color: #222f3e; } .tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg { fill: #222f3e; } .tox .tox-tree .tox-trbtn:active > * { transform: none; } .tox .tox-tree .tox-trbtn--return { align-self: stretch; height: unset; width: 16px; } .tox .tox-tree .tox-trbtn--labeled { padding: 0 4px; width: unset; } .tox .tox-tree .tox-trbtn__vlabel { display: block; font-size: 10px; font-weight: normal; letter-spacing: -0.025em; margin-bottom: 4px; white-space: nowrap; } .tox .tox-tree .tox-tree--directory { display: flex; flex-direction: column; /* stylelint-disable no-descending-specificity */ } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label { font-weight: bold; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn { margin-left: auto; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg { fill: transparent; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg { fill: #222f3e; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg { fill: #222f3e; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) { background-color: transparent; color: #222f3e; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg { fill: #222f3e; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron { margin-right: 6px; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--growing) .tox-chevron, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--shrinking) .tox-chevron { transition: transform 0.5s ease-in-out; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--growing) .tox-chevron, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--open) .tox-chevron { transform: rotate(90deg); } .tox .tox-tree .tox-tree--leaf__label { font-weight: normal; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn { margin-left: auto; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg { fill: transparent; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg, .tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg { fill: #222f3e; } .tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg { fill: #222f3e; } .tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) { background-color: transparent; color: #222f3e; } .tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg { fill: #222f3e; } .tox .tox-tree .tox-tree--directory__children { overflow: hidden; padding-left: 16px; } .tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing, .tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking { transition: height 0.5s ease-in-out; } .tox .tox-tree .tox-trbtn.tox-tree--leaf__label { display: flex; justify-content: space-between; } .tox .tox-view-wrap, .tox .tox-view-wrap__slot-container { background-color: #fff; display: flex; flex: 1; flex-direction: column; } .tox .tox-view { display: flex; flex: 1 1 auto; flex-direction: column; overflow: hidden; } .tox .tox-view__header { align-items: center; display: flex; font-size: 16px; justify-content: space-between; padding: 8px 8px 0 8px; position: relative; } .tox .tox-view--mobile.tox-view__header, .tox .tox-view--mobile.tox-view__toolbar { padding: 8px; } .tox .tox-view--scrolling { flex-wrap: nowrap; overflow-x: auto; } .tox .tox-view__toolbar { display: flex; flex-direction: row; gap: 8px; justify-content: space-between; padding: 8px 8px 0 8px; } .tox .tox-view__toolbar__group { display: flex; flex-direction: row; gap: 12px; } .tox .tox-view__header-start, .tox .tox-view__header-end { display: flex; } .tox .tox-view__pane { height: 100%; padding: 8px; width: 100%; } .tox .tox-view__pane_panel { border: 1px solid #cccccc; border-radius: 3px; } .tox:not([dir=rtl]) .tox-view__header .tox-view__header-start > *, .tox:not([dir=rtl]) .tox-view__header .tox-view__header-end > * { margin-left: 8px; } .tox[dir=rtl] .tox-view__header .tox-view__header-start > *, .tox[dir=rtl] .tox-view__header .tox-view__header-end > * { margin-right: 8px; } .tox .tox-well { border: 1px solid #cccccc; border-radius: 3px; padding: 8px; width: 100%; } .tox .tox-well > *:first-child { margin-top: 0; } .tox .tox-well > *:last-child { margin-bottom: 0; } .tox .tox-well > *:only-child { margin: 0; } .tox .tox-custom-editor { border: 1px solid #cccccc; border-radius: 3px; display: flex; flex: 1; overflow: hidden; position: relative; } /* stylelint-disable */ .tox { /* stylelint-enable */ } .tox .tox-dialog-loading::before { background-color: rgba(0, 0, 0, 0.5); content: ""; height: 100%; position: absolute; width: 100%; z-index: 1000; } .tox .tox-tab { cursor: pointer; } .tox .tox-dialog__content-js { display: flex; flex: 1; } .tox .tox-dialog__body-content .tox-collection { display: flex; flex: 1; } .tox:not(.tox-tinymce-inline) .tox-editor-header { background-color: none; padding: 0; } .tox.tox-tinymce--toolbar-bottom .tox-editor-header, .tox.tox-tinymce-inline .tox-editor-header { margin-bottom: -1px; } .tox.tox-tinymce-inline .tox-editor-container { overflow: hidden; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { border-top: none; box-shadow: none; } .tox.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header { background-color: transparent; box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); padding: 0; } .tox.tox.tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); } .tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { margin: -4px 0; } .tox .tox-menu.tox-collection.tox-collection--list { padding: 0; } .tox .tox-pop { box-shadow: none; } .tox .tox-tbtn, .tox .tox-number-input, .tox .tox-tbtn--select, .tox .tox-split-button { margin: 2px 0 3px 0; } .tox .tox-toolbar, .tox .tox-toolbar__primary, .tox .tox-toolbar__overflow { background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0px #fff !important; } .tox .tox-menubar + .tox-toolbar-overlord { border-top: none; } .tox .tox-menubar + .tox-toolbar, .tox .tox-menubar + .tox-toolbar-overlord .tox-toolbar__primary { border-top: 1px solid #cccccc; margin-top: -1px; } .tox.tox-tinymce-aux .tox-toolbar__overflow { border: 1px solid #cccccc; padding: 0; } .tox .tox-pop .tox-pop__dialog .tox-toolbar { padding: 0; } .tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { border-top: 1px solid #cccccc; } .tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar-overlord:first-child .tox-toolbar__primary, .tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child { border-top: 1px solid #cccccc; } .tox .tox-toolbar__group { padding: 0 4px 0 4px; } .tox .tox-collection__item { border-radius: 0; cursor: pointer; } .tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]) { color: rgba(34, 47, 62, 0.7); text-decoration: underline; } .tox .tox-statusbar__branding svg { vertical-align: -0.25em; } .tox:not([dir=rtl]) .tox-statusbar__branding { margin-left: 1ch; } .tox .tox-statusbar__resize-handle { padding-bottom: 0; padding-right: 0; } .tox .tox-button::before { display: none; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.css ================================================ body.tox-dialog__disable-scroll { overflow: hidden; } .tox-fullscreen { border: 0; height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; padding: 0; touch-action: pinch-zoom; width: 100%; } .tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { display: none; } .tox.tox-tinymce.tox-fullscreen, .tox-shadowhost.tox-fullscreen { left: 0; position: fixed; top: 0; z-index: 1200; } .tox.tox-tinymce.tox-fullscreen { background-color: transparent; } .tox-fullscreen .tox.tox-tinymce-aux, .tox-fullscreen ~ .tox.tox-tinymce-aux { z-index: 1201; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/tinymce-5-dark/content.css ================================================ .mce-content-body .mce-item-anchor { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; } .mce-content-body .mce-item-anchor:empty { cursor: default; display: inline-block; height: 12px !important; padding: 0 2px; -webkit-user-modify: read-only; -moz-user-modify: read-only; -webkit-user-select: all; -moz-user-select: all; user-select: all; width: 8px !important; } .mce-content-body .mce-item-anchor:not(:empty) { background-position-x: 2px; display: inline-block; padding-left: 12px; } .mce-content-body .mce-item-anchor[data-mce-selected] { outline-offset: 1px; } .tox-comments-visible .tox-comment[contenteditable="false"]:not([data-mce-selected]), .tox-comments-visible span.tox-comment img:not([data-mce-selected]), .tox-comments-visible span.tox-comment > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #ffe89d; } .tox-comments-visible .tox-comment[contenteditable="false"][data-mce-annotation-active="true"]:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] img:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment:not([data-mce-selected]) { background-color: #ffe89d; outline: none; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"]:not([data-mce-selected="inline-boundary"]) { background-color: #fed635; } .tox-checklist > li:not(.tox-checklist--hidden) { list-style: none; margin: 0.25em 0; } .tox-checklist > li:not(.tox-checklist--hidden)::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); cursor: pointer; height: 1em; margin-left: -1.5em; margin-top: 0.125em; position: absolute; width: 1em; } .tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); } [dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { margin-left: 0; margin-right: -1.5em; } /* stylelint-disable */ /* http://prismjs.com/ */ /** * Dracula Theme originally by Zeno Rocha [@zenorocha] * https://draculatheme.com/ * * Ported for PrismJS by Albert Vallverdu [@byverdu] */ code[class*="language-"], pre[class*="language-"] { color: #f8f8f2; background: none; text-shadow: 0 1px rgba(0, 0, 0, 0.3); font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.5; -moz-tab-size: 4; tab-size: 4; -webkit-hyphens: none; hyphens: none; } /* Code blocks */ pre[class*="language-"] { padding: 1em; margin: 0.5em 0; overflow: auto; border-radius: 0.3em; } :not(pre) > code[class*="language-"], pre[class*="language-"] { background: #282a36; } /* Inline code */ :not(pre) > code[class*="language-"] { padding: 0.1em; border-radius: 0.3em; white-space: normal; } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: #6272a4; } .token.punctuation { color: #f8f8f2; } .namespace { opacity: 0.7; } .token.property, .token.tag, .token.constant, .token.symbol, .token.deleted { color: #ff79c6; } .token.boolean, .token.number { color: #bd93f9; } .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #50fa7b; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string, .token.variable { color: #f8f8f2; } .token.atrule, .token.attr-value, .token.function, .token.class-name { color: #f1fa8c; } .token.keyword { color: #8be9fd; } .token.regex, .token.important { color: #ffb86c; } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } /* stylelint-enable */ .mce-content-body { overflow-wrap: break-word; word-wrap: break-word; } .mce-content-body .mce-visual-caret { background-color: black; background-color: currentColor; position: absolute; } .mce-content-body .mce-visual-caret-hidden { display: none; } .mce-content-body *[data-mce-caret] { left: -1000px; margin: 0; padding: 0; position: absolute; right: auto; top: 0; } .mce-content-body .mce-offscreen-selection { left: -2000000px; max-width: 1000000px; position: absolute; } .mce-content-body *[contentEditable=false] { cursor: default; } .mce-content-body *[contentEditable=true] { cursor: text; } .tox-cursor-format-painter { cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; } div.mce-footnotes hr { margin-inline-end: auto; margin-inline-start: 0; width: 25%; } div.mce-footnotes li > a.mce-footnotes-backlink { text-decoration: none; } @media print { sup.mce-footnote a { color: black; text-decoration: none; } div.mce-footnotes { break-inside: avoid; width: 100%; } div.mce-footnotes li > a.mce-footnotes-backlink { display: none; } } .mce-content-body figure.align-left { float: left; } .mce-content-body figure.align-right { float: right; } .mce-content-body figure.image.align-center { display: table; margin-left: auto; margin-right: auto; } .mce-preview-object { border: 1px solid gray; display: inline-block; line-height: 0; margin: 0 2px 0 2px; position: relative; } .mce-preview-object .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-preview-object[data-mce-selected="2"] .mce-shim { display: none; } .mce-content-body .mce-mergetag { cursor: default !important; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body .mce-mergetag:hover { background-color: rgba(0, 108, 231, 0.3); } .mce-content-body .mce-mergetag-affix { background-color: rgba(0, 108, 231, 0.3); color: #006ce7; } .mce-object { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; border: 1px dashed #aaa; } .mce-pagebreak { border: 1px dashed #aaa; cursor: default; display: block; height: 5px; margin-top: 15px; page-break-before: always; width: 100%; } @media print { .mce-pagebreak { border: 0; } } .tiny-pageembed .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tiny-pageembed[data-mce-selected="2"] .mce-shim { display: none; } .tiny-pageembed { display: inline-block; position: relative; } .tiny-pageembed--21by9, .tiny-pageembed--16by9, .tiny-pageembed--4by3, .tiny-pageembed--1by1 { display: block; overflow: hidden; padding: 0; position: relative; width: 100%; } .tiny-pageembed--21by9 { padding-top: 42.857143%; } .tiny-pageembed--16by9 { padding-top: 56.25%; } .tiny-pageembed--4by3 { padding-top: 75%; } .tiny-pageembed--1by1 { padding-top: 100%; } .tiny-pageembed--21by9 iframe, .tiny-pageembed--16by9 iframe, .tiny-pageembed--4by3 iframe, .tiny-pageembed--1by1 iframe { border: 0; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-content-body[data-mce-placeholder] { position: relative; } .mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { color: rgba(34, 47, 62, 0.7); content: attr(data-mce-placeholder); position: absolute; } .mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { left: 1px; } .mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { right: 1px; } .mce-content-body div.mce-resizehandle { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; height: 10px; position: absolute; width: 10px; z-index: 1298; } .mce-content-body div.mce-resizehandle:hover { background-color: #4099ff; } .mce-content-body div.mce-resizehandle:nth-of-type(1) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(2) { cursor: nesw-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(3) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(4) { cursor: nesw-resize; } .mce-content-body .mce-resize-backdrop { z-index: 10000; } .mce-content-body .mce-clonedresizable { cursor: default; opacity: 0.5; outline: 1px dashed black; position: absolute; z-index: 10001; } .mce-content-body .mce-clonedresizable.mce-resizetable-columns th, .mce-content-body .mce-clonedresizable.mce-resizetable-columns td { border: 0; } .mce-content-body .mce-resize-helper { background: #555; background: rgba(0, 0, 0, 0.75); border: 1px; border-radius: 3px; color: white; display: none; font-family: sans-serif; font-size: 12px; line-height: 14px; margin: 5px 10px; padding: 5px; position: absolute; white-space: nowrap; z-index: 10002; } .tox-rtc-user-selection { position: relative; } .tox-rtc-user-cursor { bottom: 0; cursor: default; position: absolute; top: 0; width: 2px; } .tox-rtc-user-cursor::before { background-color: inherit; border-radius: 50%; content: ''; display: block; height: 8px; position: absolute; right: -3px; top: -3px; width: 8px; } .tox-rtc-user-cursor:hover::after { background-color: inherit; border-radius: 100px; box-sizing: border-box; color: #fff; content: attr(data-user); display: block; font-size: 12px; font-weight: bold; left: -5px; min-height: 8px; min-width: 8px; padding: 0 12px; position: absolute; top: -11px; white-space: nowrap; z-index: 1000; } .tox-rtc-user-selection--1 .tox-rtc-user-cursor { background-color: #2dc26b; } .tox-rtc-user-selection--2 .tox-rtc-user-cursor { background-color: #e03e2d; } .tox-rtc-user-selection--3 .tox-rtc-user-cursor { background-color: #f1c40f; } .tox-rtc-user-selection--4 .tox-rtc-user-cursor { background-color: #3598db; } .tox-rtc-user-selection--5 .tox-rtc-user-cursor { background-color: #b96ad9; } .tox-rtc-user-selection--6 .tox-rtc-user-cursor { background-color: #e67e23; } .tox-rtc-user-selection--7 .tox-rtc-user-cursor { background-color: #aaa69d; } .tox-rtc-user-selection--8 .tox-rtc-user-cursor { background-color: #f368e0; } .tox-rtc-remote-image { background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; border: 1px solid #ccc; min-height: 240px; min-width: 320px; } .mce-match-marker { background: #aaa; color: #fff; } .mce-match-marker-selected { background: #39f; color: #fff; } .mce-match-marker-selected::-moz-selection { background: #39f; color: #fff; } .mce-match-marker-selected::selection { background: #39f; color: #fff; } .mce-content-body img[data-mce-selected], .mce-content-body video[data-mce-selected], .mce-content-body audio[data-mce-selected], .mce-content-body object[data-mce-selected], .mce-content-body embed[data-mce-selected], .mce-content-body table[data-mce-selected], .mce-content-body details[data-mce-selected] { outline: 3px solid #4099ff; } .mce-content-body hr[data-mce-selected] { outline: 3px solid #4099ff; outline-offset: 1px; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { outline: 3px solid #4099ff; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { outline: 3px solid #4099ff; } .mce-content-body *[contentEditable=false][data-mce-selected] { cursor: not-allowed; outline: 3px solid #4099ff; } .mce-content-body.mce-content-readonly *[contentEditable=true]:focus, .mce-content-body.mce-content-readonly *[contentEditable=true]:hover { outline: none; } .mce-content-body *[data-mce-selected="inline-boundary"] { background-color: #4099ff; } .mce-content-body .mce-edit-focus { outline: 3px solid #4099ff; } .mce-content-body td[data-mce-selected], .mce-content-body th[data-mce-selected] { position: relative; } .mce-content-body td[data-mce-selected]::-moz-selection, .mce-content-body th[data-mce-selected]::-moz-selection { background: none; } .mce-content-body td[data-mce-selected]::selection, .mce-content-body th[data-mce-selected]::selection { background: none; } .mce-content-body td[data-mce-selected] *, .mce-content-body th[data-mce-selected] * { outline: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { background-color: rgba(180, 215, 255, 0.7); border: 1px solid transparent; bottom: -1px; content: ''; left: -1px; mix-blend-mode: lighten; position: absolute; right: -1px; top: -1px; } @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { border-color: rgba(0, 84, 180, 0.7); } } .mce-content-body img[data-mce-selected]::-moz-selection { background: none; } .mce-content-body img[data-mce-selected]::selection { background: none; } .ephox-snooker-resizer-bar { background-color: #4099ff; opacity: 0; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .ephox-snooker-resizer-cols { cursor: col-resize; } .ephox-snooker-resizer-rows { cursor: row-resize; } .ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { opacity: 1; } .mce-spellchecker-word { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; height: 2rem; } .mce-spellchecker-grammar { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; } .mce-toc { border: 1px solid gray; } .mce-toc h2 { margin: 4px; } .mce-toc li { list-style-type: none; } [data-mce-block] { display: block; } table[style*="border-width: 0px"], .mce-item-table:not([border]), .mce-item-table[border="0"], table[style*="border-width: 0px"] td, .mce-item-table:not([border]) td, .mce-item-table[border="0"] td, table[style*="border-width: 0px"] th, .mce-item-table:not([border]) th, .mce-item-table[border="0"] th, table[style*="border-width: 0px"] caption, .mce-item-table:not([border]) caption, .mce-item-table[border="0"] caption { border: 1px dashed #bbb; } .mce-visualblocks p, .mce-visualblocks h1, .mce-visualblocks h2, .mce-visualblocks h3, .mce-visualblocks h4, .mce-visualblocks h5, .mce-visualblocks h6, .mce-visualblocks div:not([data-mce-bogus]), .mce-visualblocks section, .mce-visualblocks article, .mce-visualblocks blockquote, .mce-visualblocks address, .mce-visualblocks pre, .mce-visualblocks figure, .mce-visualblocks figcaption, .mce-visualblocks hgroup, .mce-visualblocks aside, .mce-visualblocks ul, .mce-visualblocks ol, .mce-visualblocks dl { background-repeat: no-repeat; border: 1px dashed #bbb; margin-left: 3px; padding-top: 10px; } .mce-visualblocks p { background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); } .mce-visualblocks h1 { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); } .mce-visualblocks h2 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); } .mce-visualblocks h3 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); } .mce-visualblocks h4 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); } .mce-visualblocks h5 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); } .mce-visualblocks h6 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); } .mce-visualblocks div:not([data-mce-bogus]) { background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); } .mce-visualblocks section { background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); } .mce-visualblocks article { background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); } .mce-visualblocks blockquote { background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); } .mce-visualblocks address { background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); } .mce-visualblocks pre { background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); } .mce-visualblocks figure { background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); } .mce-visualblocks figcaption { border: 1px dashed #bbb; } .mce-visualblocks hgroup { background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); } .mce-visualblocks aside { background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); } .mce-visualblocks ul { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); } .mce-visualblocks ol { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); } .mce-visualblocks dl { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); } .mce-visualblocks:not([dir=rtl]) p, .mce-visualblocks:not([dir=rtl]) h1, .mce-visualblocks:not([dir=rtl]) h2, .mce-visualblocks:not([dir=rtl]) h3, .mce-visualblocks:not([dir=rtl]) h4, .mce-visualblocks:not([dir=rtl]) h5, .mce-visualblocks:not([dir=rtl]) h6, .mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), .mce-visualblocks:not([dir=rtl]) section, .mce-visualblocks:not([dir=rtl]) article, .mce-visualblocks:not([dir=rtl]) blockquote, .mce-visualblocks:not([dir=rtl]) address, .mce-visualblocks:not([dir=rtl]) pre, .mce-visualblocks:not([dir=rtl]) figure, .mce-visualblocks:not([dir=rtl]) figcaption, .mce-visualblocks:not([dir=rtl]) hgroup, .mce-visualblocks:not([dir=rtl]) aside, .mce-visualblocks:not([dir=rtl]) ul, .mce-visualblocks:not([dir=rtl]) ol, .mce-visualblocks:not([dir=rtl]) dl { margin-left: 3px; } .mce-visualblocks[dir=rtl] p, .mce-visualblocks[dir=rtl] h1, .mce-visualblocks[dir=rtl] h2, .mce-visualblocks[dir=rtl] h3, .mce-visualblocks[dir=rtl] h4, .mce-visualblocks[dir=rtl] h5, .mce-visualblocks[dir=rtl] h6, .mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), .mce-visualblocks[dir=rtl] section, .mce-visualblocks[dir=rtl] article, .mce-visualblocks[dir=rtl] blockquote, .mce-visualblocks[dir=rtl] address, .mce-visualblocks[dir=rtl] pre, .mce-visualblocks[dir=rtl] figure, .mce-visualblocks[dir=rtl] figcaption, .mce-visualblocks[dir=rtl] hgroup, .mce-visualblocks[dir=rtl] aside, .mce-visualblocks[dir=rtl] ul, .mce-visualblocks[dir=rtl] ol, .mce-visualblocks[dir=rtl] dl { background-position-x: right; margin-right: 3px; } .mce-nbsp, .mce-shy { background: #aaa; } .mce-shy::after { content: '-'; } body { font-family: sans-serif; } table { border-collapse: collapse; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/tinymce-5-dark/content.inline.css ================================================ .mce-content-body .mce-item-anchor { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; } .mce-content-body .mce-item-anchor:empty { cursor: default; display: inline-block; height: 12px !important; padding: 0 2px; -webkit-user-modify: read-only; -moz-user-modify: read-only; -webkit-user-select: all; -moz-user-select: all; user-select: all; width: 8px !important; } .mce-content-body .mce-item-anchor:not(:empty) { background-position-x: 2px; display: inline-block; padding-left: 12px; } .mce-content-body .mce-item-anchor[data-mce-selected] { outline-offset: 1px; } .tox-comments-visible .tox-comment[contenteditable="false"]:not([data-mce-selected]), .tox-comments-visible span.tox-comment img:not([data-mce-selected]), .tox-comments-visible span.tox-comment > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #ffe89d; } .tox-comments-visible .tox-comment[contenteditable="false"][data-mce-annotation-active="true"]:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] img:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > audio:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] > video:not([data-mce-selected]), .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"] span.mce-preview-object:not([data-mce-selected]) { outline: 3px solid #fed635; } .tox-comments-visible span.tox-comment:not([data-mce-selected]) { background-color: #ffe89d; outline: none; } .tox-comments-visible span.tox-comment[data-mce-annotation-active="true"]:not([data-mce-selected="inline-boundary"]) { background-color: #fed635; } .tox-checklist > li:not(.tox-checklist--hidden) { list-style: none; margin: 0.25em 0; } .tox-checklist > li:not(.tox-checklist--hidden)::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); cursor: pointer; height: 1em; margin-left: -1.5em; margin-top: 0.125em; position: absolute; width: 1em; } .tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); } [dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { margin-left: 0; margin-right: -1.5em; } /* stylelint-disable */ /* http://prismjs.com/ */ /** * prism.js default theme for JavaScript, CSS and HTML * Based on dabblet (http://dabblet.com) * @author Lea Verou */ code[class*="language-"], pre[class*="language-"] { color: black; background: none; text-shadow: 0 1px white; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; font-size: 1em; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.5; -moz-tab-size: 4; tab-size: 4; -webkit-hyphens: none; hyphens: none; } pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { text-shadow: none; background: #b3d4fc; } pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection { text-shadow: none; background: #b3d4fc; } @media print { code[class*="language-"], pre[class*="language-"] { text-shadow: none; } } /* Code blocks */ pre[class*="language-"] { padding: 1em; margin: 0.5em 0; overflow: auto; } :not(pre) > code[class*="language-"], pre[class*="language-"] { background: #f5f2f0; } /* Inline code */ :not(pre) > code[class*="language-"] { padding: 0.1em; border-radius: 0.3em; white-space: normal; } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: slategray; } .token.punctuation { color: #999; } .token.namespace { opacity: 0.7; } .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: #905; } .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #690; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { color: #9a6e3a; /* This background color was intended by the author of this theme. */ background: hsla(0, 0%, 100%, 0.5); } .token.atrule, .token.attr-value, .token.keyword { color: #07a; } .token.function, .token.class-name { color: #DD4A68; } .token.regex, .token.important, .token.variable { color: #e90; } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } /* stylelint-enable */ .mce-content-body { overflow-wrap: break-word; word-wrap: break-word; } .mce-content-body .mce-visual-caret { background-color: black; background-color: currentColor; position: absolute; } .mce-content-body .mce-visual-caret-hidden { display: none; } .mce-content-body *[data-mce-caret] { left: -1000px; margin: 0; padding: 0; position: absolute; right: auto; top: 0; } .mce-content-body .mce-offscreen-selection { left: -2000000px; max-width: 1000000px; position: absolute; } .mce-content-body *[contentEditable=false] { cursor: default; } .mce-content-body *[contentEditable=true] { cursor: text; } .tox-cursor-format-painter { cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; } div.mce-footnotes hr { margin-inline-end: auto; margin-inline-start: 0; width: 25%; } div.mce-footnotes li > a.mce-footnotes-backlink { text-decoration: none; } @media print { sup.mce-footnote a { color: black; text-decoration: none; } div.mce-footnotes { break-inside: avoid; width: 100%; } div.mce-footnotes li > a.mce-footnotes-backlink { display: none; } } .mce-content-body figure.align-left { float: left; } .mce-content-body figure.align-right { float: right; } .mce-content-body figure.image.align-center { display: table; margin-left: auto; margin-right: auto; } .mce-preview-object { border: 1px solid gray; display: inline-block; line-height: 0; margin: 0 2px 0 2px; position: relative; } .mce-preview-object .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-preview-object[data-mce-selected="2"] .mce-shim { display: none; } .mce-content-body .mce-mergetag { cursor: default !important; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body .mce-mergetag:hover { background-color: rgba(0, 108, 231, 0.1); } .mce-content-body .mce-mergetag-affix { background-color: rgba(0, 108, 231, 0.1); color: #006ce7; } .mce-object { background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; border: 1px dashed #aaa; } .mce-pagebreak { border: 1px dashed #aaa; cursor: default; display: block; height: 5px; margin-top: 15px; page-break-before: always; width: 100%; } @media print { .mce-pagebreak { border: 0; } } .tiny-pageembed .mce-shim { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tiny-pageembed[data-mce-selected="2"] .mce-shim { display: none; } .tiny-pageembed { display: inline-block; position: relative; } .tiny-pageembed--21by9, .tiny-pageembed--16by9, .tiny-pageembed--4by3, .tiny-pageembed--1by1 { display: block; overflow: hidden; padding: 0; position: relative; width: 100%; } .tiny-pageembed--21by9 { padding-top: 42.857143%; } .tiny-pageembed--16by9 { padding-top: 56.25%; } .tiny-pageembed--4by3 { padding-top: 75%; } .tiny-pageembed--1by1 { padding-top: 100%; } .tiny-pageembed--21by9 iframe, .tiny-pageembed--16by9 iframe, .tiny-pageembed--4by3 iframe, .tiny-pageembed--1by1 iframe { border: 0; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .mce-content-body[data-mce-placeholder] { position: relative; } .mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { color: rgba(34, 47, 62, 0.7); content: attr(data-mce-placeholder); position: absolute; } .mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { left: 1px; } .mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { right: 1px; } .mce-content-body div.mce-resizehandle { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; height: 10px; position: absolute; width: 10px; z-index: 1298; } .mce-content-body div.mce-resizehandle:hover { background-color: #4099ff; } .mce-content-body div.mce-resizehandle:nth-of-type(1) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(2) { cursor: nesw-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(3) { cursor: nwse-resize; } .mce-content-body div.mce-resizehandle:nth-of-type(4) { cursor: nesw-resize; } .mce-content-body .mce-resize-backdrop { z-index: 10000; } .mce-content-body .mce-clonedresizable { cursor: default; opacity: 0.5; outline: 1px dashed black; position: absolute; z-index: 10001; } .mce-content-body .mce-clonedresizable.mce-resizetable-columns th, .mce-content-body .mce-clonedresizable.mce-resizetable-columns td { border: 0; } .mce-content-body .mce-resize-helper { background: #555; background: rgba(0, 0, 0, 0.75); border: 1px; border-radius: 3px; color: white; display: none; font-family: sans-serif; font-size: 12px; line-height: 14px; margin: 5px 10px; padding: 5px; position: absolute; white-space: nowrap; z-index: 10002; } .tox-rtc-user-selection { position: relative; } .tox-rtc-user-cursor { bottom: 0; cursor: default; position: absolute; top: 0; width: 2px; } .tox-rtc-user-cursor::before { background-color: inherit; border-radius: 50%; content: ''; display: block; height: 8px; position: absolute; right: -3px; top: -3px; width: 8px; } .tox-rtc-user-cursor:hover::after { background-color: inherit; border-radius: 100px; box-sizing: border-box; color: #fff; content: attr(data-user); display: block; font-size: 12px; font-weight: bold; left: -5px; min-height: 8px; min-width: 8px; padding: 0 12px; position: absolute; top: -11px; white-space: nowrap; z-index: 1000; } .tox-rtc-user-selection--1 .tox-rtc-user-cursor { background-color: #2dc26b; } .tox-rtc-user-selection--2 .tox-rtc-user-cursor { background-color: #e03e2d; } .tox-rtc-user-selection--3 .tox-rtc-user-cursor { background-color: #f1c40f; } .tox-rtc-user-selection--4 .tox-rtc-user-cursor { background-color: #3598db; } .tox-rtc-user-selection--5 .tox-rtc-user-cursor { background-color: #b96ad9; } .tox-rtc-user-selection--6 .tox-rtc-user-cursor { background-color: #e67e23; } .tox-rtc-user-selection--7 .tox-rtc-user-cursor { background-color: #aaa69d; } .tox-rtc-user-selection--8 .tox-rtc-user-cursor { background-color: #f368e0; } .tox-rtc-remote-image { background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; border: 1px solid #ccc; min-height: 240px; min-width: 320px; } .mce-match-marker { background: #aaa; color: #fff; } .mce-match-marker-selected { background: #39f; color: #fff; } .mce-match-marker-selected::-moz-selection { background: #39f; color: #fff; } .mce-match-marker-selected::selection { background: #39f; color: #fff; } .mce-content-body img[data-mce-selected], .mce-content-body video[data-mce-selected], .mce-content-body audio[data-mce-selected], .mce-content-body object[data-mce-selected], .mce-content-body embed[data-mce-selected], .mce-content-body table[data-mce-selected], .mce-content-body details[data-mce-selected] { outline: 3px solid #b4d7ff; } .mce-content-body hr[data-mce-selected] { outline: 3px solid #b4d7ff; outline-offset: 1px; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { outline: 3px solid #b4d7ff; } .mce-content-body *[contentEditable=false][data-mce-selected] { cursor: not-allowed; outline: 3px solid #b4d7ff; } .mce-content-body.mce-content-readonly *[contentEditable=true]:focus, .mce-content-body.mce-content-readonly *[contentEditable=true]:hover { outline: none; } .mce-content-body *[data-mce-selected="inline-boundary"] { background-color: #b4d7ff; } .mce-content-body .mce-edit-focus { outline: 3px solid #b4d7ff; } .mce-content-body td[data-mce-selected], .mce-content-body th[data-mce-selected] { position: relative; } .mce-content-body td[data-mce-selected]::-moz-selection, .mce-content-body th[data-mce-selected]::-moz-selection { background: none; } .mce-content-body td[data-mce-selected]::selection, .mce-content-body th[data-mce-selected]::selection { background: none; } .mce-content-body td[data-mce-selected] *, .mce-content-body th[data-mce-selected] * { outline: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { background-color: rgba(180, 215, 255, 0.7); border: 1px solid rgba(180, 215, 255, 0.7); bottom: -1px; content: ''; left: -1px; mix-blend-mode: multiply; position: absolute; right: -1px; top: -1px; } @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { .mce-content-body td[data-mce-selected]::after, .mce-content-body th[data-mce-selected]::after { border-color: rgba(0, 84, 180, 0.7); } } .mce-content-body img[data-mce-selected]::-moz-selection { background: none; } .mce-content-body img[data-mce-selected]::selection { background: none; } .ephox-snooker-resizer-bar { background-color: #b4d7ff; opacity: 0; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .ephox-snooker-resizer-cols { cursor: col-resize; } .ephox-snooker-resizer-rows { cursor: row-resize; } .ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { opacity: 1; } .mce-spellchecker-word { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; height: 2rem; } .mce-spellchecker-grammar { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); background-position: 0 calc(100% + 1px); background-repeat: repeat-x; background-size: auto 6px; cursor: default; } .mce-toc { border: 1px solid gray; } .mce-toc h2 { margin: 4px; } .mce-toc li { list-style-type: none; } [data-mce-block] { display: block; } table[style*="border-width: 0px"], .mce-item-table:not([border]), .mce-item-table[border="0"], table[style*="border-width: 0px"] td, .mce-item-table:not([border]) td, .mce-item-table[border="0"] td, table[style*="border-width: 0px"] th, .mce-item-table:not([border]) th, .mce-item-table[border="0"] th, table[style*="border-width: 0px"] caption, .mce-item-table:not([border]) caption, .mce-item-table[border="0"] caption { border: 1px dashed #bbb; } .mce-visualblocks p, .mce-visualblocks h1, .mce-visualblocks h2, .mce-visualblocks h3, .mce-visualblocks h4, .mce-visualblocks h5, .mce-visualblocks h6, .mce-visualblocks div:not([data-mce-bogus]), .mce-visualblocks section, .mce-visualblocks article, .mce-visualblocks blockquote, .mce-visualblocks address, .mce-visualblocks pre, .mce-visualblocks figure, .mce-visualblocks figcaption, .mce-visualblocks hgroup, .mce-visualblocks aside, .mce-visualblocks ul, .mce-visualblocks ol, .mce-visualblocks dl { background-repeat: no-repeat; border: 1px dashed #bbb; margin-left: 3px; padding-top: 10px; } .mce-visualblocks p { background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); } .mce-visualblocks h1 { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); } .mce-visualblocks h2 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); } .mce-visualblocks h3 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); } .mce-visualblocks h4 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); } .mce-visualblocks h5 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); } .mce-visualblocks h6 { background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); } .mce-visualblocks div:not([data-mce-bogus]) { background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); } .mce-visualblocks section { background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); } .mce-visualblocks article { background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); } .mce-visualblocks blockquote { background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); } .mce-visualblocks address { background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); } .mce-visualblocks pre { background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); } .mce-visualblocks figure { background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); } .mce-visualblocks figcaption { border: 1px dashed #bbb; } .mce-visualblocks hgroup { background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); } .mce-visualblocks aside { background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); } .mce-visualblocks ul { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); } .mce-visualblocks ol { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); } .mce-visualblocks dl { background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); } .mce-visualblocks:not([dir=rtl]) p, .mce-visualblocks:not([dir=rtl]) h1, .mce-visualblocks:not([dir=rtl]) h2, .mce-visualblocks:not([dir=rtl]) h3, .mce-visualblocks:not([dir=rtl]) h4, .mce-visualblocks:not([dir=rtl]) h5, .mce-visualblocks:not([dir=rtl]) h6, .mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), .mce-visualblocks:not([dir=rtl]) section, .mce-visualblocks:not([dir=rtl]) article, .mce-visualblocks:not([dir=rtl]) blockquote, .mce-visualblocks:not([dir=rtl]) address, .mce-visualblocks:not([dir=rtl]) pre, .mce-visualblocks:not([dir=rtl]) figure, .mce-visualblocks:not([dir=rtl]) figcaption, .mce-visualblocks:not([dir=rtl]) hgroup, .mce-visualblocks:not([dir=rtl]) aside, .mce-visualblocks:not([dir=rtl]) ul, .mce-visualblocks:not([dir=rtl]) ol, .mce-visualblocks:not([dir=rtl]) dl { margin-left: 3px; } .mce-visualblocks[dir=rtl] p, .mce-visualblocks[dir=rtl] h1, .mce-visualblocks[dir=rtl] h2, .mce-visualblocks[dir=rtl] h3, .mce-visualblocks[dir=rtl] h4, .mce-visualblocks[dir=rtl] h5, .mce-visualblocks[dir=rtl] h6, .mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), .mce-visualblocks[dir=rtl] section, .mce-visualblocks[dir=rtl] article, .mce-visualblocks[dir=rtl] blockquote, .mce-visualblocks[dir=rtl] address, .mce-visualblocks[dir=rtl] pre, .mce-visualblocks[dir=rtl] figure, .mce-visualblocks[dir=rtl] figcaption, .mce-visualblocks[dir=rtl] hgroup, .mce-visualblocks[dir=rtl] aside, .mce-visualblocks[dir=rtl] ul, .mce-visualblocks[dir=rtl] ol, .mce-visualblocks[dir=rtl] dl { background-position-x: right; margin-right: 3px; } .mce-nbsp, .mce-shy { background: #aaa; } .mce-shy::after { content: '-'; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/tinymce-5-dark/skin.css ================================================ .tox { box-shadow: none; box-sizing: content-box; color: #2A3746; cursor: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; font-style: normal; font-weight: normal; line-height: normal; -webkit-tap-highlight-color: transparent; text-decoration: none; text-shadow: none; text-transform: none; vertical-align: initial; white-space: normal; } .tox *:not(svg):not(rect) { box-sizing: inherit; color: inherit; cursor: inherit; direction: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; -webkit-tap-highlight-color: inherit; text-align: inherit; text-decoration: inherit; text-shadow: inherit; text-transform: inherit; vertical-align: inherit; white-space: inherit; } .tox *:not(svg):not(rect) { /* stylelint-disable-line no-duplicate-selectors */ background: transparent; border: 0; box-shadow: none; float: none; height: auto; margin: 0; max-width: none; outline: 0; padding: 0; position: static; width: auto; } .tox:not([dir=rtl]) { direction: ltr; text-align: left; } .tox[dir=rtl] { direction: rtl; text-align: right; } .tox-tinymce { border: 1px solid #000000; border-radius: 0; box-shadow: none; box-sizing: border-box; display: flex; flex-direction: column; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; overflow: hidden; position: relative; visibility: inherit !important; } .tox.tox-tinymce-inline { border: none; box-shadow: none; overflow: initial; } .tox.tox-tinymce-inline .tox-editor-container { overflow: initial; } .tox.tox-tinymce-inline .tox-editor-header { background-color: #222f3e; border: 1px solid #000000; border-radius: 0; box-shadow: none; overflow: hidden; } .tox-tinymce-aux { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; z-index: 1300; } .tox-tinymce *:focus, .tox-tinymce-aux *:focus { outline: none; } button::-moz-focus-inner { border: 0; } .tox[dir=rtl] .tox-icon--flip svg { transform: rotateY(180deg); } .tox .accessibility-issue__header { align-items: center; display: flex; margin-bottom: 4px; } .tox .accessibility-issue__description { align-items: stretch; border-radius: 3px; display: flex; justify-content: space-between; } .tox .accessibility-issue__description > div { padding-bottom: 4px; } .tox .accessibility-issue__description > div > div { align-items: center; display: flex; margin-bottom: 4px; } .tox .accessibility-issue__description > div > div .tox-icon svg { display: block; } .tox .accessibility-issue__repair { margin-top: 16px; } .tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { background-color: rgba(30, 113, 170, 0.4); color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { fill: #fff; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon { background-color: #207ab7; color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus { background-color: #1c6ca1; } .tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active { background-color: #185d8c; } .tox .tox-dialog__body-content .accessibility-issue--warn { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { background-color: rgba(255, 165, 0, 0.5); color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { fill: #fff; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon { background-color: #FFE89D; color: #2A3746; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus { background-color: #F2D574; color: #2A3746; } .tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active { background-color: #E8C657; color: #2A3746; } .tox .tox-dialog__body-content .accessibility-issue--error { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { background-color: rgba(204, 0, 0, 0.5); color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { fill: #fff; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon { background-color: #F2BFBF; color: #2A3746; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover, .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus { background-color: #E9A4A4; color: #2A3746; } .tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active { background-color: #EE9494; color: #2A3746; } .tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { background-color: rgba(120, 171, 70, 0.5); color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > *:last-child { display: none; } .tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { color: #fff; } .tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { fill: #fff; } .tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1, .tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { font-size: 14px; margin-top: 0; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button { margin-left: 4px; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { margin-left: auto; } .tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description { padding: 4px 4px 4px 8px; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button { margin-right: 4px; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { margin-right: auto; } .tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description { padding: 4px 8px 4px 4px; } .tox .tox-advtemplate .tox-form__grid { flex: 1; } .tox .tox-advtemplate .tox-form__grid > div:first-child { display: flex; flex-direction: column; width: 30%; } .tox .tox-advtemplate .tox-form__grid > div:first-child > div:nth-child(2) { flex-basis: 0; flex-grow: 1; overflow: auto; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid > div:first-child { width: 100%; } } .tox .tox-advtemplate iframe { border-color: #000000; border-radius: 0; border-style: solid; border-width: 1px; margin: 0 10px; } .tox .tox-anchorbar { display: flex; flex: 0 0 auto; } .tox .tox-bottom-anchorbar { display: flex; flex: 0 0 auto; } .tox .tox-bar { display: flex; flex: 0 0 auto; } .tox .tox-button { background-color: #207ab7; background-image: none; background-position: 0 0; background-repeat: repeat; border-color: #207ab7; border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #fff; cursor: pointer; display: inline-block; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 14px; font-style: normal; font-weight: bold; letter-spacing: normal; line-height: 24px; margin: 0; outline: none; padding: 4px 16px; position: relative; text-align: center; text-decoration: none; text-transform: none; white-space: nowrap; } .tox .tox-button::before { border-radius: 3px; bottom: -1px; box-shadow: inset 0 0 0 2px #fff, 0 0 0 1px #207ab7, 0 0 0 3px rgba(32, 122, 183, 0.25); content: ''; left: -1px; opacity: 0; pointer-events: none; position: absolute; right: -1px; top: -1px; } .tox .tox-button[disabled] { background-color: #207ab7; background-image: none; border-color: #207ab7; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-button:focus:not(:disabled) { background-color: #1c6ca1; background-image: none; border-color: #1c6ca1; box-shadow: none; color: #fff; } .tox .tox-button:focus-visible:not(:disabled)::before { opacity: 1; } .tox .tox-button:hover:not(:disabled) { background-color: #1c6ca1; background-image: none; border-color: #1c6ca1; box-shadow: none; color: #fff; } .tox .tox-button:active:not(:disabled) { background-color: #185d8c; background-image: none; border-color: #185d8c; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled { background-color: #185d8c; background-image: none; border-color: #185d8c; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled[disabled] { background-color: #185d8c; background-image: none; border-color: #185d8c; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-button.tox-button--enabled:focus:not(:disabled) { background-color: #154f76; background-image: none; border-color: #154f76; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled:hover:not(:disabled) { background-color: #154f76; background-image: none; border-color: #154f76; box-shadow: none; color: #fff; } .tox .tox-button.tox-button--enabled:active:not(:disabled) { background-color: #114060; background-image: none; border-color: #114060; box-shadow: none; color: #fff; } .tox .tox-button--icon-and-text, .tox .tox-button.tox-button--icon-and-text, .tox .tox-button.tox-button--secondary.tox-button--icon-and-text { display: flex; padding: 5px 4px; } .tox .tox-button--icon-and-text .tox-icon svg, .tox .tox-button.tox-button--icon-and-text .tox-icon svg, .tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg { display: block; fill: currentColor; } .tox .tox-button--secondary { background-color: #3d546f; background-image: none; background-position: 0 0; background-repeat: repeat; border-color: #3d546f; border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; color: #fff; font-size: 14px; font-style: normal; font-weight: bold; letter-spacing: normal; outline: none; padding: 4px 16px; text-decoration: none; text-transform: none; } .tox .tox-button--secondary[disabled] { background-color: #3d546f; background-image: none; border-color: #3d546f; box-shadow: none; color: rgba(255, 255, 255, 0.5); } .tox .tox-button--secondary:focus:not(:disabled) { background-color: #34485f; background-image: none; border-color: #34485f; box-shadow: none; color: #fff; } .tox .tox-button--secondary:hover:not(:disabled) { background-color: #34485f; background-image: none; border-color: #34485f; box-shadow: none; color: #fff; } .tox .tox-button--secondary:active:not(:disabled) { background-color: #2b3b4e; background-image: none; border-color: #2b3b4e; box-shadow: none; color: #fff; } .tox .tox-button--secondary.tox-button--enabled { background-color: #346085; background-image: none; border-color: #346085; box-shadow: none; color: #fff; } .tox .tox-button--secondary.tox-button--enabled[disabled] { background-color: #346085; background-image: none; border-color: #346085; box-shadow: none; color: rgba(255, 255, 255, 0.5); } .tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled) { background-color: #2d5373; background-image: none; border-color: #2d5373; box-shadow: none; color: #fff; } .tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled) { background-color: #2d5373; background-image: none; border-color: #2d5373; box-shadow: none; color: #fff; } .tox .tox-button--secondary.tox-button--enabled:active:not(:disabled) { background-color: #264560; background-image: none; border-color: #264560; box-shadow: none; color: #fff; } .tox .tox-button--icon, .tox .tox-button.tox-button--icon, .tox .tox-button.tox-button--secondary.tox-button--icon { padding: 4px; } .tox .tox-button--icon .tox-icon svg, .tox .tox-button.tox-button--icon .tox-icon svg, .tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { display: block; fill: currentColor; } .tox .tox-button-link { background: 0; border: none; box-sizing: border-box; cursor: pointer; display: inline-block; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; font-weight: normal; line-height: 1.3; margin: 0; padding: 0; white-space: nowrap; } .tox .tox-button-link--sm { font-size: 14px; } .tox .tox-button--naked { background-color: transparent; border-color: transparent; box-shadow: unset; color: #fff; } .tox .tox-button--naked[disabled] { background-color: #3d546f; border-color: #3d546f; box-shadow: none; color: rgba(255, 255, 255, 0.5); } .tox .tox-button--naked:hover:not(:disabled) { background-color: #34485f; border-color: #34485f; box-shadow: none; color: #fff; } .tox .tox-button--naked:focus:not(:disabled) { background-color: #34485f; border-color: #34485f; box-shadow: none; color: #fff; } .tox .tox-button--naked:active:not(:disabled) { background-color: #2b3b4e; border-color: #2b3b4e; box-shadow: none; color: #fff; } .tox .tox-button--naked .tox-icon svg { fill: currentColor; } .tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { color: #fff; } .tox .tox-checkbox { align-items: center; border-radius: 3px; cursor: pointer; display: flex; height: 36px; min-width: 36px; } .tox .tox-checkbox__input { /* Hide from view but visible to screen readers */ height: 1px; overflow: hidden; position: absolute; top: auto; width: 1px; } .tox .tox-checkbox__icons { align-items: center; border-radius: 3px; box-shadow: 0 0 0 2px transparent; box-sizing: content-box; display: flex; height: 24px; justify-content: center; padding: calc(4px - 1px); width: 24px; } .tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: block; fill: rgba(255, 255, 255, 0.2); } .tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { display: none; fill: #207ab7; } .tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { display: none; fill: #207ab7; } .tox .tox-checkbox--disabled { color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { fill: rgba(255, 255, 255, 0.5); } .tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: none; } .tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { display: block; } .tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { display: none; } .tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { display: block; } .tox input.tox-checkbox__input:focus + .tox-checkbox__icons { border-radius: 3px; box-shadow: inset 0 0 0 1px #207ab7; padding: calc(4px - 1px); } .tox:not([dir=rtl]) .tox-checkbox__label { margin-left: 4px; } .tox:not([dir=rtl]) .tox-checkbox__input { left: -10000px; } .tox:not([dir=rtl]) .tox-bar .tox-checkbox { margin-left: 4px; } .tox[dir=rtl] .tox-checkbox__label { margin-right: 4px; } .tox[dir=rtl] .tox-checkbox__input { right: -10000px; } .tox[dir=rtl] .tox-bar .tox-checkbox { margin-right: 4px; } .tox { /* stylelint-disable-next-line no-descending-specificity */ } .tox .tox-collection--toolbar .tox-collection__group { display: flex; padding: 0; } .tox .tox-collection--grid .tox-collection__group { display: flex; flex-wrap: wrap; max-height: 208px; overflow-x: hidden; overflow-y: auto; padding: 0; } .tox .tox-collection--list .tox-collection__group { border-bottom-width: 0; border-color: #1a1a1a; border-left-width: 0; border-right-width: 0; border-style: solid; border-top-width: 1px; padding: 4px 0; } .tox .tox-collection--list .tox-collection__group:first-child { border-top-width: 0; } .tox .tox-collection__group-heading { background-color: #333333; color: #fff; cursor: default; font-size: 12px; font-style: normal; font-weight: normal; margin-bottom: 4px; margin-top: -4px; padding: 4px 8px; text-transform: none; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .tox .tox-collection__item { align-items: center; border-radius: 3px; color: #fff; display: flex; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; } .tox .tox-collection--list .tox-collection__item { padding: 4px 8px; } .tox .tox-collection--toolbar .tox-collection__item { border-radius: 3px; padding: 4px; } .tox .tox-collection--grid .tox-collection__item { border-radius: 3px; padding: 4px; } .tox .tox-collection--list .tox-collection__item--enabled { background-color: #2b3b4e; color: #fff; } .tox .tox-collection--list .tox-collection__item--active { background-color: #4a5562; } .tox .tox-collection--toolbar .tox-collection__item--enabled { background-color: #757d87; color: #fff; } .tox .tox-collection--toolbar .tox-collection__item--active { background-color: #4a5562; } .tox .tox-collection--grid .tox-collection__item--enabled { background-color: #757d87; color: #fff; } .tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { background-color: #4a5562; color: #fff; } .tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { color: #fff; } .tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { color: #fff; } .tox .tox-collection__item-icon, .tox .tox-collection__item-checkmark { align-items: center; display: flex; height: 24px; justify-content: center; width: 24px; } .tox .tox-collection__item-icon svg, .tox .tox-collection__item-checkmark svg { fill: currentColor; } .tox .tox-collection--toolbar-lg .tox-collection__item-icon { height: 48px; width: 48px; } .tox .tox-collection__item-label { color: currentColor; display: inline-block; flex: 1; font-size: 14px; font-style: normal; font-weight: normal; line-height: 24px; text-transform: none; word-break: break-all; } .tox .tox-collection__item-accessory { color: rgba(255, 255, 255, 0.5); display: inline-block; font-size: 14px; height: 24px; line-height: 24px; text-transform: none; } .tox .tox-collection__item-caret { align-items: center; display: flex; min-height: 24px; } .tox .tox-collection__item-caret::after { content: ''; font-size: 0; min-height: inherit; } .tox .tox-collection__item-caret svg { fill: #fff; } .tox .tox-collection__item--state-disabled { background-color: transparent; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg { display: none; } .tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory + .tox-collection__item-checkmark { display: none; } .tox .tox-collection--horizontal { background-color: #2b3b4e; border: 1px solid #1a1a1a; border-radius: 3px; box-shadow: 0 0 2px 0 rgba(42, 55, 70, 0.2), 0 4px 8px 0 rgba(42, 55, 70, 0.15); display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: nowrap; margin-bottom: 0; overflow-x: auto; padding: 0; } .tox .tox-collection--horizontal .tox-collection__group { align-items: center; display: flex; flex-wrap: nowrap; margin: 0; padding: 0 4px; } .tox .tox-collection--horizontal .tox-collection__item { height: 34px; margin: 3px 0 2px 0; padding: 0 4px; } .tox .tox-collection--horizontal .tox-collection__item-label { white-space: nowrap; } .tox .tox-collection--horizontal .tox-collection__item-caret { margin-left: 4px; } .tox .tox-collection__item-container { display: flex; } .tox .tox-collection__item-container--row { align-items: center; flex: 1 1 auto; flex-direction: row; } .tox .tox-collection__item-container--row.tox-collection__item-container--align-left { margin-right: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--align-right { justify-content: flex-end; margin-left: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { align-items: flex-start; margin-bottom: auto; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { align-items: center; } .tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { align-items: flex-end; margin-top: auto; } .tox .tox-collection__item-container--column { align-self: center; flex: 1 1 auto; flex-direction: column; } .tox .tox-collection__item-container--column.tox-collection__item-container--align-left { align-items: flex-start; } .tox .tox-collection__item-container--column.tox-collection__item-container--align-right { align-items: flex-end; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { align-self: flex-start; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { align-self: center; } .tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { align-self: flex-end; } .tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { border-right: 1px solid #000000; } .tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > *:not(:first-child) { margin-left: 8px; } .tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { margin-left: 4px; } .tox:not([dir=rtl]) .tox-collection__item-accessory { margin-left: 16px; text-align: right; } .tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret { margin-left: 16px; } .tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { border-left: 1px solid #000000; } .tox[dir=rtl] .tox-collection--list .tox-collection__item > *:not(:first-child) { margin-right: 8px; } .tox[dir=rtl] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { margin-right: 4px; } .tox[dir=rtl] .tox-collection__item-accessory { margin-right: 16px; text-align: left; } .tox[dir=rtl] .tox-collection .tox-collection__item-caret { margin-right: 16px; transform: rotateY(180deg); } .tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret { margin-right: 4px; } .tox .tox-color-picker-container { display: flex; flex-direction: row; height: 225px; margin: 0; } .tox .tox-sv-palette { box-sizing: border-box; display: flex; height: 100%; } .tox .tox-sv-palette-spectrum { height: 100%; } .tox .tox-sv-palette, .tox .tox-sv-palette-spectrum { width: 225px; } .tox .tox-sv-palette-thumb { background: none; border: 1px solid black; border-radius: 50%; box-sizing: content-box; height: 12px; position: absolute; width: 12px; } .tox .tox-sv-palette-inner-thumb { border: 1px solid white; border-radius: 50%; height: 10px; position: absolute; width: 10px; } .tox .tox-hue-slider { box-sizing: border-box; height: 100%; width: 25px; } .tox .tox-hue-slider-spectrum { background: linear-gradient(to bottom, #f00, #ff0080, #f0f, #8000ff, #00f, #0080ff, #0ff, #00ff80, #0f0, #80ff00, #ff0, #ff8000, #f00); height: 100%; width: 100%; } .tox .tox-hue-slider, .tox .tox-hue-slider-spectrum { width: 20px; } .tox .tox-hue-slider-thumb { background: white; border: 1px solid black; box-sizing: content-box; height: 4px; width: 100%; } .tox .tox-rgb-form { display: flex; flex-direction: column; justify-content: space-between; } .tox .tox-rgb-form div { align-items: center; display: flex; justify-content: space-between; margin-bottom: 5px; width: inherit; } .tox .tox-rgb-form input { width: 6em; } .tox .tox-rgb-form input.tox-invalid { /* Need !important to override Chrome's focus styling unfortunately */ border: 1px solid red !important; } .tox .tox-rgb-form .tox-rgba-preview { border: 1px solid black; flex-grow: 2; margin-bottom: 0; } .tox:not([dir=rtl]) .tox-sv-palette { margin-right: 15px; } .tox:not([dir=rtl]) .tox-hue-slider { margin-right: 15px; } .tox:not([dir=rtl]) .tox-hue-slider-thumb { margin-left: -1px; } .tox:not([dir=rtl]) .tox-rgb-form label { margin-right: 0.5em; } .tox[dir=rtl] .tox-sv-palette { margin-left: 15px; } .tox[dir=rtl] .tox-hue-slider { margin-left: 15px; } .tox[dir=rtl] .tox-hue-slider-thumb { margin-right: -1px; } .tox[dir=rtl] .tox-rgb-form label { margin-left: 0.5em; } .tox .tox-toolbar .tox-swatches, .tox .tox-toolbar__primary .tox-swatches, .tox .tox-toolbar__overflow .tox-swatches { margin: 2px 0 3px 4px; } .tox .tox-collection--list .tox-collection__group .tox-swatches-menu { border: 0; margin: -4px 0; } .tox .tox-swatches__row { display: flex; } .tox .tox-swatch { height: 30px; transition: transform 0.15s, box-shadow 0.15s; width: 30px; } .tox .tox-swatch:hover, .tox .tox-swatch:focus { box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; transform: scale(0.8); } .tox .tox-swatch--remove { align-items: center; display: flex; justify-content: center; } .tox .tox-swatch--remove svg path { stroke: #e74c3c; } .tox .tox-swatches__picker-btn { align-items: center; background-color: transparent; border: 0; cursor: pointer; display: flex; height: 30px; justify-content: center; outline: none; padding: 0; width: 30px; } .tox .tox-swatches__picker-btn svg { fill: #fff; height: 24px; width: 24px; } .tox .tox-swatches__picker-btn:hover { background: #4a5562; } .tox div.tox-swatch:not(.tox-swatch--remove) svg { display: none; fill: #fff; height: 24px; margin: calc((30px - 24px) / 2) calc((30px - 24px) / 2); width: 24px; } .tox div.tox-swatch:not(.tox-swatch--remove) svg path { fill: #fff; paint-order: stroke; stroke: #222f3e; stroke-width: 2px; } .tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg { display: block; } .tox:not([dir=rtl]) .tox-swatches__picker-btn { margin-left: auto; } .tox[dir=rtl] .tox-swatches__picker-btn { margin-right: auto; } .tox .tox-comment-thread { background: #2b3b4e; position: relative; } .tox .tox-comment-thread > *:not(:first-child) { margin-top: 8px; } .tox .tox-comment { background: #2b3b4e; border: 1px solid #000000; border-radius: 3px; box-shadow: 0 4px 8px 0 rgba(42, 55, 70, 0.1); padding: 8px 8px 16px 8px; position: relative; } .tox .tox-comment__header { align-items: center; color: #fff; display: flex; justify-content: space-between; } .tox .tox-comment__date { color: #fff; font-size: 12px; line-height: 18px; } .tox .tox-comment__body { color: #fff; font-size: 14px; font-style: normal; font-weight: normal; line-height: 1.3; margin-top: 8px; position: relative; text-transform: initial; } .tox .tox-comment__body textarea { resize: none; white-space: normal; width: 100%; } .tox .tox-comment__expander { padding-top: 8px; } .tox .tox-comment__expander p { color: rgba(255, 255, 255, 0.5); font-size: 14px; font-style: normal; } .tox .tox-comment__body p { margin: 0; } .tox .tox-comment__buttonspacing { padding-top: 16px; text-align: center; } .tox .tox-comment-thread__overlay::after { background: #2b3b4e; bottom: 0; content: ""; display: flex; left: 0; opacity: 0.9; position: absolute; right: 0; top: 0; z-index: 5; } .tox .tox-comment__reply { display: flex; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; margin-top: 8px; } .tox .tox-comment__reply > *:first-child { margin-bottom: 8px; width: 100%; } .tox .tox-comment__edit { display: flex; flex-wrap: wrap; justify-content: flex-end; margin-top: 16px; } .tox .tox-comment__gradient::after { background: linear-gradient(rgba(43, 59, 78, 0), #2b3b4e); bottom: 0; content: ""; display: block; height: 5em; margin-top: -40px; position: absolute; width: 100%; } .tox .tox-comment__overlay { background: #2b3b4e; bottom: 0; display: flex; flex-direction: column; flex-grow: 1; left: 0; opacity: 0.9; position: absolute; right: 0; text-align: center; top: 0; z-index: 5; } .tox .tox-comment__loading-text { align-items: center; color: #fff; display: flex; flex-direction: column; position: relative; } .tox .tox-comment__loading-text > div { padding-bottom: 16px; } .tox .tox-comment__overlaytext { bottom: 0; flex-direction: column; font-size: 14px; left: 0; padding: 1em; position: absolute; right: 0; top: 0; z-index: 10; } .tox .tox-comment__overlaytext p { background-color: #2b3b4e; box-shadow: 0 0 8px 8px #2b3b4e; color: #fff; text-align: center; } .tox .tox-comment__overlaytext div:nth-of-type(2) { font-size: 0.8em; } .tox .tox-comment__busy-spinner { align-items: center; background-color: #2b3b4e; bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; z-index: 20; } .tox .tox-comment__scroll { display: flex; flex-direction: column; flex-shrink: 1; overflow: auto; } .tox .tox-conversations { margin: 8px; } .tox:not([dir=rtl]) .tox-comment__edit { margin-left: 8px; } .tox:not([dir=rtl]) .tox-comment__buttonspacing > *:last-child, .tox:not([dir=rtl]) .tox-comment__edit > *:last-child, .tox:not([dir=rtl]) .tox-comment__reply > *:last-child { margin-left: 8px; } .tox[dir=rtl] .tox-comment__edit { margin-right: 8px; } .tox[dir=rtl] .tox-comment__buttonspacing > *:last-child, .tox[dir=rtl] .tox-comment__edit > *:last-child, .tox[dir=rtl] .tox-comment__reply > *:last-child { margin-right: 8px; } .tox .tox-user { align-items: center; display: flex; } .tox .tox-user__avatar svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-user__avatar img { border-radius: 50%; height: 36px; object-fit: cover; vertical-align: middle; width: 36px; } .tox .tox-user__name { color: #fff; font-size: 14px; font-style: normal; font-weight: bold; line-height: 18px; text-transform: none; } .tox:not([dir=rtl]) .tox-user__avatar svg, .tox:not([dir=rtl]) .tox-user__avatar img { margin-right: 8px; } .tox:not([dir=rtl]) .tox-user__avatar + .tox-user__name { margin-left: 8px; } .tox[dir=rtl] .tox-user__avatar svg, .tox[dir=rtl] .tox-user__avatar img { margin-left: 8px; } .tox[dir=rtl] .tox-user__avatar + .tox-user__name { margin-right: 8px; } .tox .tox-dialog-wrap { align-items: center; bottom: 0; display: flex; justify-content: center; left: 0; position: fixed; right: 0; top: 0; z-index: 1100; } .tox .tox-dialog-wrap__backdrop { background-color: rgba(34, 47, 62, 0.75); bottom: 0; left: 0; position: absolute; right: 0; top: 0; z-index: 1; } .tox .tox-dialog-wrap__backdrop--opaque { background-color: #222f3e; } .tox .tox-dialog { background-color: #2b3b4e; border-color: #000000; border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: 0 16px 16px -10px rgba(42, 55, 70, 0.15), 0 0 40px 1px rgba(42, 55, 70, 0.15); display: flex; flex-direction: column; max-height: 100%; max-width: 480px; overflow: hidden; position: relative; width: 95vw; z-index: 2; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog { align-self: flex-start; margin: 8px auto; max-height: calc(100vh - 8px * 2); width: calc(100vw - 16px); } } .tox .tox-dialog-inline { z-index: 1100; } .tox .tox-dialog__header { align-items: center; background-color: #2b3b4e; border-bottom: none; color: #fff; display: flex; font-size: 16px; justify-content: space-between; padding: 8px 16px 0 16px; position: relative; } .tox .tox-dialog__header .tox-button { z-index: 1; } .tox .tox-dialog__draghandle { cursor: grab; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .tox .tox-dialog__draghandle:active { cursor: grabbing; } .tox .tox-dialog__dismiss { margin-left: auto; } .tox .tox-dialog__title { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 20px; font-style: normal; font-weight: normal; line-height: 1.3; margin: 0; text-transform: none; } .tox .tox-dialog__body { color: #fff; display: flex; flex: 1; font-size: 16px; font-style: normal; font-weight: normal; line-height: 1.3; min-width: 0; text-align: left; text-transform: none; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog__body { flex-direction: column; } } .tox .tox-dialog__body-nav { align-items: flex-start; display: flex; flex-direction: column; flex-shrink: 0; padding: 16px 16px; } @media only screen and (min-width: 768px ) { .tox .tox-dialog__body-nav { max-width: 11em; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { flex-direction: row; -webkit-overflow-scrolling: touch; overflow-x: auto; padding-bottom: 0; } } .tox .tox-dialog__body-nav-item { border-bottom: 2px solid transparent; color: rgba(255, 255, 255, 0.5); display: inline-block; flex-shrink: 0; font-size: 14px; line-height: 1.3; margin-bottom: 8px; max-width: 13em; text-decoration: none; } .tox .tox-dialog__body-nav-item:focus { background-color: rgba(32, 122, 183, 0.1); } .tox .tox-dialog__body-nav-item--active { border-bottom: 2px solid #207ab7; color: #207ab7; } .tox .tox-dialog__body-content { box-sizing: border-box; display: flex; flex: 1; flex-direction: column; max-height: min(650px, calc(100vh - 110px)); overflow: auto; -webkit-overflow-scrolling: touch; padding: 16px 16px; } .tox .tox-dialog__body-content > * { margin-bottom: 0; margin-top: 16px; } .tox .tox-dialog__body-content > *:first-child { margin-top: 0; } .tox .tox-dialog__body-content > *:last-child { margin-bottom: 0; } .tox .tox-dialog__body-content > *:only-child { margin-bottom: 0; margin-top: 0; } .tox .tox-dialog__body-content a { color: #207ab7; cursor: pointer; text-decoration: none; } .tox .tox-dialog__body-content a:hover, .tox .tox-dialog__body-content a:focus { color: #185d8c; text-decoration: none; } .tox .tox-dialog__body-content a:active { color: #185d8c; text-decoration: none; } .tox .tox-dialog__body-content svg { fill: #fff; } .tox .tox-dialog__body-content strong { font-weight: bold; } .tox .tox-dialog__body-content ul { list-style-type: disc; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dd { padding-inline-start: 2.5rem; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dl { margin-bottom: 16px; } .tox .tox-dialog__body-content ul, .tox .tox-dialog__body-content ol, .tox .tox-dialog__body-content dl, .tox .tox-dialog__body-content dd, .tox .tox-dialog__body-content dt { display: block; margin-inline-end: 0; margin-inline-start: 0; } .tox .tox-dialog__body-content .tox-form__group h1 { color: #fff; font-size: 20px; font-style: normal; font-weight: bold; letter-spacing: normal; margin-bottom: 16px; margin-top: 2rem; text-transform: none; } .tox .tox-dialog__body-content .tox-form__group h2 { color: #fff; font-size: 16px; font-style: normal; font-weight: bold; letter-spacing: normal; margin-bottom: 16px; margin-top: 2rem; text-transform: none; } .tox .tox-dialog__body-content .tox-form__group p { margin-bottom: 16px; } .tox .tox-dialog__body-content .tox-form__group h1:first-child, .tox .tox-dialog__body-content .tox-form__group h2:first-child, .tox .tox-dialog__body-content .tox-form__group p:first-child { margin-top: 0; } .tox .tox-dialog__body-content .tox-form__group h1:last-child, .tox .tox-dialog__body-content .tox-form__group h2:last-child, .tox .tox-dialog__body-content .tox-form__group p:last-child { margin-bottom: 0; } .tox .tox-dialog__body-content .tox-form__group h1:only-child, .tox .tox-dialog__body-content .tox-form__group h2:only-child, .tox .tox-dialog__body-content .tox-form__group p:only-child { margin-bottom: 0; margin-top: 0; } .tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center { text-align: center; } .tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end { text-align: end; } .tox .tox-dialog--width-lg { height: 650px; max-width: 1200px; } .tox .tox-dialog--fullscreen { height: 100%; max-width: 100%; } .tox .tox-dialog--fullscreen .tox-dialog__body-content { max-height: 100%; } .tox .tox-dialog--width-md { max-width: 800px; } .tox .tox-dialog--width-md .tox-dialog__body-content { overflow: auto; } .tox .tox-dialog__body-content--centered { text-align: center; } .tox .tox-dialog__footer { align-items: center; background-color: #2b3b4e; border-top: 1px solid #000000; display: flex; justify-content: space-between; padding: 8px 16px; } .tox .tox-dialog__footer-start, .tox .tox-dialog__footer-end { display: flex; } .tox .tox-dialog__busy-spinner { align-items: center; background-color: rgba(34, 47, 62, 0.75); bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; z-index: 3; } .tox .tox-dialog__table { border-collapse: collapse; width: 100%; } .tox .tox-dialog__table thead th { font-weight: bold; padding-bottom: 8px; } .tox .tox-dialog__table thead th:first-child { padding-right: 8px; } .tox .tox-dialog__table tbody tr { border-bottom: 1px solid #000000; } .tox .tox-dialog__table tbody tr:last-child { border-bottom: none; } .tox .tox-dialog__table td { padding-bottom: 8px; padding-top: 8px; } .tox .tox-dialog__table td:first-child { padding-right: 8px; } .tox .tox-dialog__iframe { min-height: 200px; } .tox .tox-dialog__iframe.tox-dialog__iframe--opaque { background: #fff; } .tox .tox-dialog__iframe.tox-dialog__iframe--bordered { border: 1px solid #000000; border-radius: 3px; } .tox .tox-dialog__popups { position: absolute; width: 100%; z-index: 1100; } .tox .tox-dialog__body-iframe { display: flex; flex: 1; flex-direction: column; } .tox .tox-dialog__body-iframe .tox-navobj { display: flex; flex: 1; } .tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { flex: 1; height: 100%; } .tox .tox-dialog-dock-fadeout { opacity: 0; visibility: hidden; } .tox .tox-dialog-dock-fadein { opacity: 1; visibility: visible; } .tox .tox-dialog-dock-transition { transition: visibility 0s linear 0.3s, opacity 0.3s ease; } .tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { transition-delay: 0s; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav { margin-right: 0; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child) { margin-left: 8px; } } .tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start > *, .tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end > * { margin-left: 8px; } .tox[dir=rtl] .tox-dialog__body { text-align: right; } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav { margin-left: 0; } } @media only screen and (max-width: 767px ) { body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child) { margin-right: 8px; } } .tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start > *, .tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end > * { margin-right: 8px; } body.tox-dialog__disable-scroll { overflow: hidden; } .tox .tox-dropzone-container { display: flex; flex: 1; } .tox .tox-dropzone { align-items: center; background: #fff; border: 2px dashed #000000; box-sizing: border-box; display: flex; flex-direction: column; flex-grow: 1; justify-content: center; min-height: 100px; padding: 10px; } .tox .tox-dropzone p { color: rgba(255, 255, 255, 0.5); margin: 0 0 16px 0; } .tox .tox-edit-area { display: flex; flex: 1; overflow: hidden; position: relative; } .tox .tox-edit-area::before { border: 2px solid #2D6ADF; border-radius: 4px; content: ''; inset: 0; opacity: 0; pointer-events: none; position: absolute; transition: opacity 0.15s; z-index: 1; } .tox .tox-edit-area__iframe { background-color: #fff; border: 0; box-sizing: border-box; flex: 1; height: 100%; position: absolute; width: 100%; } .tox.tox-edit-focus .tox-edit-area::before { opacity: 1; } .tox.tox-inline-edit-area { border: 1px dotted #000000; } .tox .tox-editor-container { display: flex; flex: 1 1 auto; flex-direction: column; overflow: hidden; } .tox .tox-editor-header { display: grid; grid-template-columns: 1fr min-content; z-index: 2; } .tox:not(.tox-tinymce-inline) .tox-editor-header { background-color: #222f3e; border-bottom: none; box-shadow: none; padding: 4px 0; } .tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition) { transition: box-shadow 0.5s; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { border-top: 1px solid #000000; box-shadow: none; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { background-color: #222f3e; box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); padding: 4px 0; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); } .tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty { background: none; border: none; box-shadow: none; padding: 0; } .tox-editor-dock-fadeout { opacity: 0; visibility: hidden; } .tox-editor-dock-fadein { opacity: 1; visibility: visible; } .tox-editor-dock-transition { transition: visibility 0s linear 0.25s, opacity 0.25s ease; } .tox-editor-dock-transition.tox-editor-dock-fadein { transition-delay: 0s; } .tox .tox-control-wrap { flex: 1; position: relative; } .tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, .tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, .tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { display: none; } .tox .tox-control-wrap svg { display: block; } .tox .tox-control-wrap__status-icon-wrap { position: absolute; top: 50%; transform: translateY(-50%); } .tox .tox-control-wrap__status-icon-invalid svg { fill: #c00; } .tox .tox-control-wrap__status-icon-unknown svg { fill: orange; } .tox .tox-control-wrap__status-icon-valid svg { fill: green; } .tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield, .tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield, .tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield { padding-right: 32px; } .tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap { right: 4px; } .tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield, .tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield, .tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield { padding-left: 32px; } .tox[dir=rtl] .tox-control-wrap__status-icon-wrap { left: 4px; } .tox .tox-autocompleter { max-width: 25em; } .tox .tox-autocompleter .tox-menu { box-sizing: border-box; max-width: 25em; } .tox .tox-autocompleter .tox-autocompleter-highlight { font-weight: bold; } .tox .tox-color-input { display: flex; position: relative; z-index: 1; } .tox .tox-color-input .tox-textfield { z-index: -1; } .tox .tox-color-input span { border-color: rgba(42, 55, 70, 0.2); border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; height: 24px; position: absolute; top: 6px; width: 24px; } .tox .tox-color-input span:hover:not([aria-disabled=true]), .tox .tox-color-input span:focus:not([aria-disabled=true]) { border-color: #207ab7; cursor: pointer; } .tox .tox-color-input span::before { background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), linear-gradient(-45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%), linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%); background-position: 0 0, 0 6px, 6px -6px, -6px 0; background-size: 12px 12px; border: 1px solid #2b3b4e; border-radius: 3px; box-sizing: border-box; content: ''; height: 24px; left: -1px; position: absolute; top: -1px; width: 24px; z-index: -1; } .tox .tox-color-input span[aria-disabled=true] { cursor: not-allowed; } .tox:not([dir=rtl]) .tox-color-input { /* stylelint-disable-next-line no-descending-specificity */ } .tox:not([dir=rtl]) .tox-color-input .tox-textfield { padding-left: 36px; } .tox:not([dir=rtl]) .tox-color-input span { left: 6px; } .tox[dir="rtl"] .tox-color-input { /* stylelint-disable-next-line no-descending-specificity */ } .tox[dir="rtl"] .tox-color-input .tox-textfield { padding-right: 36px; } .tox[dir="rtl"] .tox-color-input span { right: 6px; } .tox .tox-label, .tox .tox-toolbar-label { color: rgba(255, 255, 255, 0.5); display: block; font-size: 14px; font-style: normal; font-weight: normal; line-height: 1.3; padding: 0 8px 0 0; text-transform: none; white-space: nowrap; } .tox .tox-toolbar-label { padding: 0 8px; } .tox[dir=rtl] .tox-label { padding: 0 0 0 8px; } .tox .tox-form { display: flex; flex: 1; flex-direction: column; } .tox .tox-form__group { box-sizing: border-box; margin-bottom: 4px; } .tox .tox-form-group--maximize { flex: 1; } .tox .tox-form__group--error { color: #c00; } .tox .tox-form__group--collection { display: flex; } .tox .tox-form__grid { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-between; } .tox .tox-form__grid--2col > .tox-form__group { width: calc(50% - (8px / 2)); } .tox .tox-form__grid--3col > .tox-form__group { width: calc(100% / 3 - (8px / 2)); } .tox .tox-form__grid--4col > .tox-form__group { width: calc(25% - (8px / 2)); } .tox .tox-form__controls-h-stack { align-items: center; display: flex; } .tox .tox-form__group--inline { align-items: center; display: flex; } .tox .tox-form__group--stretched { display: flex; flex: 1; flex-direction: column; } .tox .tox-form__group--stretched .tox-textarea { flex: 1; } .tox .tox-form__group--stretched .tox-navobj { display: flex; flex: 1; } .tox .tox-form__group--stretched .tox-navobj :nth-child(2) { flex: 1; height: 100%; } .tox:not([dir=rtl]) .tox-form__controls-h-stack > *:not(:first-child) { margin-left: 4px; } .tox[dir=rtl] .tox-form__controls-h-stack > *:not(:first-child) { margin-right: 4px; } .tox .tox-lock.tox-locked .tox-lock-icon__unlock, .tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { display: none; } .tox .tox-textfield, .tox .tox-toolbar-textfield, .tox .tox-listboxfield .tox-listbox--select, .tox .tox-textarea, .tox .tox-textarea-wrap .tox-textarea:focus { -webkit-appearance: none; -moz-appearance: none; appearance: none; background-color: #2b3b4e; border-color: #000000; border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #fff; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; line-height: 24px; margin: 0; min-height: 34px; outline: none; padding: 5px 4.75px; resize: none; width: 100%; } .tox .tox-textfield[disabled], .tox .tox-textarea[disabled] { background-color: #222f3e; color: rgba(255, 255, 255, 0.85); cursor: not-allowed; } .tox .tox-textfield:focus, .tox .tox-dialog__iframe.tox-dialog__iframe--bordered:focus-within, .tox .tox-listboxfield .tox-listbox--select:focus, .tox .tox-textarea-wrap:focus-within, .tox .tox-textarea:focus, .tox .tox-custom-editor:focus-within { background-color: #2b3b4e; border-color: #207ab7; box-shadow: none; outline: 2px solid rgba(32, 122, 183, 0.25); } .tox .tox-toolbar-textfield { border-width: 0; margin-bottom: 3px; margin-top: 2px; max-width: 250px; } .tox .tox-naked-btn { background-color: transparent; border: 0; border-color: transparent; box-shadow: unset; color: #207ab7; cursor: pointer; display: block; margin: 0; padding: 0; } .tox .tox-naked-btn svg { display: block; fill: #fff; } .tox:not([dir=rtl]) .tox-toolbar-textfield + * { margin-left: 4px; } .tox[dir=rtl] .tox-toolbar-textfield + * { margin-right: 4px; } .tox .tox-listboxfield { cursor: pointer; position: relative; } .tox .tox-listboxfield .tox-listbox--select[disabled] { background-color: #19232e; color: rgba(255, 255, 255, 0.85); cursor: not-allowed; } .tox .tox-listbox__select-label { cursor: default; flex: 1; margin: 0 4px; } .tox .tox-listbox__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; } .tox .tox-listbox__select-chevron svg { fill: #fff; } .tox .tox-listboxfield .tox-listbox--select { align-items: center; display: flex; } .tox:not([dir=rtl]) .tox-listboxfield svg { right: 8px; } .tox[dir=rtl] .tox-listboxfield svg { left: 8px; } .tox .tox-selectfield { cursor: pointer; position: relative; } .tox .tox-selectfield select { -webkit-appearance: none; -moz-appearance: none; appearance: none; background-color: #2b3b4e; border-color: #000000; border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; color: #fff; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; line-height: 24px; margin: 0; min-height: 34px; outline: none; padding: 5px 4.75px; resize: none; width: 100%; } .tox .tox-selectfield select[disabled] { background-color: #19232e; color: rgba(255, 255, 255, 0.85); cursor: not-allowed; } .tox .tox-selectfield select::-ms-expand { display: none; } .tox .tox-selectfield select:focus { background-color: #2b3b4e; border-color: #207ab7; box-shadow: none; outline: 2px solid rgba(32, 122, 183, 0.25); } .tox .tox-selectfield svg { pointer-events: none; position: absolute; top: 50%; transform: translateY(-50%); } .tox:not([dir=rtl]) .tox-selectfield select[size="0"], .tox:not([dir=rtl]) .tox-selectfield select[size="1"] { padding-right: 24px; } .tox:not([dir=rtl]) .tox-selectfield svg { right: 8px; } .tox[dir=rtl] .tox-selectfield select[size="0"], .tox[dir=rtl] .tox-selectfield select[size="1"] { padding-left: 24px; } .tox[dir=rtl] .tox-selectfield svg { left: 8px; } .tox .tox-textarea-wrap { border-color: #000000; border-radius: 3px; border-style: solid; border-width: 1px; display: flex; flex: 1; overflow: hidden; } .tox .tox-textarea { -webkit-appearance: textarea; -moz-appearance: textarea; appearance: textarea; white-space: pre-wrap; } .tox .tox-textarea-wrap .tox-textarea { border: none; } .tox .tox-textarea-wrap .tox-textarea:focus { border: none; } .tox-fullscreen { border: 0; height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; padding: 0; touch-action: pinch-zoom; width: 100%; } .tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { display: none; } .tox.tox-tinymce.tox-fullscreen, .tox-shadowhost.tox-fullscreen { left: 0; position: fixed; top: 0; z-index: 1200; } .tox.tox-tinymce.tox-fullscreen { background-color: transparent; } .tox-fullscreen .tox.tox-tinymce-aux, .tox-fullscreen ~ .tox.tox-tinymce-aux { z-index: 1201; } .tox .tox-help__more-link { list-style: none; margin-top: 1em; } .tox .tox-imagepreview { background-color: #666; height: 380px; overflow: hidden; position: relative; width: 100%; } .tox .tox-imagepreview.tox-imagepreview__loaded { overflow: auto; } .tox .tox-imagepreview__container { display: flex; left: 100vw; position: absolute; top: 100vw; } .tox .tox-imagepreview__image { background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); } .tox .tox-image-tools .tox-spacer { flex: 1; } .tox .tox-image-tools .tox-bar { align-items: center; display: flex; height: 60px; justify-content: center; } .tox .tox-image-tools .tox-imagepreview, .tox .tox-image-tools .tox-imagepreview + .tox-bar { margin-top: 8px; } .tox .tox-image-tools .tox-croprect-block { background: black; filter: alpha(opacity=50); opacity: 0.5; position: absolute; zoom: 1; } .tox .tox-image-tools .tox-croprect-handle { border: 2px solid white; height: 20px; left: 0; position: absolute; top: 0; width: 20px; } .tox .tox-image-tools .tox-croprect-handle-move { border: 0; cursor: move; position: absolute; } .tox .tox-image-tools .tox-croprect-handle-nw { border-width: 2px 0 0 2px; cursor: nw-resize; left: 100px; margin: -2px 0 0 -2px; top: 100px; } .tox .tox-image-tools .tox-croprect-handle-ne { border-width: 2px 2px 0 0; cursor: ne-resize; left: 200px; margin: -2px 0 0 -20px; top: 100px; } .tox .tox-image-tools .tox-croprect-handle-sw { border-width: 0 0 2px 2px; cursor: sw-resize; left: 100px; margin: -20px 2px 0 -2px; top: 200px; } .tox .tox-image-tools .tox-croprect-handle-se { border-width: 0 2px 2px 0; cursor: se-resize; left: 200px; margin: -20px 0 0 -20px; top: 200px; } .tox .tox-insert-table-picker { display: flex; flex-wrap: wrap; width: 170px; } .tox .tox-insert-table-picker > div { border-color: #000000; border-style: solid; border-width: 0 1px 1px 0; box-sizing: border-box; height: 17px; width: 17px; } .tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { margin: 0 -4px; } .tox .tox-insert-table-picker .tox-insert-table-picker__selected { background-color: rgba(32, 122, 183, 0.5); border-color: rgba(32, 122, 183, 0.5); } .tox .tox-insert-table-picker__label { color: #fff; display: block; font-size: 14px; padding: 4px; text-align: center; width: 100%; } .tox:not([dir=rtl]) { /* stylelint-disable-next-line no-descending-specificity */ } .tox:not([dir=rtl]) .tox-insert-table-picker > div:nth-child(10n) { border-right: 0; } .tox[dir=rtl] { /* stylelint-disable-next-line no-descending-specificity */ } .tox[dir=rtl] .tox-insert-table-picker > div:nth-child(10n+1) { border-right: 0; } .tox { /* stylelint-disable */ /* stylelint-enable */ } .tox .tox-menu { background-color: #2b3b4e; border: 1px solid #000000; border-radius: 3px; box-shadow: 0 4px 8px 0 rgba(42, 55, 70, 0.1); display: inline-block; overflow: hidden; vertical-align: top; z-index: 1150; } .tox .tox-menu.tox-collection.tox-collection--list { padding: 0 0; } .tox .tox-menu.tox-collection.tox-collection--toolbar { padding: 4px; } .tox .tox-menu.tox-collection.tox-collection--grid { padding: 4px; } @media only screen and (min-width: 768px ) { .tox .tox-menu .tox-collection__item-label { overflow-wrap: break-word; word-break: normal; } } .tox .tox-menu__label h1, .tox .tox-menu__label h2, .tox .tox-menu__label h3, .tox .tox-menu__label h4, .tox .tox-menu__label h5, .tox .tox-menu__label h6, .tox .tox-menu__label p, .tox .tox-menu__label blockquote, .tox .tox-menu__label code { margin: 0; } .tox .tox-menubar { background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0 #222f3e; background-color: #222f3e; display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: wrap; grid-column: 1 / -1; grid-row: 1; padding: 0 4px 0 4px; } .tox .tox-promotion + .tox-menubar { grid-column: 1; } .tox .tox-promotion { background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0 #222f3e; background-color: #222f3e; grid-column: 2; grid-row: 1; padding-inline-end: 8px; padding-inline-start: 4px; padding-top: 5px; } .tox .tox-promotion-link { align-items: unsafe center; background-color: #E8F1F8; border-radius: 5px; color: #086BE6; cursor: pointer; display: flex; font-size: 14px; height: 26.6px; padding: 4px 8px; white-space: nowrap; } .tox .tox-promotion-link:hover { background-color: #B4D7FF; } .tox .tox-promotion-link:focus { background-color: #D9EDF7; } /* Deprecated. Remove in next major release */ .tox .tox-mbtn { align-items: center; background: transparent; border: 0; border-radius: 3px; box-shadow: none; color: #fff; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 34px; justify-content: center; margin: 2px 0 3px 0; outline: none; overflow: hidden; padding: 0 4px; text-transform: none; width: auto; } .tox .tox-mbtn[disabled] { background-color: transparent; border: 0; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-mbtn:focus:not(:disabled) { background: #4a5562; border: 0; box-shadow: none; color: #fff; } .tox .tox-mbtn--active { background: #757d87; border: 0; box-shadow: none; color: #fff; } .tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { background: #4a5562; border: 0; box-shadow: none; color: #fff; } .tox .tox-mbtn__select-label { cursor: default; font-weight: normal; margin: 0 4px; } .tox .tox-mbtn[disabled] .tox-mbtn__select-label { cursor: not-allowed; } .tox .tox-mbtn__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; display: none; } .tox .tox-notification { border-radius: 3px; border-style: solid; border-width: 1px; box-shadow: none; box-sizing: border-box; display: grid; font-size: 14px; font-weight: normal; grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); margin-top: 4px; opacity: 0; padding: 4px; transition: transform 100ms ease-in, opacity 150ms ease-in; } .tox .tox-notification p { font-size: 14px; font-weight: normal; } .tox .tox-notification a { cursor: pointer; text-decoration: underline; } .tox .tox-notification--in { opacity: 1; } .tox .tox-notification--success { background-color: #334840; border-color: #3c5440; color: #fff; } .tox .tox-notification--success p { color: #fff; } .tox .tox-notification--success a { color: #b5d199; } .tox .tox-notification--success svg { fill: #fff; } .tox .tox-notification--error { background-color: #442632; border-color: #55212b; color: #fff; } .tox .tox-notification--error p { color: #fff; } .tox .tox-notification--error a { color: #e68080; } .tox .tox-notification--error svg { fill: #fff; } .tox .tox-notification--warn, .tox .tox-notification--warning { background-color: #222f3e; border-color: #000000; color: #fff0b3; } .tox .tox-notification--warn p, .tox .tox-notification--warning p { color: #fff0b3; } .tox .tox-notification--warn a, .tox .tox-notification--warning a { color: #ffcc00; } .tox .tox-notification--warn svg, .tox .tox-notification--warning svg { fill: #fff0b3; } .tox .tox-notification--info { background-color: #254161; border-color: #264972; color: #fff; } .tox .tox-notification--info p { color: #fff; } .tox .tox-notification--info a { color: #83b7f3; } .tox .tox-notification--info svg { fill: #fff; } .tox .tox-notification__body { align-self: center; color: #fff; font-size: 14px; grid-column-end: 3; grid-column-start: 2; grid-row-end: 2; grid-row-start: 1; text-align: center; white-space: normal; word-break: break-all; word-break: break-word; } .tox .tox-notification__body > * { margin: 0; } .tox .tox-notification__body > * + * { margin-top: 1rem; } .tox .tox-notification__icon { align-self: center; grid-column-end: 2; grid-column-start: 1; grid-row-end: 2; grid-row-start: 1; justify-self: end; } .tox .tox-notification__icon svg { display: block; } .tox .tox-notification__dismiss { align-self: start; grid-column-end: 4; grid-column-start: 3; grid-row-end: 2; grid-row-start: 1; justify-self: end; } .tox .tox-notification .tox-progress-bar { grid-column-end: 4; grid-column-start: 1; grid-row-end: 3; grid-row-start: 2; justify-self: center; } .tox .tox-pop { display: inline-block; position: relative; } .tox .tox-pop--resizing { transition: width 0.1s ease; } .tox .tox-pop--resizing .tox-toolbar, .tox .tox-pop--resizing .tox-toolbar__group { flex-wrap: nowrap; } .tox .tox-pop--transition { transition: 0.15s ease; transition-property: left, right, top, bottom; } .tox .tox-pop--transition::before, .tox .tox-pop--transition::after { transition: all 0.15s, visibility 0s, opacity 0.075s ease 0.075s; } .tox .tox-pop__dialog { background-color: #222f3e; border: 1px solid #000000; border-radius: 3px; box-shadow: 0 0 2px 0 rgba(42, 55, 70, 0.2), 0 4px 8px 0 rgba(42, 55, 70, 0.15); min-width: 0; overflow: hidden; } .tox .tox-pop__dialog > *:not(.tox-toolbar) { margin: 4px 4px 4px 8px; } .tox .tox-pop__dialog .tox-toolbar { background-color: transparent; margin-bottom: -1px; } .tox .tox-pop::before, .tox .tox-pop::after { border-style: solid; content: ''; display: block; height: 0; opacity: 1; position: absolute; width: 0; } .tox .tox-pop.tox-pop--inset::before, .tox .tox-pop.tox-pop--inset::after { opacity: 0; transition: all 0s 0.15s, visibility 0s, opacity 0.075s ease; } .tox .tox-pop.tox-pop--bottom::before, .tox .tox-pop.tox-pop--bottom::after { left: 50%; top: 100%; } .tox .tox-pop.tox-pop--bottom::after { border-color: #222f3e transparent transparent transparent; border-width: 8px; margin-left: -8px; margin-top: -1px; } .tox .tox-pop.tox-pop--bottom::before { border-color: #000000 transparent transparent transparent; border-width: 9px; margin-left: -9px; } .tox .tox-pop.tox-pop--top::before, .tox .tox-pop.tox-pop--top::after { left: 50%; top: 0; transform: translateY(-100%); } .tox .tox-pop.tox-pop--top::after { border-color: transparent transparent #222f3e transparent; border-width: 8px; margin-left: -8px; margin-top: 1px; } .tox .tox-pop.tox-pop--top::before { border-color: transparent transparent #000000 transparent; border-width: 9px; margin-left: -9px; } .tox .tox-pop.tox-pop--left::before, .tox .tox-pop.tox-pop--left::after { left: 0; top: calc(50% - 1px); transform: translateY(-50%); } .tox .tox-pop.tox-pop--left::after { border-color: transparent #222f3e transparent transparent; border-width: 8px; margin-left: -15px; } .tox .tox-pop.tox-pop--left::before { border-color: transparent #000000 transparent transparent; border-width: 10px; margin-left: -19px; } .tox .tox-pop.tox-pop--right::before, .tox .tox-pop.tox-pop--right::after { left: 100%; top: calc(50% + 1px); transform: translateY(-50%); } .tox .tox-pop.tox-pop--right::after { border-color: transparent transparent transparent #222f3e; border-width: 8px; margin-left: -1px; } .tox .tox-pop.tox-pop--right::before { border-color: transparent transparent transparent #000000; border-width: 10px; margin-left: -1px; } .tox .tox-pop.tox-pop--align-left::before, .tox .tox-pop.tox-pop--align-left::after { left: 20px; } .tox .tox-pop.tox-pop--align-right::before, .tox .tox-pop.tox-pop--align-right::after { left: calc(100% - 20px); } .tox .tox-sidebar-wrap { display: flex; flex-direction: row; flex-grow: 1; min-height: 0; } .tox .tox-sidebar { background-color: #222f3e; display: flex; flex-direction: row; justify-content: flex-end; } .tox .tox-sidebar__slider { display: flex; overflow: hidden; } .tox .tox-sidebar__pane-container { display: flex; } .tox .tox-sidebar__pane { display: flex; } .tox .tox-sidebar--sliding-closed { opacity: 0; } .tox .tox-sidebar--sliding-open { opacity: 1; } .tox .tox-sidebar--sliding-growing, .tox .tox-sidebar--sliding-shrinking { transition: width 0.5s ease, opacity 0.5s ease; } .tox .tox-selector { background-color: #4099ff; border-color: #4099ff; border-style: solid; border-width: 1px; box-sizing: border-box; display: inline-block; height: 10px; position: absolute; width: 10px; } .tox.tox-platform-touch .tox-selector { height: 12px; width: 12px; } .tox .tox-slider { align-items: center; display: flex; flex: 1; height: 24px; justify-content: center; position: relative; } .tox .tox-slider__rail { background-color: transparent; border: 1px solid #000000; border-radius: 3px; height: 10px; min-width: 120px; width: 100%; } .tox .tox-slider__handle { background-color: #207ab7; border: 2px solid #185d8c; border-radius: 3px; box-shadow: none; height: 24px; left: 50%; position: absolute; top: 50%; transform: translateX(-50%) translateY(-50%); width: 14px; } .tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { margin-inline-start: 8px; } .tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { margin-inline-start: 32px; } .tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { margin-inline-start: 32px; } .tox .tox-source-code { overflow: auto; } .tox .tox-spinner { display: flex; } .tox .tox-spinner > div { animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; background-color: rgba(255, 255, 255, 0.5); border-radius: 100%; height: 8px; width: 8px; } .tox .tox-spinner > div:nth-child(1) { animation-delay: -0.32s; } .tox .tox-spinner > div:nth-child(2) { animation-delay: -0.16s; } @keyframes tam-bouncing-dots { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } } .tox:not([dir=rtl]) .tox-spinner > div:not(:first-child) { margin-left: 4px; } .tox[dir=rtl] .tox-spinner > div:not(:first-child) { margin-right: 4px; } .tox .tox-statusbar { align-items: center; background-color: #222f3e; border-top: 1px solid #000000; color: #fff; display: flex; flex: 0 0 auto; font-size: 12px; font-weight: normal; height: 18px; overflow: hidden; padding: 0 8px; position: relative; text-transform: uppercase; } .tox .tox-statusbar__text-container { display: flex; flex: 1 1 auto; justify-content: flex-end; overflow: hidden; } .tox .tox-statusbar__path { display: flex; flex: 1 1 auto; margin-right: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-statusbar__path > * { display: inline; white-space: nowrap; } .tox .tox-statusbar__wordcount { flex: 0 0 auto; margin-left: 1ch; } .tox .tox-statusbar a, .tox .tox-statusbar__path-item, .tox .tox-statusbar__wordcount { color: #fff; text-decoration: none; } .tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]) { color: #fff; cursor: pointer; } .tox .tox-statusbar__branding svg { fill: rgba(255, 255, 255, 0.8); height: 1.14em; vertical-align: -0.28em; width: 3.6em; } .tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg, .tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg { fill: #fff; } .tox .tox-statusbar__resize-handle { align-items: flex-end; align-self: stretch; cursor: nwse-resize; display: flex; flex: 0 0 auto; justify-content: flex-end; margin-left: auto; margin-right: -8px; padding-bottom: 3px; padding-left: 1ch; padding-right: 3px; } .tox .tox-statusbar__resize-handle svg { display: block; fill: rgba(255, 255, 255, 0.5); } .tox .tox-statusbar__resize-handle:focus svg { background-color: #4a5562; border-radius: 1px 1px -4px 1px; box-shadow: 0 0 0 2px #4a5562; } .tox:not([dir=rtl]) .tox-statusbar__path > * { margin-right: 4px; } .tox:not([dir=rtl]) .tox-statusbar__branding { margin-left: 2ch; } .tox[dir=rtl] .tox-statusbar { flex-direction: row-reverse; } .tox[dir=rtl] .tox-statusbar__path > * { margin-left: 4px; } .tox .tox-throbber { z-index: 1299; } .tox .tox-throbber__busy-spinner { align-items: center; background-color: rgba(34, 47, 62, 0.6); bottom: 0; display: flex; justify-content: center; left: 0; position: absolute; right: 0; top: 0; } .tox .tox-tbtn { align-items: center; background: transparent; border: 0; border-radius: 3px; box-shadow: none; color: #fff; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 34px; justify-content: center; margin: 3px 0 2px 0; outline: none; overflow: hidden; padding: 0; text-transform: none; width: 34px; } .tox .tox-tbtn svg { display: block; fill: #fff; } .tox .tox-tbtn.tox-tbtn-more { padding-left: 5px; padding-right: 5px; width: inherit; } .tox .tox-tbtn:focus { background: #4a5562; border: 0; box-shadow: none; } .tox .tox-tbtn:hover { background: #4a5562; border: 0; box-shadow: none; color: #fff; } .tox .tox-tbtn:hover svg { fill: #fff; } .tox .tox-tbtn:active { background: #757d87; border: 0; box-shadow: none; color: #fff; } .tox .tox-tbtn:active svg { fill: #fff; } .tox .tox-tbtn--disabled .tox-tbtn--enabled svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-tbtn--disabled, .tox .tox-tbtn--disabled:hover, .tox .tox-tbtn:disabled, .tox .tox-tbtn:disabled:hover { background: transparent; border: 0; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-tbtn--disabled svg, .tox .tox-tbtn--disabled:hover svg, .tox .tox-tbtn:disabled svg, .tox .tox-tbtn:disabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: rgba(255, 255, 255, 0.5); } .tox .tox-tbtn--enabled, .tox .tox-tbtn--enabled:hover { background: #757d87; border: 0; box-shadow: none; color: #fff; } .tox .tox-tbtn--enabled > *, .tox .tox-tbtn--enabled:hover > * { transform: none; } .tox .tox-tbtn--enabled svg, .tox .tox-tbtn--enabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: #fff; } .tox .tox-tbtn--enabled.tox-tbtn--disabled svg, .tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { color: #fff; } .tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { fill: #fff; } .tox .tox-tbtn:active > * { transform: none; } .tox .tox-tbtn--md { height: 51px; width: 51px; } .tox .tox-tbtn--lg { flex-direction: column; height: 68px; width: 68px; } .tox .tox-tbtn--return { align-self: stretch; height: unset; width: 16px; } .tox .tox-tbtn--labeled { padding: 0 4px; width: unset; } .tox .tox-tbtn__vlabel { display: block; font-size: 10px; font-weight: normal; letter-spacing: -0.025em; margin-bottom: 4px; white-space: nowrap; } .tox .tox-number-input { border-radius: 3px; display: flex; margin: 3px 0 2px 0; padding: 0 4px; width: auto; } .tox .tox-number-input .tox-input-wrapper { background: transparent; display: flex; pointer-events: none; text-align: center; } .tox .tox-number-input .tox-input-wrapper:focus { background: #4a5562; } .tox .tox-number-input input { border-radius: 3px; color: #fff; font-size: 14px; margin: 2px 0; pointer-events: all; width: 60px; } .tox .tox-number-input input:hover { background: #4a5562; color: #fff; } .tox .tox-number-input input:focus { background: #fff; color: #2A3746; } .tox .tox-number-input input:disabled { background: transparent; border: 0; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-number-input button { background: transparent; color: #fff; height: 34px; text-align: center; width: 24px; } .tox .tox-number-input button svg { display: block; fill: #fff; margin: 0 auto; transform: scale(0.67); } .tox .tox-number-input button:focus { background: #4a5562; } .tox .tox-number-input button:hover { background: #4a5562; border: 0; box-shadow: none; color: #fff; } .tox .tox-number-input button:hover svg { fill: #fff; } .tox .tox-number-input button:active { background: #757d87; border: 0; box-shadow: none; color: #fff; } .tox .tox-number-input button:active svg { fill: #fff; } .tox .tox-number-input button:disabled { background: transparent; border: 0; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-number-input button:disabled svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-number-input button.minus { border-radius: 3px 0 0 3px; } .tox .tox-number-input button.plus { border-radius: 0 3px 3px 0; } .tox .tox-number-input:focus:not(:active) > button, .tox .tox-number-input:focus:not(:active) > .tox-input-wrapper { background: #4a5562; } .tox .tox-tbtn--select { margin: 3px 0 2px 0; padding: 0 4px; width: auto; } .tox .tox-tbtn__select-label { cursor: default; font-weight: normal; height: initial; margin: 0 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-tbtn__select-chevron { align-items: center; display: flex; justify-content: center; width: 16px; } .tox .tox-tbtn__select-chevron svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-tbtn--bespoke { background: transparent; } .tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { margin-inline-start: 0; } .tox .tox-tbtn--bespoke .tox-tbtn__select-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 7em; } .tox .tox-tbtn--disabled .tox-tbtn__select-label, .tox .tox-tbtn--select:disabled .tox-tbtn__select-label { cursor: not-allowed; } .tox .tox-split-button { border: 0; border-radius: 3px; box-sizing: border-box; display: flex; margin: 3px 0 2px 0; overflow: hidden; } .tox .tox-split-button:hover { box-shadow: 0 0 0 1px #4a5562 inset; } .tox .tox-split-button:focus { background: #4a5562; box-shadow: none; color: #fff; } .tox .tox-split-button > * { border-radius: 0; } .tox .tox-split-button__chevron { width: 16px; } .tox .tox-split-button__chevron svg { fill: rgba(255, 255, 255, 0.5); } .tox .tox-split-button .tox-tbtn { margin: 0; } .tox .tox-split-button.tox-tbtn--disabled:hover, .tox .tox-split-button.tox-tbtn--disabled:focus, .tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, .tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus { background: transparent; box-shadow: none; color: rgba(255, 255, 255, 0.5); } .tox.tox-platform-touch .tox-split-button .tox-tbtn--select { padding: 0 0px; } .tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { width: 30px; } .tox.tox-platform-touch .tox-split-button__chevron { width: 20px; } .tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color, .tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color { opacity: 0.6; } .tox .tox-toolbar-overlord { background-color: #222f3e; } .tox .tox-toolbar, .tox .tox-toolbar__primary, .tox .tox-toolbar__overflow { background-attachment: local; background-color: #222f3e; background-image: repeating-linear-gradient(#000000 0px 1px, transparent 1px 39px); background-position: center top 39px; background-repeat: no-repeat; background-size: calc(100% - 4px * 2) calc(100% - 39px); display: flex; flex: 0 0 auto; flex-shrink: 0; flex-wrap: wrap; padding: 0 0px; transform: perspective(1px); } .tox .tox-toolbar-overlord > .tox-toolbar, .tox .tox-toolbar-overlord > .tox-toolbar__primary, .tox .tox-toolbar-overlord > .tox-toolbar__overflow { background-position: center top 0px; background-size: calc(100% - 4px * 2) calc(100% - 0px); } .tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { height: 0; opacity: 0; padding-bottom: 0; padding-top: 0; visibility: hidden; } .tox .tox-toolbar__overflow--growing { transition: height 0.3s ease, opacity 0.2s linear 0.1s; } .tox .tox-toolbar__overflow--shrinking { transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; } .tox .tox-toolbar-overlord, .tox .tox-anchorbar { grid-column: 1 / -1; } .tox .tox-menubar + .tox-toolbar, .tox .tox-menubar + .tox-toolbar-overlord { border-top: 1px solid #000000; margin-top: -1px; padding-bottom: 0px; padding-top: 0px; } .tox .tox-toolbar--scrolling { flex-wrap: nowrap; overflow-x: auto; } .tox .tox-pop .tox-toolbar { border-width: 0; } .tox .tox-toolbar--no-divider { background-image: none; } .tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, .tox .tox-toolbar-overlord .tox-toolbar__primary { background-position: center top 39px; } .tox .tox-editor-header > .tox-toolbar--scrolling, .tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { background-image: none; } .tox.tox-tinymce-aux .tox-toolbar__overflow { background-color: #222f3e; background-position: center top 43px; background-size: calc(100% - 8px * 2) calc(100% - 51px); border: none; border-radius: 3px; box-shadow: 0 0 2px 0 rgba(42, 55, 70, 0.2), 0 4px 8px 0 rgba(42, 55, 70, 0.15); overscroll-behavior: none; padding: 4px 0; } .tox-pop .tox-pop__dialog { /* stylelint-disable-next-line no-descending-specificity */ } .tox-pop .tox-pop__dialog .tox-toolbar { background-position: center top 43px; background-size: calc(100% - 4px * 2) calc(100% - 51px); padding: 4px 0; } .tox .tox-toolbar__group { align-items: center; display: flex; flex-wrap: wrap; margin: 0 0; padding: 0 4px 0 4px; } .tox .tox-toolbar__group--pull-right { margin-left: auto; } .tox .tox-toolbar--scrolling .tox-toolbar__group { flex-shrink: 0; flex-wrap: nowrap; } .tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type) { border-right: 1px solid #000000; } .tox[dir=rtl] .tox-toolbar__group:not(:last-of-type) { border-left: 1px solid #000000; } .tox .tox-tooltip { display: inline-block; padding: 8px; position: relative; } .tox .tox-tooltip__body { background-color: #3d546f; border-radius: 3px; box-shadow: 0 2px 4px rgba(42, 55, 70, 0.3); color: rgba(255, 255, 255, 0.75); font-size: 14px; font-style: normal; font-weight: normal; padding: 4px 8px; text-transform: none; } .tox .tox-tooltip__arrow { position: absolute; } .tox .tox-tooltip--down .tox-tooltip__arrow { border-left: 8px solid transparent; border-right: 8px solid transparent; border-top: 8px solid #3d546f; bottom: 0; left: 50%; position: absolute; transform: translateX(-50%); } .tox .tox-tooltip--up .tox-tooltip__arrow { border-bottom: 8px solid #3d546f; border-left: 8px solid transparent; border-right: 8px solid transparent; left: 50%; position: absolute; top: 0; transform: translateX(-50%); } .tox .tox-tooltip--right .tox-tooltip__arrow { border-bottom: 8px solid transparent; border-left: 8px solid #3d546f; border-top: 8px solid transparent; position: absolute; right: 0; top: 50%; transform: translateY(-50%); } .tox .tox-tooltip--left .tox-tooltip__arrow { border-bottom: 8px solid transparent; border-right: 8px solid #3d546f; border-top: 8px solid transparent; left: 0; position: absolute; top: 50%; transform: translateY(-50%); } .tox .tox-tree { display: flex; flex-direction: column; } .tox .tox-tree .tox-trbtn { align-items: center; background: transparent; border: 0; border-radius: 4px; box-shadow: none; color: #fff; display: flex; flex: 0 0 auto; font-size: 14px; font-style: normal; font-weight: normal; height: 28px; margin-bottom: 4px; margin-top: 4px; outline: none; overflow: hidden; padding: 0; padding-left: 8px; text-transform: none; } .tox .tox-tree .tox-trbtn .tox-tree__label { cursor: default; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tox .tox-tree .tox-trbtn svg { display: block; fill: #fff; } .tox .tox-tree .tox-trbtn:focus { background: #4a5562; border: 0; box-shadow: none; } .tox .tox-tree .tox-trbtn:hover { background: #4a5562; border: 0; box-shadow: none; color: #fff; } .tox .tox-tree .tox-trbtn:hover svg { fill: #fff; } .tox .tox-tree .tox-trbtn:active { background: #6ea9d0; border: 0; box-shadow: none; color: #fff; } .tox .tox-tree .tox-trbtn:active svg { fill: #fff; } .tox .tox-tree .tox-trbtn--disabled, .tox .tox-tree .tox-trbtn--disabled:hover, .tox .tox-tree .tox-trbtn:disabled, .tox .tox-tree .tox-trbtn:disabled:hover { background: transparent; border: 0; box-shadow: none; color: rgba(255, 255, 255, 0.5); cursor: not-allowed; } .tox .tox-tree .tox-trbtn--disabled svg, .tox .tox-tree .tox-trbtn--disabled:hover svg, .tox .tox-tree .tox-trbtn:disabled svg, .tox .tox-tree .tox-trbtn:disabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: rgba(255, 255, 255, 0.5); } .tox .tox-tree .tox-trbtn--enabled, .tox .tox-tree .tox-trbtn--enabled:hover { background: #6ea9d0; border: 0; box-shadow: none; color: #fff; } .tox .tox-tree .tox-trbtn--enabled > *, .tox .tox-tree .tox-trbtn--enabled:hover > * { transform: none; } .tox .tox-tree .tox-trbtn--enabled svg, .tox .tox-tree .tox-trbtn--enabled:hover svg { /* stylelint-disable-line no-descending-specificity */ fill: #fff; } .tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) { color: #fff; } .tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg { fill: #fff; } .tox .tox-tree .tox-trbtn:active > * { transform: none; } .tox .tox-tree .tox-trbtn--return { align-self: stretch; height: unset; width: 16px; } .tox .tox-tree .tox-trbtn--labeled { padding: 0 4px; width: unset; } .tox .tox-tree .tox-trbtn__vlabel { display: block; font-size: 10px; font-weight: normal; letter-spacing: -0.025em; margin-bottom: 4px; white-space: nowrap; } .tox .tox-tree .tox-tree--directory { display: flex; flex-direction: column; /* stylelint-disable no-descending-specificity */ } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label { font-weight: bold; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn { margin-left: auto; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg { fill: transparent; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg { fill: #fff; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg { fill: #fff; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) { background-color: transparent; color: #fff; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg { fill: #fff; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron { margin-right: 6px; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--growing) .tox-chevron, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--shrinking) .tox-chevron { transition: transform 0.5s ease-in-out; } .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--growing) .tox-chevron, .tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+ .tox-tree--directory__children--open) .tox-chevron { transform: rotate(90deg); } .tox .tox-tree .tox-tree--leaf__label { font-weight: normal; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn { margin-left: auto; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg { fill: transparent; } .tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg, .tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg { fill: #fff; } .tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg { fill: #fff; } .tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) { background-color: transparent; color: #fff; } .tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg { fill: #fff; } .tox .tox-tree .tox-tree--directory__children { overflow: hidden; padding-left: 16px; } .tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing, .tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking { transition: height 0.5s ease-in-out; } .tox .tox-tree .tox-trbtn.tox-tree--leaf__label { display: flex; justify-content: space-between; } .tox .tox-view-wrap, .tox .tox-view-wrap__slot-container { background-color: #222f3e; display: flex; flex: 1; flex-direction: column; } .tox .tox-view { display: flex; flex: 1 1 auto; flex-direction: column; overflow: hidden; } .tox .tox-view__header { align-items: center; display: flex; font-size: 16px; justify-content: space-between; padding: 8px 8px 0 8px; position: relative; } .tox .tox-view--mobile.tox-view__header, .tox .tox-view--mobile.tox-view__toolbar { padding: 8px; } .tox .tox-view--scrolling { flex-wrap: nowrap; overflow-x: auto; } .tox .tox-view__toolbar { display: flex; flex-direction: row; gap: 8px; justify-content: space-between; padding: 8px 8px 0 8px; } .tox .tox-view__toolbar__group { display: flex; flex-direction: row; gap: 12px; } .tox .tox-view__header-start, .tox .tox-view__header-end { display: flex; } .tox .tox-view__pane { height: 100%; padding: 8px; width: 100%; } .tox .tox-view__pane_panel { border: 1px solid #000000; border-radius: 3px; } .tox:not([dir=rtl]) .tox-view__header .tox-view__header-start > *, .tox:not([dir=rtl]) .tox-view__header .tox-view__header-end > * { margin-left: 8px; } .tox[dir=rtl] .tox-view__header .tox-view__header-start > *, .tox[dir=rtl] .tox-view__header .tox-view__header-end > * { margin-right: 8px; } .tox .tox-well { border: 1px solid #000000; border-radius: 3px; padding: 8px; width: 100%; } .tox .tox-well > *:first-child { margin-top: 0; } .tox .tox-well > *:last-child { margin-bottom: 0; } .tox .tox-well > *:only-child { margin: 0; } .tox .tox-custom-editor { border: 1px solid #000000; border-radius: 3px; display: flex; flex: 1; overflow: hidden; position: relative; } /* stylelint-disable */ .tox { /* stylelint-enable */ } .tox .tox-dialog-loading::before { background-color: rgba(0, 0, 0, 0.5); content: ""; height: 100%; position: absolute; width: 100%; z-index: 1000; } .tox .tox-tab { cursor: pointer; } .tox .tox-dialog__content-js { display: flex; flex: 1; } .tox .tox-dialog__body-content .tox-collection { display: flex; flex: 1; } .tox:not(.tox-tinymce-inline) .tox-editor-header { background-color: none; padding: 0; } .tox.tox-tinymce--toolbar-bottom .tox-editor-header, .tox.tox-tinymce-inline .tox-editor-header { margin-bottom: -1px; } .tox.tox-tinymce-inline .tox-editor-container { overflow: hidden; } .tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { border-top: none; box-shadow: none; } .tox.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header { background-color: transparent; box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); padding: 0; } .tox.tox.tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); } .tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { margin: -4px 0; } .tox .tox-menu.tox-collection.tox-collection--list { padding: 0; } .tox .tox-pop { box-shadow: none; } .tox .tox-tbtn, .tox .tox-number-input, .tox .tox-tbtn--select, .tox .tox-split-button { margin: 2px 0 3px 0; } .tox .tox-toolbar, .tox .tox-toolbar__primary, .tox .tox-toolbar__overflow { background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0px #222f3e !important; } .tox .tox-menubar + .tox-toolbar-overlord { border-top: none; } .tox .tox-menubar + .tox-toolbar, .tox .tox-menubar + .tox-toolbar-overlord .tox-toolbar__primary { border-top: 1px solid #000000; margin-top: -1px; } .tox.tox-tinymce-aux .tox-toolbar__overflow { border: 1px solid #000000; padding: 0; } .tox .tox-pop .tox-pop__dialog .tox-toolbar { padding: 0; } .tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { border-top: 1px solid #000000; } .tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar-overlord:first-child .tox-toolbar__primary, .tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child { border-top: 1px solid #000000; } .tox .tox-toolbar__group { padding: 0 4px 0 4px; } .tox .tox-collection__item { border-radius: 0; cursor: pointer; } .tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]), .tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]) { color: #fff; text-decoration: underline; } .tox .tox-statusbar__branding svg { vertical-align: -0.25em; } .tox:not([dir=rtl]) .tox-statusbar__branding { margin-left: 1ch; } .tox .tox-statusbar__resize-handle { padding-bottom: 0; padding-right: 0; } .tox .tox-button::before { display: none; } ================================================ FILE: minimalist-vue3/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.css ================================================ body.tox-dialog__disable-scroll { overflow: hidden; } .tox-fullscreen { border: 0; height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; padding: 0; touch-action: pinch-zoom; width: 100%; } .tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { display: none; } .tox.tox-tinymce.tox-fullscreen, .tox-shadowhost.tox-fullscreen { left: 0; position: fixed; top: 0; z-index: 1200; } .tox.tox-tinymce.tox-fullscreen { background-color: transparent; } .tox-fullscreen .tox.tox-tinymce-aux, .tox-fullscreen ~ .tox.tox-tinymce-aux { z-index: 1201; } ================================================ FILE: minimalist-vue3/src/App.vue ================================================ ================================================ FILE: minimalist-vue3/src/api/config.js ================================================ import axios from '~/axios' //添加参数 export function addConfigApi(data) { return axios.post('/basic/config/addConfig', data) } //删除参数 export function deleteConfigByConfigIdApi(configId) { return axios({ method: 'DELETE', url: '/basic/config/deleteConfigByConfigId', params: { configId: configId } }) } //修改参数 export function updateConfigByConfigIdApi(data) { return axios.put('/basic/config/updateConfigByConfigId', data) } //获取参数列表 - 分页 export function getPageConfigListApi(params) { return axios({ method: 'GET', url: '/basic/config/getPageConfigList', params: params }) } //获取参数详细信息 export function getConfigByConfigIdApi(configId) { return axios.get(`/basic/config/getConfigByConfigId/${configId}`) } ================================================ FILE: minimalist-vue3/src/api/dept.js ================================================ import axios from '~/axios' //添加部门 export function addDeptApi(data) { return axios.post('/basic/dept/addDept', data) } //删除部门 export function deleteDeptByDeptIdApi(deptId) { return axios({ method: 'DELETE', url: '/basic/dept/deleteDeptByDeptId', params: { deptId: deptId } }) } //修改部门 export function updateDeptByDeptIdApi(data) { return axios.put('/basic/dept/updateDeptByDeptId', data) } //获取部门树 -> 部门管理中使用 export function getDeptListApi(params) { return axios({ method: 'GET', url: '/basic/dept/getDeptList', params: params }) } //获取部门树(只查询状态为正常的部门) export function getEnableDeptListApi() { return axios.get("/basic/dept/getEnableDeptList") } //获取部门详细信息 export function getDeptByDeptIdApi(deptId) { return axios.get(`/basic/dept/getDeptByDeptId/${deptId}`) } ================================================ FILE: minimalist-vue3/src/api/dict.js ================================================ import axios from '~/axios' //获取字典列表 - 分页 export function getPageDictListApi(params) { return axios({ method: 'GET', url: '/basic/dict/getPageDictList', params: params }) } //添加字典 export function addDictApi(data) { return axios.post('/basic/dict/addDict', data) } //根据字典类型查询字典 - 单个类型 export function getDictByDictTypeApi(dictType) { return axios.get(`/basic/dict/getDictByDictType/${dictType}`) } //根据字典类型查询字典 - 多个类型 export function getDictByDictTypeListApi(dictTypes) { return axios.get(`/basic/dict/getDictList/${dictTypes}`) } //删除字典 -> 根据字典类型删除 export function deleteDictByDictTypeApi(dictType) { return axios({ method: 'DELETE', url: '/basic/dict/deleteDictByDictType', params: { dictType: dictType } }) } //删除字典 -> 根据字典ID删除 export function deleteDictByDictIdApi(dictId) { return axios({ method: 'DELETE', url: '/basic/dict/deleteDictByDictId', params: { dictId: dictId } }) } //修改字典 export function updateDictApi(data) { return axios.put('/basic/dict/updateDictByDictId', data) } ================================================ FILE: minimalist-vue3/src/api/file.js ================================================ import axios from '~/axios' //上传文件 export function uploadFileApi(data, onUploadProgress) { return axios.post('/basic/file/uploadFile', data, { onUploadProgress:(e)=>{ //获取上传进度 if (onUploadProgress) { onUploadProgress(e) } } }) } //删除文件 -> 根据文件URL删除 export function deleteFileApi(fileId) { return axios({ method: 'DELETE', url: '/basic/file/deleteFile', params: { fileId: fileId } }) } //获取文件列表 - 分页 export function getPageFileListApi(params) { return axios({ method: 'GET', url: '/basic/file/getPageFileList', params: params }) } ================================================ FILE: minimalist-vue3/src/api/notice.js ================================================ import axios from '~/axios' //添加公告 export function addNoticeApi(data) { return axios.post('/basic/notice/addNotice', data) } //删除公告 export function deleteNoticeByNoticeIdApi(noticeId) { return axios({ method: 'DELETE', url: '/basic/notice/deleteNoticeByNoticeId', params: { noticeId: noticeId } }) } //修改公告 export function updateNoticeByNoticeIdApi(data) { return axios.put('/basic/notice/updateNoticeByNoticeId', data) } //获取公告列表 - 分页 -> 公告管理使用 export function getPageNoticeListApi(params) { return axios({ method: 'GET', url: '/basic/notice/getPageNoticeList', params: params }) } //获取公告列表 - 分页 -> 首页使用 export function getPageHomeNoticeListApi(params) { return axios({ method: 'GET', url: '/basic/notice/getPageHomeNoticeList', params: params }) } //获取公告详细信息 export function getNoticeByNoticeIdApi(noticeId) { return axios.get(`/basic/notice/getNoticeByNoticeId/${noticeId}`) } ================================================ FILE: minimalist-vue3/src/api/perm.js ================================================ import axios from '~/axios' //权限类型 export const permType = { M: {key: 'M', value: '菜单'}, B: {key: 'B', value: '按钮'} } //添加权限 export function addPermApi(data) { return axios.post('/basic/permission/addPerm', data) } //删除权限 export function deletePermByPermIdApi(permId) { return axios({ method: 'DELETE', url: '/basic/permission/deletePermByPermId', params: { permId: permId } }) } //修改权限 export function updatePermByPermIdApi(data) { return axios.put('/basic/permission/updatePermByPermId', data) } //获取权限树 export function getPermListApi(params) { return axios({ method: 'GET', url: '/basic/permission/getPermList', params: params }) } //获取系统租户权限树(只查询启用的权限) export function getEnablePermListApi() { return axios.get("/basic/permission/getEnablePermList") } //获取租户权限树(只查询启用的权限) export function getTenantEnablePermListApi() { return axios.get("/basic/permission/getTenantEnablePermList") } //获取权限详细信息 export function getPermByPermIdApi(permId) { return axios.get(`/basic/permission/getPermByPermId/${permId}`) } ================================================ FILE: minimalist-vue3/src/api/post.js ================================================ import axios from '~/axios' //添加岗位 export function addPostApi(data) { return axios.post('/basic/post/addPost', data) } //删除岗位 export function deletePostByPostIdApi(postId) { return axios({ method: 'DELETE', url: '/basic/post/deletePostByPostId', params: { postId: postId } }) } //修改岗位 export function updatePostByPostIdApi(data) { return axios.put('/basic/post/updatePostByPostId', data) } //获取岗位列表 - 分页 export function getPagePostListApi(params) { return axios({ method: 'GET', url: '/basic/post/getPagePostList', params: params }) } //获取岗位详细信息 export function getPostByPostIdApi(postId) { return axios.get(`/basic/post/getPostByPostId/${postId}`) } ================================================ FILE: minimalist-vue3/src/api/role.js ================================================ import axios from '~/axios' //添加角色 export function addRoleApi(data) { return axios.post('/basic/role/addRole', data) } //删除角色 export function deleteRoleByRoleIdApi(roleId) { return axios({ method: 'DELETE', url: '/basic/role/deleteRoleByRoleId', params: { roleId: roleId } }) } //修改角色 export function updateRoleByRoleIdApi(data) { return axios.put('/basic/role/updateRoleByRoleId', data) } //获取角色列表 - 分页 export function getPageRoleListApi(params) { return axios({ method: 'GET', url: '/basic/role/getPageRoleList', params: params }) } //获取角色详细信息 export function getRoleByRoleIdApi(roleId) { return axios.get(`/basic/role/getRoleByRoleId/${roleId}`) } ================================================ FILE: minimalist-vue3/src/api/storage.js ================================================ import axios from '~/axios' //添加存储 export function addStorageApi(data) { return axios.post('/basic/storage/addStorage', data) } //删除存储 export function deleteStorageByStorageIdApi(storageId) { return axios({ method: 'DELETE', url: '/basic/storage/deleteStorageByStorageId', params: { storageId: storageId } }) } //修改存储 export function updateStorageByStorageIdApi(data) { return axios.put('/basic/storage/updateStorageByStorageId', data) } //获取存储列表 - 分页 export function getPageStorageListApi(params) { return axios({ method: 'GET', url: '/basic/storage/getPageStorageList', params: params }) } //获取存储详细信息 export function getStorageByStorageIdApi(storageId) { return axios.get(`/basic/storage/getStorageByStorageId/${storageId}`) } ================================================ FILE: minimalist-vue3/src/api/tenant.js ================================================ import axios from '~/axios' //添加租户 export function addTenantApi(data) { return axios.post('/basic/tenant/addTenant', data) } //删除租户 export function deleteTenantByTenantIdApi(tenantId) { return axios({ method: 'DELETE', url: '/basic/tenant/deleteTenantByTenantId', params: { tenantId: tenantId } }) } //修改租户 export function updateTenantByTenantIdApi(data) { return axios.put('/basic/tenant/updateTenantByTenantId', data) } //获取租户列表 - 分页 export function getPageTenantListApi(params) { return axios({ method: 'GET', url: '/basic/tenant/getPageTenantList', params: params }) } //获取租户详细信息 export function getTenantByTenantIdApi(tenantId) { return axios.get(`/basic/tenant/getTenantByTenantId/${tenantId}`) } ================================================ FILE: minimalist-vue3/src/api/tenantPackage.js ================================================ import axios from '~/axios' //添加套餐 export function addTenantPackageApi(data) { return axios.post('/basic/tenantPackage/addTenantPackage', data) } //删除租户套餐 export function deleteTenantPackageByTenantPackageIdApi(tenantPackageId) { return axios({ method: 'DELETE', url: '/basic/tenantPackage/deleteTenantPackageByTenantPackageId', params: { tenantPackageId: tenantPackageId } }) } //修改套餐 export function updateTenantPackageByTenantPackageIdApi(data) { return axios.put('/basic/tenantPackage/updateTenantPackageByTenantPackageId', data) } //获取租户套餐列表 - 分页 export function getPageTenantPackageListApi(params) { return axios({ method: 'GET', url: '/basic/tenantPackage/getPageTenantPackageList', params: params }) } //获取租户套餐详细信息 export function getTenantPackageByTenantPackageIdApi(tenantPackageId) { return axios.get(`/basic/tenantPackage/getTenantPackageByTenantPackageId/${tenantPackageId}`) } ================================================ FILE: minimalist-vue3/src/api/user.js ================================================ import axios from '~/axios' //添加用户 export function addUserApi(data) { return axios.post('/basic/user/addUser', data) } //删除用户 export function deleteUserByUserIdApi(userId) { return axios({ method: 'DELETE', url: '/basic/user/deleteUserByUserId', params: { userId: userId } }) } //修改用户 export function updateUserByUserIdApi(data) { return axios.put('/basic/user/updateUserByUserId', data) } //获取用户列表 - 分页 export function getPageUserListApi(params) { return axios({ method: 'GET', url: '/basic/user/getPageUserList', params: params }) } //获取用户详细信息 export function getUserByUserIdApi(userId) { return axios.get(`/basic/user/getUserByUserId/${userId}`) } //获取用户信息 export function getUserInfoApi() { return axios.get('/basic/user/getUserInfo') } //获取图形验证码 export function getImageCaptchaApi() { return axios.get('/basic/user/getImageCaptcha') } //登录 export function loginApi(loginForm) { return axios.post('/basic/user/login', { username: loginForm.username, password: loginForm.password, captcha: loginForm.captcha, captchaId: loginForm.captchaId }) } //修改密码 export function resetPasswordApi(rePasswordForm) { return axios.post('/basic/user/resetPassword', { oldPassword: rePasswordForm.oldPassword, newPassword: rePasswordForm.newPassword }) } //修改用户头像 export function updateUserAvatarApi(userAvatar) { let params = new FormData(); params.append('userAvatar', userAvatar); return axios.post('/basic/user/updateUserAvatar', params) } //用户设置 -> 修改用户信息 export function updateUserInfoApi(form) { return axios.post('/basic/user/updateUserInfo', form) } //退出 export function logoutApi() { return axios.post('/basic/user/logout') } ================================================ FILE: minimalist-vue3/src/assets/globalStyle.css ================================================ /* 全局样式 */ body { margin: 0; padding: 0; width: 100%; height: 100%; } /* 过渡动画 -> 渐显/渐隐 */ /* 进入之前 */ .fade-enter-from { @apply opacity-0; } /* 进入之后 */ .fade-enter-to { @apply opacity-100; } /* 离开之前 */ .fade-leave-from { @apply opacity-100; } /* 离开之后 */ .fade-leave-to { @apply opacity-0; } .fade-enter-active,.fade-leave-active { @apply transition-all; } .fade-enter-active { transition-delay: 0.4s; } /* 配合文件选择组件 - 图片 */ .image-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 8px; /* 图片间距 */ padding: 0; margin: 0; width: 100%; } .image-item, .upload-item { aspect-ratio: 1; /* 保持1:1比例 */ position: relative; } .image-content { width: 100%; height: 100%; object-fit: cover; border-radius: 4px; } .action-buttons { position: absolute; top: 0; right: 0; left: 0; display: flex; justify-content: center; align-items: center; height: 100%; opacity: 0; background: rgba(0, 0, 0, .5); transition: opacity .1s cubic-bezier(0,0,1,1); } .action-buttons:hover { opacity: 1; } .icon-btn { border: none; padding: 3px 6px; border-radius: 4px; cursor: pointer; display: flex; color: #ffffff; font-size: 1.5em; } .upload-btn { width: 100%; height: 100%; border: 2px dashed var(--color-border-3); background: var(--color-border-2); border-radius: 4px; cursor: pointer; transition: border-color 0.3s; } .upload-btn:hover { border-color: rgb(var(--arcoblue-6)); } .upload-content { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 1.2em; color: var(--color-text-3); } .upload-icon { font-size: 1.5em; margin-bottom: 4px; } ================================================ FILE: minimalist-vue3/src/axios.js ================================================ import axios from "axios"; import Msg from '~/utils/msg'; const service = axios.create({ //基础URL baseURL: import.meta.env.VITE_API_BASE_PREFIX, //请求超时30秒 timeout: 30000 }) //请求拦截器 service.interceptors.request.use(function (config) { return config; }, function (err) { //请求错误 return Promise.reject(err); }); //响应拦截器 service.interceptors.response.use(function (response) { //对响应数据做点什么 return response.data }, function (res) { //响应错误 Msg.error(res.response.data || '请求失败') return Promise.reject(res); }); export default service ================================================ FILE: minimalist-vue3/src/components/MHeader.vue ================================================ ================================================ FILE: minimalist-vue3/src/components/MSider.vue ================================================ ================================================ FILE: minimalist-vue3/src/components/PageTabList.vue ================================================ ================================================ FILE: minimalist-vue3/src/components/dictValue/index.vue ================================================ ================================================ FILE: minimalist-vue3/src/components/iconSelect/FunctionalIcons.vue ================================================ ================================================ FILE: minimalist-vue3/src/components/iconSelect/index.vue ================================================ ================================================ FILE: minimalist-vue3/src/components/menuTree/index.vue ================================================ ================================================ FILE: minimalist-vue3/src/components/pagination/index.vue ================================================ ================================================ FILE: minimalist-vue3/src/components/tinymceEditor/index.vue ================================================ ================================================ FILE: minimalist-vue3/src/components/uploadFile/index.vue ================================================ ================================================ FILE: minimalist-vue3/src/directives/permission.js ================================================ import {hasPerm} from "~/utils/sys.js"; /** * 自定义指令 v-perm,可传递两类参数,数组和对象 * v-perm="['user:add', 'user:get']" -> 数组参数:传入权限编码 * v-perm="{ perms: [], userIds: [] }" -> 对象参数:传入权限编码 和 用户ID,为何要传入用户ID请参考 hasPerm方法的注释 */ export default { install(app) { app.directive('perm', { mounted(el, binding) { //权限列表参数 let perms = [] //用户ID参数 let userIds = [] let params = binding.value if (params instanceof Array) { perms = params } else if (params instanceof Object) { perms = params.perms userIds = params.userIds } else { throw new Error('使用v-perm指令时参数错误') } //校验权限 let checkPerm = hasPerm(perms, userIds) if (!checkPerm && el?.parentNode) { el.parentNode.removeChild(el) } } }) } } ================================================ FILE: minimalist-vue3/src/directives/role.js ================================================ import { hasRole } from "~/utils/sys.js"; /** * 自定义指令 v-role,可传递两类参数,数组和对象 * v-role="['admin', 'pm']" -> 数组参数:传入角色编码 * v-role="{ roles: [], userIds: [] }" -> 对象参数:传入角色编码 和 用户ID,为何要传入用户ID请参考 hasPerm方法的注释 */ export default { install(app) { app.directive('role', { mounted(el, binding) { //角色列表参数 let roles = [] //用户ID参数 let userIds = [] let params = binding.value if (params instanceof Array) { roles = params } else if (params instanceof Object) { roles = params.roles userIds = params.userIds } else { throw new Error('使用v-role指令时参数错误') } //校验角色 let checkRole = hasRole(roles, userIds) if (!checkRole && el?.parentNode) { el.parentNode.removeChild(el) } } }) } } ================================================ FILE: minimalist-vue3/src/main.js ================================================ import { createApp } from 'vue' import '~/assets/globalStyle.css' import ArcoVue from '@arco-design/web-vue'; import '@arco-design/web-vue/dist/arco.css'; import ArcoVueIcon from '@arco-design/web-vue/es/icon'; import App from './App.vue' //windicss import 'virtual:windi.css' const app = createApp(App) //全局挂载公共工具类 import Msg from '~/utils/msg' import { randomCode, operationType, yesNo, hasPerm, hasRole } from '~/utils/sys' import { LoadDicts, DICT } from '~/utils/dict' app.config.globalProperties = { //消息提示 $msg: Msg, //生成随即编码 randomCode: randomCode, //操作类型 operationType: operationType, //'是/否' 枚举 yesNo: yesNo, //字典枚举 DICT: DICT, //加载字典 LoadDicts: LoadDicts, //权限校验 hasPerm: hasPerm, //角色校验 hasRole: hasRole } //状态管理 import pinia from '~/store' app.use(pinia) //路由 import Router from './router' app.use(Router) //arco app.use(ArcoVue) //arco图标 app.use(ArcoVueIcon) //字典转换组件 import DictValue from '~/components/dictValue/index.vue' app.component('dict-convert', DictValue) //分页组件 import Pagination from '~/components/pagination/index.vue' app.component('pagination', Pagination) //自定义权限指令 import permission from "~/directives/permission.js"; app.use(permission) //自定义角色限指令 import role from "~/directives/role.js"; app.use(role) app.mount('#app') ================================================ FILE: minimalist-vue3/src/pages/404.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/config/ConfigDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/config/ConfigEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/config/ConfigMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/dept/DeptDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/dept/DeptEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/dept/DeptMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/dict/DictDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/dict/DictEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/dict/DictMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/file/FileMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/file/FileSelect.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/notice/NoticeDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/notice/NoticeEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/notice/NoticeMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/perm/PermDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/perm/PermEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/perm/PermMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/post/PostDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/post/PostEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/post/PostMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/role/RoleDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/role/RoleEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/role/RoleMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/storage/Local.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/storage/Minio.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/storage/QiNiu.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/storage/StorageDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/storage/StorageEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/storage/StorageMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/system/Swagger.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/tenant/TenantDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/tenant/TenantEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/tenant/TenantMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/tenantPackage/TenantPackageDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/tenantPackage/TenantPackageEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/tenantPackage/TenantPackageMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/user/UserDetail.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/user/UserEdit.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/user/UserMgt.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/basic/user/UserSetting.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/container.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/index.vue ================================================ ================================================ FILE: minimalist-vue3/src/pages/login.vue ================================================ ================================================ FILE: minimalist-vue3/src/router/index.js ================================================ import {createRouter, createWebHashHistory} from "vue-router"; import {CHANGE_TENANT_ALLOW, getToken, setCookie} from "~/utils/cookie"; import Container from '~/pages/container.vue' import Index from '~/pages/index.vue' import UserSetting from '~/pages/basic/user/UserSetting.vue' import {getUserInfoApi} from "~/api/user.js"; import { useSysStore } from '~/store/module/sys-store.js' //页面加载条 import NProgress from 'nprogress' import'nprogress/nprogress.css' //登录页 import Login from '~/pages/login.vue' //404页面 import NotFound from '~/pages/404.vue' //网页标题 const pageTitle = '极简多租户管理系统' //公共路由,所有用户共享 const commonRoutes = [ { path: '/', name: 'Container', component: Container, children: [ {path: '/', component: Index, meta: {title: '控制台'}}, {path: '/user/setting', component: UserSetting, meta: {title: '用户设置'}}, ] }, {path: '/login', name: 'Login', component: Login, meta: {title: '登录'}}, {path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound, meta: {title: ''}}, ] //导入所有路由,动态加载 const routeAll = import.meta.glob(`../pages/**/*.vue`); const router = createRouter({ history: createWebHashHistory(), routes: commonRoutes }) //从路径中自动提取组件名 const getComponentNameFromPath = (path) => { // 匹配最后一个 / 后的内容,并去掉 .vue 扩展名 const match = path.match(/\/([^/.]+)\.vue$/) return match ? match[1] : null } /** * 动态添加路由 * @param menus 菜单 * @returns {boolean} */ function dynamicAddRoutes(menus) { //是否有新的路由 let hasNewRouter = false //获取已有路由 let allRouter = router.getRoutes() const findAndAddRoutesByMenus = (arr) => { //遍历菜单 arr.forEach(e => { //检查该路由是否已存在 let item = allRouter.find(o => o.path === e.permPath) //如果未查找到,则该路由不存在,进行添加 if (!item) { //如果指定了组件路径,则添加路由 if (e.component) { //查找路由 let comp = findRouter(e.component) if (comp) { //向外层路由中添加子路由 router.addRoute('Container', { path: e.permPath, meta: {title: e.permName, name: getComponentNameFromPath(e.component)}, component: comp }) hasNewRouter = true } } } //如果包含子菜单,递归执行 if (e.children && e.children.length > 0) { findAndAddRoutesByMenus(e.children) } }) } findAndAddRoutesByMenus(menus) return hasNewRouter } /** * 查找路由 * @param component 路由 * @returns import的路由 */ function findRouter(component) { for (let key in routeAll) { if (key.includes(component)) { return routeAll[key] } } //未找到路由 return null } //路由白名单 索引0为登录路由 const routerWhiteList = ['/login'] //路由前置守卫 router.beforeEach(async (to, from, next) => { //显示加载条 NProgress.start() //获取token const token = getToken() //如果已经登录 并且 还访问登录页 if (token && routerWhiteList[0] === to.path) { //有原页面继续停留在原页面,否则将跳转至首页 return next({path: from.path ? from.path : '/'}) } //白名单页面访问放行 if (routerWhiteList.includes(to.path)) { return next() } //如果未登录,将跳转到登录页进行登录 if (!token) { return next({path: routerWhiteList[0]}) } //设置页面动态标题 document.title = (to.meta.title ? to.meta.title + ' - ' : '') + pageTitle //是否有新添加的路由 let hasNewRouter = false //缓存 let useStore = useSysStore() //是否调用过getUserInfo接口,没有调用过则调用,调用后不再重复调用 let hasGetUserInfo = useStore.hasGetUserinfo //未调用过getUserInfo,就执行获取用户信息、菜单等数据 if (!hasGetUserInfo) { //获取用户信息 await getUserInfoApi().then(res => { //用户信息存储到缓存 useStore.user = res //已调用过getUserInfo useStore.hasGetUserinfo = true //渲染动态路由 hasNewRouter = dynamicAddRoutes(useStore.user.menus) //此处将校验是否允许进行租户切换操作 //目前是系统管理员角色允许操作,可以自定义调整 //在MHeader.vue中租户切换功能配合v-if="getCookie(CHANGE_TENANT_ALLOW)"来实现是否显示 //退出登录后,该cookie会被清除 let roles = res.roles || [] if (roles.includes('system_admin')) { //允许操作租户切换 setCookie(CHANGE_TENANT_ALLOW, true) } }).catch(res => { //401 认证失败,重新登录 if (res.response.status === 401) { //退出 useStore.userLogoutHandler() //跳转到登录页 return next({path: routerWhiteList[0]}) } }) } //放行,如果跳转到新添加的路由next()中需要给参数to.fullPath,否则刷新会404 hasNewRouter ? next(to.fullPath) : next() }) //路由后置守卫 router.afterEach(() => { //关闭加载条 NProgress.done() }) export default router ================================================ FILE: minimalist-vue3/src/store/index.js ================================================ import { createPinia } from 'pinia'; const pinia = createPinia(); export default pinia; ================================================ FILE: minimalist-vue3/src/store/module/sys-store.js ================================================ /** * 存储系统缓存 */ import { defineStore } from 'pinia' import { useCookies } from '@vueuse/integrations/useCookies' import { Authentication, PAGE_TAB_LIST, CHANGE_TENANT_ID, CHANGE_TENANT_ID_BASE64, CHANGE_TENANT_ALLOW } from "~/utils/cookie.js"; //命名最好以 `use` 开头且以 `Store` 结尾,(比如 `useUserStore`,`useCartStore`,`useProductStore`) //"sysStore" -> 第一个参数是应用中 Store 的唯一ID export const useSysStore = defineStore('sysStore', { state: () => ({ //用户信息 user: null, //是否调用过用户信息接口 hasGetUserinfo: false, //sider展开/缩起,false展开,true缩起 siderCollapsed: false, //sider当前宽度 siderWidth: 200, //sider展开时的宽度 siderMaxWidth: 200, //sider缩起时的宽度 siderMinWidth: 48, //缓存的页面 - 首页index默认被缓存 includePage: ['index'] }), actions: { //修改用户头像 updateUserAvatar(userAvatar) { this.user.userAvatar = userAvatar }, //用户退出登录后的处理 userLogoutHandler() { //清空cookie let cookie = useCookies() //清空请求头 cookie.remove(Authentication) //清空租户切换的租户ID cookie.remove(CHANGE_TENANT_ID) //清空租户切换的租户ID cookie.remove(CHANGE_TENANT_ID_BASE64) //清空标签页 cookie.remove(PAGE_TAB_LIST) //清空租户切换权限标记 cookie.remove(CHANGE_TENANT_ALLOW) //清除当前用户状态 this.user = null //是否获取过用户信息接口置为false this.hasGetUserinfo = false } } }) ================================================ FILE: minimalist-vue3/src/utils/cookie.js ================================================ import { useCookies } from '@vueuse/integrations/useCookies' const cookie = useCookies() //租户切换的租户ID 字符串格式 key export const CHANGE_TENANT_ID = 'change_tenant_id' //租户切换的租户ID base64格式 key export const CHANGE_TENANT_ID_BASE64 = 'change_tenant_id_base64' //标签页 key export const PAGE_TAB_LIST = 'pageTabList' //token key export const Authentication = 'Authentication' //租户切换操作权限标记 key export const CHANGE_TENANT_ALLOW = 'changeTenantAllow' //获取token export function getToken() { return cookie.get(Authentication) } //设置token export function setToken(token) { return cookie.set(Authentication, token) } //清除token export function removeToken() { return cookie.remove(Authentication) } export function getCookie(key) { return cookie.get(key) } export function setCookie(key, value) { return cookie.set(key, value) } ================================================ FILE: minimalist-vue3/src/utils/dict.js ================================================ import { getDictByDictTypeListApi } from '../api/dict' import { reactive, onMounted } from 'vue'; export const DICT = { //是/否 yesNo: 'yes-no', //字典样式 dictClass: 'dict-class', //权限类型 permType: 'perm-type', //用户性别 userSex: 'user-sex', //公告类型 noticeType: 'notice-type', //文件来源 fileSource: 'file-source', //通用状态 - 数字 commonNumberStatus: 'common-number-status', //存储类型 storageType: 'storage-type', //多租户数据隔离方式 tenantDataIsolation: 'tenant-data-isolation', /**************** 额外字典 ***************/ //租户套餐列表 -> 额外字典 tenantPackageList: 'tenant-package-list', //部门列表 -> 额外字典 deptList: 'dict-dept-list', //用户列表 -> 额外字典 userList: 'dict-user-list', //角色列表 -> 额外字典 roleList: 'dict-role-list', //岗位列表 -> 额外字典 postList: 'dict-post-list', //租户列表 -> 额外字典 tenantList: 'dict-tenant-list', //存储列表 -> 额外字典 storageList: 'storage-list' } /** * 加载字典数据 * @param dictTypeList 字典类型列表 * @return 返回一个对象,key是字典类型,value是字典数据列表 */ export const LoadDicts = (dictTypeList) => { let result = reactive({}) if (!dictTypeList || dictTypeList.length === 0) { return result; } //获取字典 onMounted(async () => { await getDictByDictTypeListApi(dictTypeList).then(res => { //处理数据 if (res && res.length > 0) { res.forEach(dict => { let dictType = dict.dictType let dictList = dict.dictList || [] dictList.forEach(d => { if (/^true|false$/.test(d.dictKey)) { //转布尔 d.dictKey = d.dictKey === 'true' } else if (isNaN(d.dictKey)) { //转字符串 d.dictKey = String(d.dictKey) } else { if (d.dictKey.length > 13) { //数字超过13位,转字符串 d.dictKey = String(d.dictKey) } else { if (d.dictKey instanceof String) { d.dictKey = String(d.dictKey) } else { //转数字 d.dictKey = Number(d.dictKey) } } } }) //存储到返回结果 result[dictType] = dictList }) } }) }); return result } ================================================ FILE: minimalist-vue3/src/utils/msg.js ================================================ import { Message } from '@arco-design/web-vue'; export default { success(msg) { Message.success(msg || '操作成功') }, error(msg) { Message.error(msg || '操作失败') } } ================================================ FILE: minimalist-vue3/src/utils/sys.js ================================================ import pinia from '../store' import { useSysStore } from '../store/module/sys-store.js' //缓存 const sysStore = useSysStore(pinia) //公共的状态 export const status = { status_0: {key: 0, value: '禁用'}, status_1: {key: 1, value: '正常'} } //全局 - '是/否' 枚举 export const yesNo = { yes: {key: true, value: '是'}, no: {key: false, value: '否'} } //文件类型 export const fileType = { image: {key: 'image', value: '图片'}, video: {key: 'video', value: '视频'} } //全局 - '文件来源' 枚举 export const fileSource = { notice_cover_img: {key: 1, value: '系统公告封面图片'}, notice_content_img: {key: 2, value: '系统公告内容图片'}, } //全局 - '文件类型' 枚举 export const fileAccept = { //图片允许的类型 img: '.jpg,.jpeg,.png,.jfif,.bmp,.webp', //视频允许的类型 video: '.mp4,.avi,.mov,.flv,.mpeg,.3gp,.rmvb,.ts', } //全局 - '上传文件列表样式' 枚举 export const fileListType = { text: 'text', picture: 'picture', pictureCard: 'picture-card' } //操作类型 export const operationType = { //新增 add: {type: 'add', success: '添加成功', error: '添加失败'}, //修改 update: {type: 'update', success: '修改成功', error: '修改失败'}, //查看详情 detail: {type: 'detail'}, //删除 delete: {type: 'delete', success: '删除成功', error: '删除失败'}, //上传 upload: {type: 'upload', success: '上传成功', error: '上传失败'}, //操作 operation: {type: 'operation', success: '操作成功', error: '操作失败'} } /** * 获取所有树中的父ID(只要有子集,就视为是父节点) * @param allTree 树 * @param key 父ID的key名称 * @returns [] 父ID */ export const getAllTreeParentId = (allTree, key) => { //所有父ID let allId = [] const findAllTree = (arr) => { arr.forEach(node => { //如果包含子集,递归执行 if (node.children && node.children.length > 0) { //有子集,放入返回结果 allId.push(node[key]) //递归 findAllTree(node.children) } }) } findAllTree(allTree) return allId } //0~9 const characters = '0123456789'; /** * 生成随机编码 * @param length 编码位数 */ export const randomCode = (length) => { let result = ''; const charactersLength = characters.length; for (let i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; } /** * 视频类型处理 * @param url 视频url * @returns {`video/${string}`} */ export const videoTypeHandler = (url) => { let type = url.split('.').pop().toLowerCase() return `video/${type}` } /** * 检查权限,不止按照权限标识检查,若 userIdArr 中任意数据与当前登录用户一致,则放行 * 场景举例:假设有一个项目管理系统,有一个产品需求列表,有很多行数据, * 当某一行数据的产品经理 = 当前登录的用户时,才显示修改和删除按钮,其余数据隐藏按钮 * @param permArr 权限标识数组 * @param userIdArr 放行的用户ID */ export const hasPerm = (permArr = [], userIdArr = []) => { return checkPermOrRole(permArr, userIdArr, 'perm') } /** * 检查角色,不止按照角色标识检查,若 userIdArr 中任意数据与当前登录用户一致,则放行 * 场景举例:假设有一个项目管理系统,有一个产品需求列表,有很多行数据, * 当某一行数据的产品经理 = 当前登录的用户时,才显示修改和删除按钮,其余数据隐藏按钮 * @param roleArr 角色标识数组 * @param userIdArr 放行的用户ID */ export const hasRole = (roleArr = [], userIdArr = []) => { return checkPermOrRole(roleArr, userIdArr, 'role') } const checkPermOrRole = (checkArr = [], userIdArr = [], checkType) => { //当前登录用户ID let currentLoginUserId = sysStore.user.userId //传入的用户ID,与当前登录用户一致,则放行 let checkUser = userIdArr.includes(currentLoginUserId) if (checkUser) { return true } //校验权限或角色 let arr = checkType === 'role' ? sysStore.user.roles : sysStore.user.perms return checkArr.some(elem => arr.includes(elem)) } ================================================ FILE: minimalist-vue3/vite.config.js ================================================ import {defineConfig, loadEnv} from 'vite' import vue from '@vitejs/plugin-vue' import WindiCSS from 'vite-plugin-windicss' import path from 'path' export default defineConfig(({command, mode }) => { //获取.env文件里定义的环境变量 const env = loadEnv(mode, process.cwd()); return { resolve: { //别名配置 alias: { //输入 ~ ,相当于src目录 '~': path.resolve(__dirname, 'src') } }, //本地运行配置 server: { //代理 proxy: { //请求 /minimalist,相当于请求 env.VITE_REQUEST_URL '/minimalist': { target: env.VITE_REQUEST_URL, //允许跨域 changeOrigin: true, //规则匹配 rewrite: (path) => path.replace(/^\/minimalist/, '') } } }, plugins: [vue(), WindiCSS()], } }) ================================================ FILE: pom.xml ================================================ 4.0.0 com.cn minimalist-saas 1.0.0-SNAPSHOT pom minimalist-basic minimalist-application 3.1.1 3.36.0 8.0.33 1.9.7 1.8.3 4.0.3 4.3.1 7.18.0 5.8.32 1.39.0 4.1.0 2.2.1 3.3.2 0.4.20 0.1.6 17 17 17 minimalist-saas-backend UTF-8 org.springframework.boot spring-boot-dependencies ${springboot.version} pom import org.springframework.boot spring-boot-starter-test test ================================================ FILE: resources/sql/mysql/2024-12-03 ~ 2025-03-12期间的SQL变更(第一次使用本项目忽略).sql ================================================ -- 修改为mybatis flex框架后,deleted字段由 "0已删除 1未删除" 调整为 "0未删除 1已删除" ALTER TABLE `minimalist`.`m_config` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; ALTER TABLE `minimalist`.`m_dept` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; ALTER TABLE `minimalist`.`m_dict` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; ALTER TABLE `minimalist`.`m_file` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; ALTER TABLE `minimalist`.`m_notice` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; ALTER TABLE `minimalist`.`m_perms` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; ALTER TABLE `minimalist`.`m_post` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; ALTER TABLE `minimalist`.`m_role` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; ALTER TABLE `minimalist`.`m_storage` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; ALTER TABLE `minimalist`.`m_tenant_package` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; ALTER TABLE `minimalist`.`m_user` MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除' AFTER `update_time`; -- 文件表删除 storage_type 存储类型 字段 ALTER TABLE `minimalist`.`m_file` DROP COLUMN `storage_type`; -- 文件表增加 storage_id 存储ID字段 ALTER TABLE `minimalist`.`m_file` ADD COLUMN `storage_id` bigint(0) NULL COMMENT '存储ID' AFTER `file_th_url`; -- 存储表删除 storage_default 默认存储字段 ALTER TABLE `minimalist`.`m_storage` DROP COLUMN `storage_default`; -- 租户表增加 data_isolation(数据隔离方式)、 datasource(数据源名称)、storage_id(存储ID) 字段 ALTER TABLE m_tenant ADD COLUMN `data_isolation` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'column' COMMENT '数据隔离方式 column字段隔离(默认) db数据库隔离' AFTER `account_count`, ADD COLUMN `datasource` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'master' COMMENT '数据源名称 master(默认使用主库) ' AFTER `data_isolation`, ADD COLUMN `storage_id` bigint(0) NULL DEFAULT NULL COMMENT '存储ID 表示该租户使用哪个文件存储' AFTER `datasource`; -- 租户表字段顺序、字段默认值、注释调整 ALTER TABLE m_tenant MODIFY COLUMN `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注' AFTER `storage_id`, MODIFY COLUMN `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常' AFTER `remark`, MODIFY COLUMN `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', MODIFY COLUMN `version` int(0) NULL DEFAULT 0 COMMENT '版本号'; -- 新增 m_tenant_datasource 租户数据源表,目的是同时支持租户字段隔离和数据源隔离 DROP TABLE IF EXISTS `m_tenant_datasource`; CREATE TABLE `m_tenant_datasource` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `datasource_id` bigint(0) NOT NULL COMMENT '数据源ID', `tenant_id` bigint(0) NOT NULL COMMENT '租户ID', `datasource_name` varchar(24) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '数据源名称', `datasource_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '数据源连接', `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '数据源用户名', `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '数据源密码', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '租户数据源表' ROW_FORMAT = Dynamic; -- 新增七牛云存储数据 INSERT INTO `minimalist`.`m_storage`(`storage_id`, `storage_name`, `storage_type`, `description`, `storage_config`, `status`, `create_id`, `create_time`, `update_id`, `update_time`, `deleted`, `version`) VALUES (1891827317205766144, '七牛云2', 'qiniu', NULL, '{\"accessKey\":\"2222\",\"secretKey\":\"2222\",\"endPoint\":\"2222\",\"bucketName\":\"2222\",\"regionId\":\"2222\"}', 1, 0, '2025-02-18 20:29:15.000000', 0, '2025-02-18 20:29:56.000000', b'0', 2); -- 新增字典数据 INSERT INTO `minimalist`.`m_dict`(`dict_id`, `dict_type`, `dict_key`, `dict_value`, `dict_name`, `dict_desc`, `dict_order`, `dict_class`, `status`, `create_id`, `create_time`, `update_id`, `update_time`, `deleted`, `version`) VALUES (1890393477224509440, 'tenant-data-isolation', 'column', '字段隔离', '租户数据隔离方式', '多租户隔离方式:字段隔离 或 数据库隔离', 1, 'green', 1, 0, '2025-02-14 21:31:41.000000', 0, '2025-02-14 21:31:41.000000', b'0', 0); INSERT INTO `minimalist`.`m_dict`(`dict_id`, `dict_type`, `dict_key`, `dict_value`, `dict_name`, `dict_desc`, `dict_order`, `dict_class`, `status`, `create_id`, `create_time`, `update_id`, `update_time`, `deleted`, `version`) VALUES (1890393477329367040, 'tenant-data-isolation', 'db', '数据库隔离', '租户数据隔离方式', '多租户隔离方式:字段隔离 或 数据库隔离', 2, 'arcoblue', 1, 0, '2025-02-14 21:31:41.000000', 0, '2025-02-14 21:31:41.000000', b'0', 0); INSERT INTO `minimalist`.`m_dict`(`dict_id`, `dict_type`, `dict_key`, `dict_value`, `dict_name`, `dict_desc`, `dict_order`, `dict_class`, `status`, `create_id`, `create_time`, `update_id`, `update_time`, `deleted`, `version`) VALUES (1891825581577605120, 'storage-type', 'qiniu', '七牛云', '存储类型', '存储平台,如阿里云oss、腾讯云oss、七牛云oss等', 3, 'gold', 1, 0, '2025-02-18 20:22:21.000000', 0, '2025-02-18 20:29:34.000000', b'0', 2); INSERT INTO `minimalist`.`m_dict`(`dict_id`, `dict_type`, `dict_key`, `dict_value`, `dict_name`, `dict_desc`, `dict_order`, `dict_class`, `status`, `create_id`, `create_time`, `update_id`, `update_time`, `deleted`, `version`) VALUES (1899098996038688768, 'file-type', 'image', '图片', '文件类型', '文件类型,与file表中file_type字段对应', 0, NULL, 1, 0, '2025-03-10 22:04:18.000000', 0, '2025-03-10 22:04:18.000000', b'0', 0); INSERT INTO `minimalist`.`m_dict`(`dict_id`, `dict_type`, `dict_key`, `dict_value`, `dict_name`, `dict_desc`, `dict_order`, `dict_class`, `status`, `create_id`, `create_time`, `update_id`, `update_time`, `deleted`, `version`) VALUES (1899098996160323584, 'file-type', 'video', '视频', '文件类型', '文件类型,与file表中file_type字段对应', 0, NULL, 1, 0, '2025-03-10 22:04:18.000000', 0, '2025-03-10 22:04:18.000000', b'0', 0); INSERT INTO `minimalist`.`m_dict`(`dict_id`, `dict_type`, `dict_key`, `dict_value`, `dict_name`, `dict_desc`, `dict_order`, `dict_class`, `status`, `create_id`, `create_time`, `update_id`, `update_time`, `deleted`, `version`) VALUES (1899780153331810304, 'file-source-path', '-1', 'common/', '文件来源-存储位置', '文件来源对应的存储位置,配合\"文件来源\"一起使用', 0, NULL, 1, 0, '2025-03-12 19:11:03.000000', 0, '2025-03-12 19:11:03.000000', b'0', 0); ================================================ FILE: resources/sql/mysql/minimalist_全部sql,如果是第一次使用本项目直接执行这个.sql ================================================ /* Navicat Premium Data Transfer Source Server : 优客得 Source Server Type : MySQL Source Server Version : 80024 Source Host : 117.50.179.102:12306 Source Schema : minimalist Target Server Type : MySQL Target Server Version : 80024 File Encoding : 65001 Date: 12/03/2025 22:00:20 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for m_config -- ---------------------------- DROP TABLE IF EXISTS `m_config`; CREATE TABLE `m_config` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `config_id` bigint(0) NOT NULL COMMENT '参数ID', `config_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '参数名称', `config_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '参数键名', `config_value` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '参数键值', `description` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '说明', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `create_id` bigint(0) NULL DEFAULT 0 COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT 0 COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '参数配置表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_config -- ---------------------------- INSERT INTO `m_config` VALUES (1, 1833741434936000512, '系统参数-多租户开关', 'system.config.tenant', 'true', 'true开启多租户,false关闭多租户', 1, 0, '2024-09-11 13:36:42.050638', 0, '2024-10-07 18:42:57.798908', b'0', 7); INSERT INTO `m_config` VALUES (3, 1833773478936207360, '系统参数-用户头像大小限制(kb)', 'system.config.user.avatar.size', '102400', '用户头像图片的大小,单位是kb', 1, 0, '2024-09-11 15:44:01.932583', 0, '2024-10-07 18:45:32.477747', b'0', 2); INSERT INTO `m_config` VALUES (4, 1833773744087523328, '系统参数-登录验证码是否开启', 'system.config.captcha.enable', 'true', '系统登录时的验证码,true打开,false关闭', 1, 0, '2024-09-11 15:45:05.149415', 0, '2024-10-21 21:36:23.000000', b'0', 5); -- ---------------------------- -- Table structure for m_dept -- ---------------------------- DROP TABLE IF EXISTS `m_dept`; CREATE TABLE `m_dept` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `dept_id` bigint(0) NOT NULL COMMENT '部门id', `parent_dept_id` bigint(0) NULL DEFAULT 0 COMMENT '父部门id', `ancestors` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '祖级列表', `dept_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '部门名称', `dept_leader` bigint(0) NULL DEFAULT NULL COMMENT '部门负责人', `dept_sort` int(0) NULL DEFAULT 0 COMMENT '显示顺序', `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话', `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `tenant_id` bigint(0) NULL DEFAULT NULL COMMENT '租户编号', `create_id` bigint(0) NULL DEFAULT 0 COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT 0 COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 30 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '部门表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_dept -- ---------------------------- INSERT INTO `m_dept` VALUES (5, 1677964029214371840, 0, NULL, '极简多租户', 0, 0, '10086', '123456@qq.com', 1, 0, 0, '2023-07-09 16:52:54.285322', 0, '2024-09-12 13:42:59.939494', b'0', 2); INSERT INTO `m_dept` VALUES (6, 1677964231673425920, 1677964029214371840, '1677964029214371840', '北京总部', 0, 0, '10010', '123456@qq.com', 1, 0, 0, '2023-07-09 16:53:42.555301', 0, '2024-09-12 13:55:20.471072', b'0', 2); INSERT INTO `m_dept` VALUES (7, 1677964435873116160, 1677964231673425920, '1677964029214371840,1677964231673425920', '基础架构部', 0, 20, '123456', '12121212', 1, 0, 0, '2023-07-09 16:54:31.240378', 0, '2024-09-12 13:48:55.319535', b'0', 3); INSERT INTO `m_dept` VALUES (8, 1677964531410972672, 1677964231673425920, '1677964029214371840,1677964231673425920', '产品设计部', 0, 10, '123456', '233223', 1, 0, 0, '2023-07-09 16:54:54.018152', 0, '2024-09-12 13:48:49.612112', b'0', 2); INSERT INTO `m_dept` VALUES (9, 1677964682431082496, 1677964231673425920, '1677964029214371840,1677964231673425920', '人力资源部', 0, 0, '456789', '4565346', 1, 0, 0, '2023-07-09 16:55:30.024647', 0, '2024-09-12 13:48:16.133344', b'0', 4); INSERT INTO `m_dept` VALUES (10, 1686015040692744192, 1677964231673425920, '1677964029214371840,1677964231673425920', '市场营销部', 0, 30, '123456', '123456@qq.com', 1, 0, 0, '2023-07-31 22:04:45.032834', 0, '2024-09-12 13:48:59.471250', b'0', 2); INSERT INTO `m_dept` VALUES (11, 1686019822887170048, 1677964231673425920, '1677964029214371840,1677964231673425920', '销售部', 0, 5, '1234567', '123456@qq.com', 1, 0, 0, '2023-07-31 22:23:45.167050', 0, '2024-09-12 13:48:43.809374', b'0', 3); INSERT INTO `m_dept` VALUES (12, 1686021322711560192, 1677964231673425920, '1677964029214371840,1677964231673425920', '财务部', 0, 40, '123456', '123456@qq.com', 1, 0, 0, '2023-07-31 22:29:42.752069', 0, '2024-09-12 13:49:04.612000', b'0', 2); INSERT INTO `m_dept` VALUES (13, 1686021452114227200, 1677964231673425920, '1677964029214371840,1677964231673425920', '客户服务部', 0, 50, '123456', '123456@qq.com', 1, 0, 0, '2023-07-31 22:30:13.605403', 0, '2024-09-12 13:49:08.625494', b'0', 2); INSERT INTO `m_dept` VALUES (14, 1686021621496999936, 1677964231673425920, '1677964029214371840,1677964231673425920', '运营部', 0, 60, '123456', '123456@qq.com', 1, 0, 0, '2023-07-31 22:30:53.989690', 0, '2024-09-12 13:49:16.259154', b'0', 2); INSERT INTO `m_dept` VALUES (15, 1686021776396840960, 1677964029214371840, '1677964029214371840', '河北分部', 0, 10, '123456', '123456@qq.com', 1, 0, 0, '2023-07-31 22:31:30.920687', 0, '2024-09-12 13:49:24.009569', b'0', 1); INSERT INTO `m_dept` VALUES (16, 1686349179535036416, 1686021776396840960, '1677964029214371840,1686021776396840960', '销售部', 0, 10, '123456', '123456@qq.com', 1, 0, 0, '2023-08-01 20:12:29.912108', 0, '2024-09-12 13:49:36.360331', b'0', 1); INSERT INTO `m_dept` VALUES (17, 1686349332929122304, 1686021776396840960, '1677964029214371840,1686021776396840960', '财务部', 0, 20, '123456', '123456@qq.com', 1, 0, 0, '2023-08-01 20:13:06.483608', 0, '2024-09-12 13:49:42.360847', b'0', 1); INSERT INTO `m_dept` VALUES (18, 1688102484086906880, 1686021776396840960, '1677964029214371840,1686021776396840960', '运营部', 0, 30, '13888888888', '13888888888@phone.com', 1, 0, 0, '2023-08-06 16:19:30.292609', 0, '2024-09-12 13:49:46.840120', b'0', 1); INSERT INTO `m_dept` VALUES (24, 1834773502369406976, 0, NULL, '东东胡辣汤', 1834763884364705792, 0, '11111', '11111', 1, 1834763883194494976, 1834763884364705792, '2024-09-14 09:57:46.111124', 1834763884364705792, '2024-09-14 10:01:30.581557', b'0', 1); INSERT INTO `m_dept` VALUES (25, 1834774513448329216, 1834773502369406976, '1834773502369406976', '东东胡辣汤一部', 1834763884364705792, 0, '111', '111', 1, 1834763883194494976, 1834763884364705792, '2024-09-14 10:01:48.475618', 1834763884364705792, '2024-09-14 10:01:48.475618', b'0', 0); INSERT INTO `m_dept` VALUES (26, 1834774974033240064, 1834773502369406976, '1834773502369406976', '东东胡辣汤二部', 1834763884364705792, 0, '222', '222', 1, 1834763883194494976, 1834763884364705792, '2024-09-14 10:03:37.111552', 1834763884364705792, '2024-09-14 10:03:37.111552', b'0', 0); INSERT INTO `m_dept` VALUES (27, 1836060155556687872, 0, NULL, '测试租户111', 1836055978990497792, 100, '1111111', '1111111', 1, 1836055976968843264, 1836055978990497792, '2024-09-17 23:10:28.128713', 1836055978990497792, '2024-09-17 23:10:28.128713', b'0', 0); INSERT INTO `m_dept` VALUES (28, 1836060210875363328, 1836060155556687872, '1836060155556687872', '一部', 1836059921829097472, 11, '11', '11', 1, 1836055976968843264, 1836055978990497792, '2024-09-17 23:10:41.436305', 1836055978990497792, '2024-09-17 23:10:41.436305', b'0', 0); INSERT INTO `m_dept` VALUES (29, 1836060257859956736, 1836060155556687872, '1836060155556687872', '二部', 1836060007078326272, 22, '22', '22', 1, 1836055976968843264, 1836055978990497792, '2024-09-17 23:10:52.640320', 1836055978990497792, '2024-09-17 23:10:52.640320', b'0', 0); -- ---------------------------- -- Table structure for m_dict -- ---------------------------- DROP TABLE IF EXISTS `m_dict`; CREATE TABLE `m_dict` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `dict_id` bigint(0) NULL DEFAULT NULL COMMENT '字典ID', `dict_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字典类型', `dict_key` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字典key', `dict_value` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字典value', `dict_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字典名称', `dict_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字典描述', `dict_order` int(0) NULL DEFAULT NULL COMMENT '字典排序值', `dict_class` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字典样式,对应前端Tag组件的type', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `create_id` bigint(0) NULL DEFAULT 0 COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT 0 COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 139 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字典表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_dict -- ---------------------------- INSERT INTO `m_dict` VALUES (63, 1666983160652914688, 'yes-no', 'true', '是', '是/否', '公共字典,是/否', 1, 'arcoblue', 1, 0, '2024-10-09 14:45:18.000000', 0, '2024-10-10 14:47:09.609727', b'0', 0); INSERT INTO `m_dict` VALUES (64, 1666983160652914689, 'yes-no', 'false', '否', '是/否', '公共字典,是/否', 2, 'red', 1, 0, '2024-10-09 14:45:18.000000', 0, '2024-10-10 14:47:09.732989', b'0', 0); INSERT INTO `m_dict` VALUES (66, 1667413525115789313, 'perm-type', 'M', '菜单', '权限类型', '权限管理中的权限类型', 5, 'arcoblue', 1, 0, '2024-10-09 14:45:18.000000', 0, '2023-06-28 10:58:51.929748', b'0', 0); INSERT INTO `m_dict` VALUES (67, 1667413525115789314, 'perm-type', 'B', '按钮', '权限类型', '权限管理中的权限类型', 10, 'magenta', 1, 0, '2024-10-09 14:45:18.000000', 0, '2023-06-28 10:58:51.929748', b'0', 0); INSERT INTO `m_dict` VALUES (68, 1669515928599478272, 'dict-class', 'default', '默认', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 0, 'default', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (69, 1669515928603672576, 'dict-class', 'orange', '橙', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 10, 'orange', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (70, 1669515928603672577, 'dict-class', 'gold', '金', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 20, 'gold', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (71, 1669515928603672578, 'dict-class', 'lime', '绿黄', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 40, 'lime', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (72, 1669515928603672579, 'dict-class', 'green', '绿', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 50, 'green', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (73, 1669515928603672580, 'dict-class', 'cyan', '青', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 60, 'cyan', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (74, 1669515928603672581, 'dict-class', 'blue', '蓝', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 70, 'blue', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (75, 1669515928603672582, 'dict-class', 'arcoblue', '湖蓝', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 80, 'arcoblue', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (76, 1669515928603672583, 'dict-class', 'purple', '紫', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 90, 'purple', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (77, 1669515928603672584, 'dict-class', 'pinkpurple', '紫粉', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 100, 'pinkpurple', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (78, 1669515928603672585, 'dict-class', 'magenta', '洋红', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 110, 'magenta', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (79, 1669515928603672586, 'dict-class', 'gray', '灰', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 120, 'gray', 1, 0, '2023-06-16 09:23:10.142052', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (80, 1669518820391731200, 'dict-class', 'red', '红', '字典样式', '字典管理中的字典样式,对应Tag标签的样式', 30, 'red', 1, 0, '2024-10-09 14:45:18.000000', 0, '2023-06-17 11:25:04.092472', b'0', 0); INSERT INTO `m_dict` VALUES (98, 1677961643871744000, 'user-sex', '1', '男', '用户性别', '用户管理中的用户性别', 1, 'arcoblue', 1, 0, '2023-07-09 16:43:25.575566', 0, '2023-07-09 16:43:25.575566', b'0', 0); INSERT INTO `m_dict` VALUES (99, 1677961643871744001, 'user-sex', '2', '女', '用户性别', '用户管理中的用户性别', 2, 'orange', 1, 0, '2023-07-09 16:43:25.575566', 0, '2023-07-09 16:43:25.575566', b'0', 0); INSERT INTO `m_dict` VALUES (104, 1681499349985316864, 'notice-type', '1', '公告', '系统公告类型', '系统公告中的公告类型', 0, 'arcoblue', 1, 0, '2023-07-19 11:01:00.440762', 0, '2023-07-23 22:51:26.805770', b'0', 0); INSERT INTO `m_dict` VALUES (105, 1683127629625241600, 'notice-type', '2', '新闻', '系统公告类型', '系统公告中的公告类型', 5, 'orange', 1, 0, '2024-10-09 14:45:18.000000', 0, '2023-07-23 22:51:26.805770', b'0', 0); INSERT INTO `m_dict` VALUES (108, 1683308098322038784, 'file-source', '1', '公告封面', '文件来源', '标识文件的用途,配合\"文件来源-存储位置\"一起使用', 1, 'orange', 1, 0, '2024-10-14 10:48:15.649000', 0, '2024-10-15 10:21:45.183768', b'0', 0); INSERT INTO `m_dict` VALUES (109, 1683308098322038785, 'file-source', '2', '公告内容', '文件来源', '标识文件的用途,配合\"文件来源-存储位置\"一起使用', 2, 'lime', 1, 0, '2024-10-14 10:48:19.649000', 0, '2024-10-15 10:21:45.306306', b'0', 0); INSERT INTO `m_dict` VALUES (126, 1843908761895776256, 'common-number-status', '0', '禁用', '通用状态-数字', '0禁用 1正常', 1, 'red', 1, 0, '2024-10-09 14:45:18.000000', 0, '2024-10-10 16:59:41.651688', b'0', 0); INSERT INTO `m_dict` VALUES (127, 1843908761895776257, 'common-number-status', '1', '正常', '通用状态-数字', '0禁用 1正常', 2, 'green', 1, 0, '2024-10-11 14:45:26.000000', 0, '2024-10-10 16:59:41.770223', b'0', 0); INSERT INTO `m_dict` VALUES (128, 1843932948186218496, 'storage-type', 'local', '本地', '存储类型', '存储平台,如阿里云oss、腾讯云oss、七牛云oss等', 1, 'orange', 1, 0, '2024-10-09 14:45:18.000000', 0, '2025-02-18 20:29:33.000000', b'0', 4); INSERT INTO `m_dict` VALUES (129, 1843932948186218497, 'storage-type', 'minio', 'MinIO', '存储类型', '存储平台,如阿里云oss、腾讯云oss、七牛云oss等', 2, 'blue', 1, 0, '2024-10-09 14:45:18.000000', 0, '2025-02-18 20:29:33.000000', b'0', 4); INSERT INTO `m_dict` VALUES (130, 1845016876603019264, 'file-source-path', '1', 'notice/cover/', '文件来源-存储位置', '文件来源对应的存储位置,配合\"文件来源\"一起使用', 1, NULL, 1, 0, '2024-10-15 10:13:34.000000', 0, '2025-03-12 19:11:03.000000', b'0', 4); INSERT INTO `m_dict` VALUES (131, 1845016876603019265, 'file-source-path', '2', 'notice/content/', '文件来源-存储位置', '文件来源对应的存储位置,配合\"文件来源\"一起使用', 2, NULL, 1, 0, '2024-10-15 10:13:38.000000', 0, '2025-03-12 19:11:03.000000', b'0', 4); INSERT INTO `m_dict` VALUES (133, 1890393477224509440, 'tenant-data-isolation', 'column', '字段隔离', '租户数据隔离方式', '多租户隔离方式:字段隔离 或 数据库隔离', 1, 'green', 1, 0, '2025-02-14 21:31:41.000000', 0, '2025-02-14 21:31:41.000000', b'0', 0); INSERT INTO `m_dict` VALUES (134, 1890393477329367040, 'tenant-data-isolation', 'db', '数据库隔离', '租户数据隔离方式', '多租户隔离方式:字段隔离 或 数据库隔离', 2, 'arcoblue', 1, 0, '2025-02-14 21:31:41.000000', 0, '2025-02-14 21:31:41.000000', b'0', 0); INSERT INTO `m_dict` VALUES (136, 1891825581577605120, 'storage-type', 'qiniu', '七牛云', '存储类型', '存储平台,如阿里云oss、腾讯云oss、七牛云oss等', 3, 'gold', 1, 0, '2025-02-18 20:22:21.000000', 0, '2025-02-18 20:29:34.000000', b'0', 2); INSERT INTO `m_dict` VALUES (137, 1899098996038688768, 'file-type', 'image', '图片', '文件类型', '文件类型,与file表中file_type字段对应', 0, NULL, 1, 0, '2025-03-10 22:04:18.000000', 0, '2025-03-10 22:04:18.000000', b'0', 0); INSERT INTO `m_dict` VALUES (138, 1899098996160323584, 'file-type', 'video', '视频', '文件类型', '文件类型,与file表中file_type字段对应', 0, NULL, 1, 0, '2025-03-10 22:04:18.000000', 0, '2025-03-10 22:04:18.000000', b'0', 0); INSERT INTO `m_dict` VALUES (139, 1899780153331810304, 'file-source-path', '-1', 'common/', '文件来源-存储位置', '文件来源对应的存储位置,配合\"文件来源\"一起使用', 0, NULL, 1, 0, '2025-03-12 19:11:03.000000', 0, '2025-03-12 19:11:03.000000', b'0', 0); -- ---------------------------- -- Table structure for m_file -- ---------------------------- DROP TABLE IF EXISTS `m_file`; CREATE TABLE `m_file` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `file_id` bigint(0) NOT NULL COMMENT '文件ID', `file_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '原文件名', `new_file_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '现文件名', `file_size` bigint(0) NOT NULL DEFAULT 0 COMMENT '文件大小', `file_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件类型', `file_base_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件基础路径', `file_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件相对路径', `file_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件url', `file_source` int(0) NULL DEFAULT NULL COMMENT '文件来源', `file_th_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件缩略图url', `storage_id` bigint(0) NULL DEFAULT NULL COMMENT '存储ID', `file_th_filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件缩略图文件名', `file_th_size` bigint(0) NULL DEFAULT NULL COMMENT '缩略图文件大小', `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', `tenant_id` bigint(0) NULL DEFAULT NULL COMMENT '租户ID', `status` tinyint(0) NULL DEFAULT 0 COMMENT '状态 0未使用 1已使用,默认未使用,代码中控制修改为已使用,可以定期清理未使用的文件', `create_id` bigint(0) NULL DEFAULT 0 COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT 0 COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_file_id`(`file_id`) USING BTREE COMMENT '文件ID索引', INDEX `idx_file_url`(`file_url`) USING BTREE COMMENT '文件URL索引' ) ENGINE = InnoDB AUTO_INCREMENT = 203 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '文件表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_file -- ---------------------------- INSERT INTO `m_file` VALUES (204, 1899820597440864256, '微信图片_20241122215116.jpg', '67d1916e29479ffe018772d7.jpg', 28263, 'image/jpeg', 'D:/application/minimalist-saas/', 'D:/application/minimalist-saas/common/', 'http://localhost:9090/minimalist/files/common/67d1916e29479ffe018772d7.jpg', -1, 'http://localhost:9090/minimalist/files/common/thumbnail-67d1916e29479ffe018772d7.jpg', 1843939697907720192, 'thumbnail-67d1916e29479ffe018772d7.jpg', 5286, NULL, 0, 1, 0, '2025-03-12 21:51:41.000000', 0, '2025-03-12 21:51:41.000000', b'0', 0); INSERT INTO `m_file` VALUES (205, 1899821417918029824, '微信图片_20250301225402.png', '67d1923129479ffe018772d8.png', 303148, 'image/png', 'D:/application/minimalist-saas/', 'D:/application/minimalist-saas/common/', 'http://localhost:9090/minimalist/files/common/67d1923129479ffe018772d8.png', -1, 'http://localhost:9090/minimalist/files/common/thumbnail-67d1923129479ffe018772d8.png', 1843939697907720192, 'thumbnail-67d1923129479ffe018772d8.png', 58592, NULL, 0, 1, 0, '2025-03-12 21:54:57.000000', 0, '2025-03-12 21:54:57.000000', b'0', 0); INSERT INTO `m_file` VALUES (206, 1899821823532392448, '无标题.png', '67d1929229479ffe018772d9.png', 295216, 'image/png', 'D:/application/minimalist-saas/', 'D:/application/minimalist-saas/common/', 'http://localhost:9090/minimalist/files/common/67d1929229479ffe018772d9.png', -1, 'http://localhost:9090/minimalist/files/common/thumbnail-67d1929229479ffe018772d9.png', 1843939697907720192, 'thumbnail-67d1929229479ffe018772d9.png', 92429, NULL, 0, 1, 0, '2025-03-12 21:56:34.000000', 0, '2025-03-12 21:56:34.000000', b'0', 0); -- ---------------------------- -- Table structure for m_notice -- ---------------------------- DROP TABLE IF EXISTS `m_notice`; CREATE TABLE `m_notice` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `notice_id` bigint(0) NOT NULL COMMENT '公告ID', `notice_title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '公告标题', `notice_type` tinyint(0) NOT NULL COMMENT '公告类型(1公告)', `notice_content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '公告内容', `notice_pic_file_id` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '封面图文件ID,多个使用 , 分割', `notice_top` bit(1) NULL DEFAULT b'0' COMMENT '是否置顶 0否 1是', `notice_time_interval` datetime(6) NULL DEFAULT NULL COMMENT '延时发布的时间', `notice_sort` int(0) NULL DEFAULT 0 COMMENT '排序', `notice_out_chain` bit(1) NULL DEFAULT NULL COMMENT '是否外链 0否 1是', `notice_link` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '外部跳转链接', `publish_dept_id` bigint(0) NULL DEFAULT NULL COMMENT '发布部门', `publish_author_id` bigint(0) NULL DEFAULT NULL COMMENT '发布人', `publish_time` datetime(6) NULL DEFAULT NULL COMMENT '发布时间', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `create_id` bigint(0) NULL DEFAULT 0 COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT 0 COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '通知公告表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_notice -- ---------------------------- INSERT INTO `m_notice` VALUES (16, 1849729827784355840, '极简多租户管理系统1.0.0版本发布', 1, '<p>极简多租户管理系统是一个多租户管理系统,基于SpringBoot3+Vue3的前后端分离的后台开发脚手架,具备一些常用的基础功能。</p>\n<p>演示地址:<a href="https://www.jjian.com.cn" target="_blank">https://www.jjian.com.cn</a></p>\n<p>Gitee:<a href="https://gitee.com/marlife/minimalist-saas" target="_blank">https://gitee.com/marlife/minimalist-saas</a></p>\n<p>Github:<a href="https://github.com/lmq2582609/minimalist-saas" target="_blank">https://github.com/lmq2582609/minimalist-saas</a></p>\n<p>管理员账号/密码: admin/111111</p>\n<p>租户账号/密码:dongdong/111111</p>', '1851164126132932608', b'1', NULL, 1, b'0', NULL, 1677964029214371840, 0, '2024-10-25 16:28:51.919183', 1, 0, '2024-10-25 16:28:52.000000', 0, '2024-10-29 15:28:42.000000', b'0', 12); -- ---------------------------- -- Table structure for m_perms -- ---------------------------- DROP TABLE IF EXISTS `m_perms`; CREATE TABLE `m_perms` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `perm_id` bigint(0) NOT NULL COMMENT '权限ID', `perm_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '权限标识', `perm_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '权限名称', `parent_perm_id` bigint(0) NULL DEFAULT 0 COMMENT '父权限ID', `perm_sort` int(0) NULL DEFAULT 0 COMMENT '显示顺序', `perm_path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路由地址', `perm_icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '权限图标 菜单或目录时可传图标', `perm_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'M' COMMENT '权限类型 M菜单 B按钮', `component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组件路径', `external_link` bit(1) NULL DEFAULT b'0' COMMENT '是否为外部链接 0否 1是', `visible` bit(1) NULL DEFAULT b'1' COMMENT '是否可见 0隐藏 1显示)', `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `create_id` bigint(0) NULL DEFAULT 0 COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT 0 COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 89 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '权限表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_perms -- ---------------------------- INSERT INTO `m_perms` VALUES (6, 1669336412647133184, NULL, '系统管理', 0, 20, NULL, 'IconSettings', 'M', NULL, b'0', b'1', '', 1, 0, '2023-06-15 21:29:50.202052', 0, '2023-07-26 21:42:24.834876', b'0', 4); INSERT INTO `m_perms` VALUES (7, 1669338708936298496, NULL, '用户管理', 1669336412647133184, 10, '/basic/user/mgt', 'IconUser', 'M', '/basic/user/UserMgt.vue', b'0', b'1', '', 1, 0, '2023-06-15 21:38:57.680970', 0, '2023-07-31 21:29:03.510290', b'0', 6); INSERT INTO `m_perms` VALUES (8, 1669339147886989312, NULL, '菜单权限', 1669336412647133184, 30, '/basic/perm/mgt', 'IconNav', 'M', '/basic/perm/PermMgt.vue', b'0', b'1', '', 1, 0, '2023-06-15 21:40:42.334745', 0, '2024-09-13 13:59:01.298846', b'0', 8); INSERT INTO `m_perms` VALUES (9, 1669339375922909184, NULL, '字典管理', 1669336412647133184, 50, '/basic/dict/mgt', 'IconDice', 'M', '/basic/dict/DictMgt.vue', b'0', b'1', '', 1, 0, '2023-06-15 21:41:36.702313', 0, '2023-07-31 21:29:40.385520', b'0', 6); INSERT INTO `m_perms` VALUES (15, 1673167646340120576, NULL, '角色管理', 1669336412647133184, 20, '/basic/role/mgt', 'IconUserGroup', 'M', '/basic/role/RoleMgt.vue', b'0', b'1', '', 1, 0, '2023-06-26 11:13:47.496133', 0, '2023-07-31 21:29:13.988209', b'0', 6); INSERT INTO `m_perms` VALUES (16, 1673524365792530432, NULL, '部门管理', 1669336412647133184, 40, '/basic/dept/mgt', 'IconMindMapping', 'M', '/basic/dept/DeptMgt.vue', b'0', b'1', '', 1, 0, '2023-06-27 10:51:16.041741', 0, '2023-07-31 21:29:27.845462', b'0', 5); INSERT INTO `m_perms` VALUES (17, 1673524591861321728, NULL, '岗位管理', 1669336412647133184, 45, '/basic/post/mgt', 'IconBulb', 'M', '/basic/post/PostMgt.vue', b'0', b'1', '', 1, 0, '2023-06-27 10:52:09.940810', 0, '2023-07-31 21:29:33.111096', b'0', 5); INSERT INTO `m_perms` VALUES (19, 1673863803093557248, NULL, '开发文档', 0, 10, 'https://apebbs.cn/docs/minimalist-saas/1.0.0/introduction.html', 'IconBookmark', 'M', NULL, b'1', b'1', '', 1, 0, '2023-06-28 09:20:04.200055', 0, '2024-10-29 14:59:51.000000', b'0', 6); INSERT INTO `m_perms` VALUES (20, 1676499330464649216, NULL, '租户维护', 1669336412647133184, 60, NULL, 'IconCloud', 'M', NULL, b'0', b'1', '', 1, 0, '2023-07-05 15:52:42.891799', 0, '2023-07-26 21:53:05.189805', b'0', 4); INSERT INTO `m_perms` VALUES (21, 1676499559247155200, NULL, '套餐管理', 1676499330464649216, 10, '/basic/tenantPackage/mgt', 'IconCommon', 'M', '/basic/tenantPackage/TenantPackageMgt.vue', b'0', b'1', '', 1, 0, '2023-07-05 15:53:37.437053', 0, '2023-07-31 21:29:59.129666', b'0', 5); INSERT INTO `m_perms` VALUES (22, 1676501907755405312, NULL, '租户管理', 1676499330464649216, 20, '/basic/tenant/mgt', 'IconRelation', 'M', '/basic/tenant/TenantMgt.vue', b'0', b'1', '', 1, 0, '2023-07-05 16:02:57.365341', 0, '2023-07-31 21:30:04.168813', b'0', 4); INSERT INTO `m_perms` VALUES (28, 1680749851857862656, '', '接口文档', 1669336412647133184, 100, '/basic/swagger', 'IconBook', 'M', '/basic/system/Swagger.vue', b'0', b'1', '将swagger页面嵌入到系统', 1, 0, '2023-07-17 09:22:46.162278', 0, '2024-10-17 15:44:19.846129', b'0', 4); INSERT INTO `m_perms` VALUES (29, 1681273378598850560, NULL, '系统公告', 1669336412647133184, 60, '/basic/notice/mgt', 'IconSubscribe', 'M', '/basic/notice/NoticeMgt.vue', b'0', b'1', '', 1, 0, '2023-07-18 20:03:04.663282', 0, '2023-07-31 21:30:08.721061', b'0', 2); INSERT INTO `m_perms` VALUES (30, 1683285343149096960, NULL, '文件管理', 1669336412647133184, 55, '/basic/file/mgt', 'IconFile', 'M', '/basic/file/FileMgt.vue', b'0', b'1', '', 1, 0, '2023-07-24 09:17:54.393048', 0, '2023-07-31 21:29:48.832685', b'0', 3); INSERT INTO `m_perms` VALUES (31, 1685985572129398784, 'basic:user:add', '添加用户', 1669338708936298496, 10, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:07:39.152606', 0, '2023-07-31 20:07:39.152606', b'0', 0); INSERT INTO `m_perms` VALUES (32, 1685985875515990016, 'basic:user:delete', '删除用户', 1669338708936298496, 20, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:08:51.482954', 0, '2023-07-31 20:08:51.482954', b'0', 0); INSERT INTO `m_perms` VALUES (33, 1685985977349496832, 'basic:user:update', '修改用户', 1669338708936298496, 30, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:09:15.762162', 0, '2023-07-31 20:09:15.762162', b'0', 0); INSERT INTO `m_perms` VALUES (34, 1685986276453703680, 'basic:user:get', '查询用户', 1669338708936298496, 40, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:10:27.074176', 0, '2023-07-31 20:10:27.074176', b'0', 0); INSERT INTO `m_perms` VALUES (35, 1685986566443687936, 'basic:role:add', '添加角色', 1673167646340120576, 10, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:11:36.213812', 0, '2023-07-31 20:11:36.213812', b'0', 0); INSERT INTO `m_perms` VALUES (36, 1685986702834065408, 'basic:role:delete', '删除角色', 1673167646340120576, 20, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:12:08.733552', 0, '2023-07-31 20:12:08.733552', b'0', 0); INSERT INTO `m_perms` VALUES (37, 1685986806387236864, 'basic:role:update', '修改角色', 1673167646340120576, 30, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:12:33.419706', 0, '2023-07-31 20:12:33.419706', b'0', 0); INSERT INTO `m_perms` VALUES (38, 1685986887102423040, 'basic:role:get', '查询角色', 1673167646340120576, 40, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:12:52.664113', 0, '2023-07-31 20:12:52.664113', b'0', 0); INSERT INTO `m_perms` VALUES (39, 1685987612687654912, 'basic:perm:add', '添加权限', 1669339147886989312, 10, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:15:45.657682', 0, '2023-07-31 20:15:45.657682', b'0', 0); INSERT INTO `m_perms` VALUES (40, 1685987708229705728, 'basic:perm:delete', '删除权限', 1669339147886989312, 20, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:16:08.439529', 0, '2023-07-31 20:16:08.439529', b'0', 0); INSERT INTO `m_perms` VALUES (41, 1685988419789185024, 'basic:perm:update', '修改权限', 1669339147886989312, 30, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:18:58.085960', 0, '2023-08-06 10:29:38.265543', b'0', 1); INSERT INTO `m_perms` VALUES (42, 1685988623951126528, 'basic:perm:get', '查询权限', 1669339147886989312, 40, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:19:46.761240', 0, '2023-08-06 10:29:55.392998', b'0', 1); INSERT INTO `m_perms` VALUES (43, 1685996318275985408, 'basic:dept:add', '添加部门', 1673524365792530432, 10, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:50:21.231736', 0, '2023-07-31 20:50:21.231736', b'0', 0); INSERT INTO `m_perms` VALUES (44, 1685996426530971648, 'basic:dept:delete', '删除部门', 1673524365792530432, 20, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:50:47.041079', 0, '2023-07-31 20:50:47.041079', b'0', 0); INSERT INTO `m_perms` VALUES (45, 1685996547448561664, 'basic:dept:update', '修改部门', 1673524365792530432, 30, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:51:15.869518', 0, '2023-07-31 20:51:15.869518', b'0', 0); INSERT INTO `m_perms` VALUES (46, 1685996623386435584, 'basic:dept:get', '查询部门', 1673524365792530432, 40, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:51:33.974273', 0, '2023-07-31 20:51:33.974273', b'0', 0); INSERT INTO `m_perms` VALUES (47, 1685996875623489536, 'basic:post:add', '添加岗位', 1673524591861321728, 10, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:52:34.113986', 0, '2023-07-31 20:52:34.113986', b'0', 0); INSERT INTO `m_perms` VALUES (48, 1685997536914235392, 'basic:post:delete', '删除岗位', 1673524591861321728, 20, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:55:11.777212', 0, '2023-07-31 20:55:11.777212', b'0', 0); INSERT INTO `m_perms` VALUES (49, 1685997640341577728, 'basic:post:update', '修改岗位', 1673524591861321728, 30, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:55:36.435155', 0, '2023-07-31 20:55:36.435155', b'0', 0); INSERT INTO `m_perms` VALUES (50, 1685997732956004352, 'basic:post:get', '查询岗位', 1673524591861321728, 40, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:55:58.516359', 0, '2023-07-31 20:55:58.516359', b'0', 0); INSERT INTO `m_perms` VALUES (51, 1685998041879076864, 'basic:dict:add', '添加字典', 1669339375922909184, 10, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:57:12.169238', 0, '2023-07-31 20:57:12.169238', b'0', 0); INSERT INTO `m_perms` VALUES (52, 1685998171407572992, 'basic:dict:delete', '删除字典', 1669339375922909184, 20, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:57:43.052637', 0, '2023-07-31 20:57:43.052637', b'0', 0); INSERT INTO `m_perms` VALUES (53, 1685998244715618304, 'basic:dict:update', '修改字典', 1669339375922909184, 30, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:58:00.530266', 0, '2023-07-31 20:58:00.530266', b'0', 0); INSERT INTO `m_perms` VALUES (54, 1685998340425441280, 'basic:dict:get', '查询字典', 1669339375922909184, 40, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 20:58:23.349675', 0, '2023-07-31 20:58:23.349675', b'0', 0); INSERT INTO `m_perms` VALUES (55, 1686001693859569664, 'basic:notice:add', '添加公告', 1681273378598850560, 10, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:11:42.870516', 0, '2023-07-31 21:11:42.870516', b'0', 0); INSERT INTO `m_perms` VALUES (56, 1686001770980237312, 'basic:notice:delete', '删除公告', 1681273378598850560, 20, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:12:01.257352', 0, '2023-07-31 21:12:01.257352', b'0', 0); INSERT INTO `m_perms` VALUES (57, 1686002193703165952, 'basic:notice:update', '修改公告', 1681273378598850560, 30, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:13:42.042772', 0, '2023-07-31 21:13:42.042772', b'0', 0); INSERT INTO `m_perms` VALUES (58, 1686002291338174464, 'basic:notice:get', '查询公告', 1681273378598850560, 40, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:14:05.320984', 0, '2023-07-31 21:14:05.320984', b'0', 0); INSERT INTO `m_perms` VALUES (59, 1686002657173757952, 'basic:tenantPackage:add', '添加套餐', 1676499559247155200, 10, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:15:32.542913', 0, '2023-07-31 21:15:32.542913', b'0', 0); INSERT INTO `m_perms` VALUES (60, 1686002750660599808, 'basic:tenantPackage:delete', '删除套餐', 1676499559247155200, 20, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:15:54.831477', 0, '2023-07-31 21:15:54.831477', b'0', 0); INSERT INTO `m_perms` VALUES (61, 1686002863185387520, 'basic:tenantPackage:update', '修改套餐', 1676499559247155200, 30, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:16:21.658749', 0, '2023-07-31 21:16:21.658749', b'0', 0); INSERT INTO `m_perms` VALUES (62, 1686002975089418240, 'basic:tenantPackage:get', '查询套餐', 1676499559247155200, 40, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:16:48.338212', 0, '2023-07-31 21:16:48.338212', b'0', 0); INSERT INTO `m_perms` VALUES (63, 1686004858881368064, 'basic:tenant:add', '添加租户', 1676501907755405312, 10, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:24:17.469065', 0, '2023-07-31 21:24:17.469065', b'0', 0); INSERT INTO `m_perms` VALUES (64, 1686005292303966208, 'basic:tenant:delete', '删除租户', 1676501907755405312, 20, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:26:00.806007', 0, '2023-07-31 21:26:00.806007', b'0', 0); INSERT INTO `m_perms` VALUES (65, 1686005483111243776, 'basic:tenant:update', '修改租户', 1676501907755405312, 30, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:26:46.297456', 0, '2023-07-31 21:26:46.297456', b'0', 0); INSERT INTO `m_perms` VALUES (66, 1686005567790047232, 'basic:tenant:get', '查询租户', 1676501907755405312, 40, NULL, NULL, 'B', NULL, b'0', b'1', '', 1, 0, '2023-07-31 21:27:06.487964', 0, '2023-07-31 21:27:06.487964', b'0', 0); INSERT INTO `m_perms` VALUES (73, 1833687152849211392, '', '参数配置', 1669336412647133184, 70, '/basic/config/mgt', 'IconSettings', 'M', '/basic/config/ConfigMgt.vue', b'0', b'1', NULL, 1, 0, '2024-09-11 10:01:00.193232', 0, '2024-09-11 10:02:35.271112', b'0', 5); INSERT INTO `m_perms` VALUES (74, 1833688664656728064, 'basic:config:add', '添加参数', 1833687152849211392, 10, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-09-11 10:07:00.633835', 0, '2024-09-11 10:07:00.633835', b'0', 0); INSERT INTO `m_perms` VALUES (75, 1833688838682595328, 'basic:config:delete', '删除参数', 1833687152849211392, 20, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-09-11 10:07:42.123295', 0, '2024-09-11 10:07:42.123295', b'0', 0); INSERT INTO `m_perms` VALUES (76, 1833688910472302592, 'basic:config:update', '修改参数', 1833687152849211392, 30, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-09-11 10:07:59.239329', 0, '2024-09-11 10:07:59.239329', b'0', 0); INSERT INTO `m_perms` VALUES (77, 1833688972682219520, 'basic:config:get', '查询参数', 1833687152849211392, 40, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-09-11 10:08:14.070779', 0, '2024-09-11 10:08:14.070779', b'0', 0); INSERT INTO `m_perms` VALUES (78, 1843898617245937664, NULL, '存储管理', 1669336412647133184, 58, '/basic/storage/mgt', 'IconStorage', 'M', '/basic/storage/StorageMgt.vue', b'0', b'1', NULL, 1, 0, '2024-10-09 14:17:43.024177', 0, '2024-10-09 14:22:46.976870', b'0', 2); INSERT INTO `m_perms` VALUES (79, 1843900739123359744, 'basic:storage:add', '添加存储', 1843898617245937664, 10, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-10-09 14:26:08.915829', 0, '2024-10-09 14:26:08.915829', b'0', 0); INSERT INTO `m_perms` VALUES (80, 1843900820899704832, 'basic:storage:delete', '删除存储', 1843898617245937664, 20, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-10-09 14:26:28.413099', 0, '2024-10-09 14:26:28.413099', b'0', 0); INSERT INTO `m_perms` VALUES (81, 1843900873001349120, 'basic:storage:update', '修改存储', 1843898617245937664, 30, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-10-09 14:26:40.835720', 0, '2024-10-09 14:26:40.835720', b'0', 0); INSERT INTO `m_perms` VALUES (82, 1843900946787545088, 'basic:storage:get', '查询存储', 1843898617245937664, 40, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-10-09 14:26:58.428091', 0, '2024-10-09 14:27:06.999102', b'0', 1); INSERT INTO `m_perms` VALUES (84, 1846813160695615488, 'basic:file:upload', '文件上传', 1683285343149096960, 10, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-10-17 15:19:04.331491', 0, '2024-10-17 15:19:04.331491', b'0', 0); INSERT INTO `m_perms` VALUES (85, 1846813266043949056, 'basic:file:delete', '删除文件', 1683285343149096960, 20, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-10-17 15:19:29.445881', 0, '2024-10-17 15:19:29.445881', b'0', 0); INSERT INTO `m_perms` VALUES (86, 1846813437867806720, 'basic:file:download', '下载文件', 1683285343149096960, 30, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-10-17 15:20:10.412608', 0, '2024-10-17 15:20:10.412608', b'0', 0); INSERT INTO `m_perms` VALUES (87, 1846813517064654848, 'basic:file:get', '查询文件', 1683285343149096960, 40, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-10-17 15:20:29.294472', 0, '2024-10-17 15:20:29.294472', b'0', 0); INSERT INTO `m_perms` VALUES (88, 1846819585257852928, 'system:swagger', '查看接口', 1680749851857862656, 10, NULL, NULL, 'B', NULL, b'0', b'1', NULL, 1, 0, '2024-10-17 15:44:36.063573', 0, '2024-10-17 15:44:36.063573', b'0', 0); -- ---------------------------- -- Table structure for m_post -- ---------------------------- DROP TABLE IF EXISTS `m_post`; CREATE TABLE `m_post` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `post_id` bigint(0) NOT NULL COMMENT '岗位ID', `post_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '岗位编码', `post_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '岗位名称', `post_sort` int(0) NOT NULL COMMENT '显示顺序', `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `tenant_id` bigint(0) NULL DEFAULT NULL COMMENT '租户编号', `create_id` bigint(0) NULL DEFAULT 0 COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT 0 COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '岗位表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_post -- ---------------------------- INSERT INTO `m_post` VALUES (1, 1676044813214400512, 'super-admin', '超级管理员', 0, '超级无敌管理员', 1, 0, 0, '2023-07-04 09:46:37.534734', 0, '2023-07-27 23:23:36.287549', b'0', 3); INSERT INTO `m_post` VALUES (3, 1676046492030717952, 'develop-post', '开发', 20, NULL, 1, 0, 0, '2023-07-04 09:53:17.795741', 0, '2023-07-12 13:55:35.942153', b'0', 3); INSERT INTO `m_post` VALUES (4, 1679006310662467584, 'sell-post', '销售', 30, NULL, 1, 0, 0, '2023-07-12 13:54:33.547206', 0, '2023-07-12 13:55:38.805938', b'0', 1); INSERT INTO `m_post` VALUES (5, 1679006401066496000, 'finance-post', '财务', 40, NULL, 1, 0, 0, '2023-07-12 13:54:55.102228', 0, '2023-07-12 13:54:55.102228', b'0', 0); INSERT INTO `m_post` VALUES (6, 1685180496364257280, 'tester-post', '测试岗', 100, NULL, 1, 0, 0, '2023-07-29 14:48:37.544778', 0, '2023-07-31 22:32:33.193652', b'0', 1); INSERT INTO `m_post` VALUES (7, 1685181450862055424, 'hr-post', '人力资源', 50, NULL, 1, 0, 0, '2023-07-29 14:52:21.704777', 0, '2023-07-31 22:32:40.815096', b'0', 2); INSERT INTO `m_post` VALUES (8, 1836060404593487872, 'xiaoshou', '销售1', 1, NULL, 1, 1836055976968843264, 1836055978990497792, '2024-09-17 23:11:27.505296', 1836055978990497792, '2024-09-17 23:18:33.795853', b'0', 1); INSERT INTO `m_post` VALUES (9, 1836060433332858880, 'caiwu', '财务2', 2, NULL, 1, 1836055976968843264, 1836055978990497792, '2024-09-17 23:11:34.356145', 1836055978990497792, '2024-09-17 23:18:37.233269', b'0', 1); INSERT INTO `m_post` VALUES (10, 1836060483333156864, 'dongshizhang', '董事长', 0, NULL, 1, 1836055976968843264, 1836055978990497792, '2024-09-17 23:11:46.279929', 1836055978990497792, '2024-09-17 23:11:46.279929', b'0', 0); INSERT INTO `m_post` VALUES (11, 1863857681786707968, 'security-test-post', '安全测试', 60, NULL, 1, 0, 0, '2024-12-03 16:07:55.000000', 0, '2024-12-03 16:07:55.000000', b'0', 0); -- ---------------------------- -- Table structure for m_role -- ---------------------------- DROP TABLE IF EXISTS `m_role`; CREATE TABLE `m_role` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `role_id` bigint(0) NOT NULL COMMENT '角色ID', `role_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名称', `role_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色编码', `role_sort` int(0) NULL DEFAULT 0 COMMENT '显示顺序', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', `tenant_id` bigint(0) NULL DEFAULT NULL COMMENT '租户编号', `create_id` bigint(0) NULL DEFAULT 0 COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT 0 COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 118 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_role -- ---------------------------- INSERT INTO `m_role` VALUES (101, 1671337763855073280, '系统管理员', 'system_admin', 0, 1, NULL, 0, 0, '2023-06-21 10:02:29.514290', 0, '2024-10-17 16:10:43.997451', b'0', 43); INSERT INTO `m_role` VALUES (104, 1671343260918325248, '销售人员', 'sell', 10, 1, NULL, 0, 0, '2023-06-21 10:24:20.116648', 0, '2024-10-29 16:41:07.000000', b'0', 21); INSERT INTO `m_role` VALUES (105, 1671389807492136960, '财务人员', 'financial', 20, 1, NULL, 0, 0, '2023-06-21 13:29:17.684715', 0, '2023-08-06 12:52:19.880964', b'0', 7); INSERT INTO `m_role` VALUES (106, 1677966412497596416, '开发人员', 'developer', 30, 1, NULL, 0, 0, '2023-07-09 17:02:22.504978', 0, '2023-08-06 12:52:25.197098', b'0', 1); INSERT INTO `m_role` VALUES (107, 1677966506420645888, '测试人员', 'tester', 40, 1, NULL, 0, 0, '2023-07-09 17:02:44.898094', 0, '2023-08-06 12:52:30.282735', b'0', 1); INSERT INTO `m_role` VALUES (108, 1677966630567849984, '运维人员', 'devopser', 50, 1, NULL, 0, 0, '2023-07-09 17:03:14.496421', 0, '2023-08-06 12:52:34.732570', b'0', 1); INSERT INTO `m_role` VALUES (109, 1834763883194494977, '管理员', 'admin', 0, 1, '添加租户系统自动创建角色', 1834763883194494976, 0, '2024-09-14 09:19:32.826724', 0, '2024-09-14 09:19:32.826724', b'0', 0); INSERT INTO `m_role` VALUES (110, 1834790150900002816, '普通用户', 'putongyonghu', 1, 1, NULL, 1834763883194494976, 1834763884364705792, '2024-09-14 11:03:55.423220', 0, '2024-10-04 21:44:55.734261', b'0', 2); INSERT INTO `m_role` VALUES (111, 1836055976973037568, '管理员', 'admin', 0, 1, '添加租户系统自动创建角色', 1836055976968843264, 0, '2024-09-17 22:53:52.221775', 1836055978990497792, '2024-09-17 23:29:36.280452', b'0', 1); INSERT INTO `m_role` VALUES (112, 1836056110565814273, '管理员', 'admin', 0, 1, '添加租户系统自动创建角色', 1836056110565814272, 0, '2024-09-17 22:54:23.727486', 0, '2024-09-17 22:54:23.727486', b'0', 0); INSERT INTO `m_role` VALUES (113, 1836057975659556864, '测试租户1普通', 'ceshi1-putong', 1, 1, NULL, 1836055976968843264, 1836055978990497792, '2024-09-17 23:01:48.394988', 1836055978990497792, '2024-09-17 23:01:48.394988', b'0', 0); INSERT INTO `m_role` VALUES (114, 1846431773459197953, '管理员', 'admin', 0, 1, '添加租户系统自动创建角色', 1846431773459197952, 0, '2024-10-16 14:03:34.527236', 0, '2024-10-16 14:03:34.527236', b'0', 0); INSERT INTO `m_role` VALUES (115, 1890404237937938432, '管理员', 'admin', 0, 1, '系统自动创建角色', 1890404237296209920, 0, '2025-02-14 22:14:26.000000', 0, '2025-02-14 22:14:26.000000', b'0', 0); INSERT INTO `m_role` VALUES (116, 1890405820998291456, '管理员', 'admin', 0, 1, '系统自动创建角色', 1890405820364951552, 0, '2025-02-14 22:20:44.000000', 0, '2025-02-14 22:20:44.000000', b'0', 0); INSERT INTO `m_role` VALUES (117, 1890406866659250176, '管理员', 'admin', 0, 1, '系统自动创建角色', 1890406866181099520, 0, '2025-02-14 22:24:53.000000', 0, '2025-02-14 22:24:53.000000', b'0', 0); -- ---------------------------- -- Table structure for m_role_dept -- ---------------------------- DROP TABLE IF EXISTS `m_role_dept`; CREATE TABLE `m_role_dept` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `role_id` bigint(0) NOT NULL COMMENT '角色ID', `dept_id` bigint(0) NOT NULL COMMENT '部门ID', PRIMARY KEY (`id`) USING BTREE, INDEX `dept_id_idx`(`dept_id`) USING BTREE COMMENT '部门ID索引', INDEX `role_id_idx`(`role_id`) USING BTREE COMMENT '角色ID索引' ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色与部门关联表 1角色-N部门' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for m_role_perm -- ---------------------------- DROP TABLE IF EXISTS `m_role_perm`; CREATE TABLE `m_role_perm` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `role_id` bigint(0) NOT NULL COMMENT '角色ID', `perm_id` bigint(0) NOT NULL COMMENT '权限ID', PRIMARY KEY (`id`) USING BTREE, INDEX `perm_id_idx`(`perm_id`) USING BTREE COMMENT '权限ID索引', INDEX `role_id_idx`(`role_id`) USING BTREE COMMENT '角色ID索引' ) ENGINE = InnoDB AUTO_INCREMENT = 2098 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色与权限关联表 1角色-N权限' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_role_perm -- ---------------------------- INSERT INTO `m_role_perm` VALUES (747, 1671389807492136960, 1673863803093557248); INSERT INTO `m_role_perm` VALUES (748, 1677966412497596416, 1673863803093557248); INSERT INTO `m_role_perm` VALUES (749, 1677966506420645888, 1673863803093557248); INSERT INTO `m_role_perm` VALUES (750, 1677966630567849984, 1673863803093557248); INSERT INTO `m_role_perm` VALUES (880, 1836057975659556864, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (881, 1836057975659556864, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (882, 1836057975659556864, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (883, 1836057975659556864, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (884, 1836057975659556864, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (885, 1836057975659556864, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (1110, 1834790150900002816, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (1111, 1834790150900002816, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (1112, 1834790150900002816, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (1113, 1834790150900002816, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (1114, 1834790150900002816, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (1115, 1834790150900002816, 1673167646340120576); INSERT INTO `m_role_perm` VALUES (1118, 1834790150900002816, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (1119, 1834790150900002816, 1685986566443687936); INSERT INTO `m_role_perm` VALUES (1120, 1834790150900002816, 1685986702834065408); INSERT INTO `m_role_perm` VALUES (1121, 1834790150900002816, 1685986806387236864); INSERT INTO `m_role_perm` VALUES (1122, 1834790150900002816, 1685986887102423040); INSERT INTO `m_role_perm` VALUES (1880, 1671337763855073280, 1673863803093557248); INSERT INTO `m_role_perm` VALUES (1881, 1671337763855073280, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (1882, 1671337763855073280, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (1883, 1671337763855073280, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (1884, 1671337763855073280, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (1885, 1671337763855073280, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (1886, 1671337763855073280, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (1887, 1671337763855073280, 1673167646340120576); INSERT INTO `m_role_perm` VALUES (1888, 1671337763855073280, 1685986566443687936); INSERT INTO `m_role_perm` VALUES (1889, 1671337763855073280, 1685986702834065408); INSERT INTO `m_role_perm` VALUES (1890, 1671337763855073280, 1685986806387236864); INSERT INTO `m_role_perm` VALUES (1891, 1671337763855073280, 1685986887102423040); INSERT INTO `m_role_perm` VALUES (1892, 1671337763855073280, 1669339147886989312); INSERT INTO `m_role_perm` VALUES (1893, 1671337763855073280, 1685987612687654912); INSERT INTO `m_role_perm` VALUES (1894, 1671337763855073280, 1685987708229705728); INSERT INTO `m_role_perm` VALUES (1895, 1671337763855073280, 1685988419789185024); INSERT INTO `m_role_perm` VALUES (1896, 1671337763855073280, 1685988623951126528); INSERT INTO `m_role_perm` VALUES (1897, 1671337763855073280, 1673524365792530432); INSERT INTO `m_role_perm` VALUES (1898, 1671337763855073280, 1685996318275985408); INSERT INTO `m_role_perm` VALUES (1899, 1671337763855073280, 1685996426530971648); INSERT INTO `m_role_perm` VALUES (1900, 1671337763855073280, 1685996547448561664); INSERT INTO `m_role_perm` VALUES (1901, 1671337763855073280, 1685996623386435584); INSERT INTO `m_role_perm` VALUES (1902, 1671337763855073280, 1673524591861321728); INSERT INTO `m_role_perm` VALUES (1903, 1671337763855073280, 1685996875623489536); INSERT INTO `m_role_perm` VALUES (1904, 1671337763855073280, 1685997536914235392); INSERT INTO `m_role_perm` VALUES (1905, 1671337763855073280, 1685997640341577728); INSERT INTO `m_role_perm` VALUES (1906, 1671337763855073280, 1685997732956004352); INSERT INTO `m_role_perm` VALUES (1907, 1671337763855073280, 1669339375922909184); INSERT INTO `m_role_perm` VALUES (1908, 1671337763855073280, 1685998041879076864); INSERT INTO `m_role_perm` VALUES (1909, 1671337763855073280, 1685998171407572992); INSERT INTO `m_role_perm` VALUES (1910, 1671337763855073280, 1685998244715618304); INSERT INTO `m_role_perm` VALUES (1911, 1671337763855073280, 1685998340425441280); INSERT INTO `m_role_perm` VALUES (1912, 1671337763855073280, 1683285343149096960); INSERT INTO `m_role_perm` VALUES (1913, 1671337763855073280, 1846813160695615488); INSERT INTO `m_role_perm` VALUES (1914, 1671337763855073280, 1846813266043949056); INSERT INTO `m_role_perm` VALUES (1915, 1671337763855073280, 1846813437867806720); INSERT INTO `m_role_perm` VALUES (1916, 1671337763855073280, 1846813517064654848); INSERT INTO `m_role_perm` VALUES (1917, 1671337763855073280, 1843898617245937664); INSERT INTO `m_role_perm` VALUES (1918, 1671337763855073280, 1843900739123359744); INSERT INTO `m_role_perm` VALUES (1919, 1671337763855073280, 1843900820899704832); INSERT INTO `m_role_perm` VALUES (1920, 1671337763855073280, 1843900873001349120); INSERT INTO `m_role_perm` VALUES (1921, 1671337763855073280, 1843900946787545088); INSERT INTO `m_role_perm` VALUES (1922, 1671337763855073280, 1676499330464649216); INSERT INTO `m_role_perm` VALUES (1923, 1671337763855073280, 1676499559247155200); INSERT INTO `m_role_perm` VALUES (1924, 1671337763855073280, 1686002657173757952); INSERT INTO `m_role_perm` VALUES (1925, 1671337763855073280, 1686002750660599808); INSERT INTO `m_role_perm` VALUES (1926, 1671337763855073280, 1686002863185387520); INSERT INTO `m_role_perm` VALUES (1927, 1671337763855073280, 1686002975089418240); INSERT INTO `m_role_perm` VALUES (1928, 1671337763855073280, 1676501907755405312); INSERT INTO `m_role_perm` VALUES (1929, 1671337763855073280, 1686004858881368064); INSERT INTO `m_role_perm` VALUES (1930, 1671337763855073280, 1686005292303966208); INSERT INTO `m_role_perm` VALUES (1931, 1671337763855073280, 1686005483111243776); INSERT INTO `m_role_perm` VALUES (1932, 1671337763855073280, 1686005567790047232); INSERT INTO `m_role_perm` VALUES (1933, 1671337763855073280, 1681273378598850560); INSERT INTO `m_role_perm` VALUES (1934, 1671337763855073280, 1686001693859569664); INSERT INTO `m_role_perm` VALUES (1935, 1671337763855073280, 1686001770980237312); INSERT INTO `m_role_perm` VALUES (1936, 1671337763855073280, 1686002193703165952); INSERT INTO `m_role_perm` VALUES (1937, 1671337763855073280, 1686002291338174464); INSERT INTO `m_role_perm` VALUES (1938, 1671337763855073280, 1833687152849211392); INSERT INTO `m_role_perm` VALUES (1939, 1671337763855073280, 1833688664656728064); INSERT INTO `m_role_perm` VALUES (1940, 1671337763855073280, 1833688838682595328); INSERT INTO `m_role_perm` VALUES (1941, 1671337763855073280, 1833688910472302592); INSERT INTO `m_role_perm` VALUES (1942, 1671337763855073280, 1833688972682219520); INSERT INTO `m_role_perm` VALUES (1943, 1671337763855073280, 1680749851857862656); INSERT INTO `m_role_perm` VALUES (1944, 1671337763855073280, 1846819585257852928); INSERT INTO `m_role_perm` VALUES (1945, 1671343260918325248, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (1946, 1671343260918325248, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (1947, 1671343260918325248, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (1948, 1671343260918325248, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (1949, 1671343260918325248, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (1950, 1671343260918325248, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (1951, 1834763883194494977, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (1952, 1834763883194494977, 1685986566443687936); INSERT INTO `m_role_perm` VALUES (1953, 1834763883194494977, 1685986702834065408); INSERT INTO `m_role_perm` VALUES (1954, 1834763883194494977, 1685986806387236864); INSERT INTO `m_role_perm` VALUES (1955, 1834763883194494977, 1685986887102423040); INSERT INTO `m_role_perm` VALUES (1956, 1834763883194494977, 1673167646340120576); INSERT INTO `m_role_perm` VALUES (1957, 1834763883194494977, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (1958, 1834763883194494977, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (1959, 1834763883194494977, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (1960, 1834763883194494977, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (1961, 1834763883194494977, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (1962, 1834763883194494977, 1685996318275985408); INSERT INTO `m_role_perm` VALUES (1963, 1834763883194494977, 1685996426530971648); INSERT INTO `m_role_perm` VALUES (1964, 1834763883194494977, 1685996547448561664); INSERT INTO `m_role_perm` VALUES (1965, 1834763883194494977, 1685996623386435584); INSERT INTO `m_role_perm` VALUES (1966, 1834763883194494977, 1673524365792530432); INSERT INTO `m_role_perm` VALUES (1967, 1834763883194494977, 1685996875623489536); INSERT INTO `m_role_perm` VALUES (1968, 1834763883194494977, 1685997536914235392); INSERT INTO `m_role_perm` VALUES (1969, 1834763883194494977, 1685997640341577728); INSERT INTO `m_role_perm` VALUES (1970, 1834763883194494977, 1685997732956004352); INSERT INTO `m_role_perm` VALUES (1971, 1834763883194494977, 1673524591861321728); INSERT INTO `m_role_perm` VALUES (1972, 1836055976973037568, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (1973, 1836055976973037568, 1685986566443687936); INSERT INTO `m_role_perm` VALUES (1974, 1836055976973037568, 1685986702834065408); INSERT INTO `m_role_perm` VALUES (1975, 1836055976973037568, 1685986806387236864); INSERT INTO `m_role_perm` VALUES (1976, 1836055976973037568, 1685986887102423040); INSERT INTO `m_role_perm` VALUES (1977, 1836055976973037568, 1673167646340120576); INSERT INTO `m_role_perm` VALUES (1978, 1836055976973037568, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (1979, 1836055976973037568, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (1980, 1836055976973037568, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (1981, 1836055976973037568, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (1982, 1836055976973037568, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (1983, 1836055976973037568, 1685996318275985408); INSERT INTO `m_role_perm` VALUES (1984, 1836055976973037568, 1685996426530971648); INSERT INTO `m_role_perm` VALUES (1985, 1836055976973037568, 1685996547448561664); INSERT INTO `m_role_perm` VALUES (1986, 1836055976973037568, 1685996623386435584); INSERT INTO `m_role_perm` VALUES (1987, 1836055976973037568, 1673524365792530432); INSERT INTO `m_role_perm` VALUES (1988, 1836055976973037568, 1685996875623489536); INSERT INTO `m_role_perm` VALUES (1989, 1836055976973037568, 1685997536914235392); INSERT INTO `m_role_perm` VALUES (1990, 1836055976973037568, 1685997640341577728); INSERT INTO `m_role_perm` VALUES (1991, 1836055976973037568, 1685997732956004352); INSERT INTO `m_role_perm` VALUES (1992, 1836055976973037568, 1673524591861321728); INSERT INTO `m_role_perm` VALUES (1993, 1836056110565814273, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (1994, 1836056110565814273, 1685986566443687936); INSERT INTO `m_role_perm` VALUES (1995, 1836056110565814273, 1685986702834065408); INSERT INTO `m_role_perm` VALUES (1996, 1836056110565814273, 1685986806387236864); INSERT INTO `m_role_perm` VALUES (1997, 1836056110565814273, 1685986887102423040); INSERT INTO `m_role_perm` VALUES (1998, 1836056110565814273, 1673167646340120576); INSERT INTO `m_role_perm` VALUES (1999, 1836056110565814273, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (2000, 1836056110565814273, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (2001, 1836056110565814273, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (2002, 1836056110565814273, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (2003, 1836056110565814273, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (2004, 1836056110565814273, 1685996318275985408); INSERT INTO `m_role_perm` VALUES (2005, 1836056110565814273, 1685996426530971648); INSERT INTO `m_role_perm` VALUES (2006, 1836056110565814273, 1685996547448561664); INSERT INTO `m_role_perm` VALUES (2007, 1836056110565814273, 1685996623386435584); INSERT INTO `m_role_perm` VALUES (2008, 1836056110565814273, 1673524365792530432); INSERT INTO `m_role_perm` VALUES (2009, 1836056110565814273, 1685996875623489536); INSERT INTO `m_role_perm` VALUES (2010, 1836056110565814273, 1685997536914235392); INSERT INTO `m_role_perm` VALUES (2011, 1836056110565814273, 1685997640341577728); INSERT INTO `m_role_perm` VALUES (2012, 1836056110565814273, 1685997732956004352); INSERT INTO `m_role_perm` VALUES (2013, 1836056110565814273, 1673524591861321728); INSERT INTO `m_role_perm` VALUES (2014, 1846431773459197953, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (2015, 1846431773459197953, 1685986566443687936); INSERT INTO `m_role_perm` VALUES (2016, 1846431773459197953, 1685986702834065408); INSERT INTO `m_role_perm` VALUES (2017, 1846431773459197953, 1685986806387236864); INSERT INTO `m_role_perm` VALUES (2018, 1846431773459197953, 1685986887102423040); INSERT INTO `m_role_perm` VALUES (2019, 1846431773459197953, 1673167646340120576); INSERT INTO `m_role_perm` VALUES (2020, 1846431773459197953, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (2021, 1846431773459197953, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (2022, 1846431773459197953, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (2023, 1846431773459197953, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (2024, 1846431773459197953, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (2025, 1846431773459197953, 1685996318275985408); INSERT INTO `m_role_perm` VALUES (2026, 1846431773459197953, 1685996426530971648); INSERT INTO `m_role_perm` VALUES (2027, 1846431773459197953, 1685996547448561664); INSERT INTO `m_role_perm` VALUES (2028, 1846431773459197953, 1685996623386435584); INSERT INTO `m_role_perm` VALUES (2029, 1846431773459197953, 1673524365792530432); INSERT INTO `m_role_perm` VALUES (2030, 1846431773459197953, 1685996875623489536); INSERT INTO `m_role_perm` VALUES (2031, 1846431773459197953, 1685997536914235392); INSERT INTO `m_role_perm` VALUES (2032, 1846431773459197953, 1685997640341577728); INSERT INTO `m_role_perm` VALUES (2033, 1846431773459197953, 1685997732956004352); INSERT INTO `m_role_perm` VALUES (2034, 1846431773459197953, 1673524591861321728); INSERT INTO `m_role_perm` VALUES (2035, 1890404237937938432, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (2036, 1890404237937938432, 1685986566443687936); INSERT INTO `m_role_perm` VALUES (2037, 1890404237937938432, 1685986702834065408); INSERT INTO `m_role_perm` VALUES (2038, 1890404237937938432, 1685986806387236864); INSERT INTO `m_role_perm` VALUES (2039, 1890404237937938432, 1685986887102423040); INSERT INTO `m_role_perm` VALUES (2040, 1890404237937938432, 1673167646340120576); INSERT INTO `m_role_perm` VALUES (2041, 1890404237937938432, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (2042, 1890404237937938432, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (2043, 1890404237937938432, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (2044, 1890404237937938432, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (2045, 1890404237937938432, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (2046, 1890404237937938432, 1685996318275985408); INSERT INTO `m_role_perm` VALUES (2047, 1890404237937938432, 1685996426530971648); INSERT INTO `m_role_perm` VALUES (2048, 1890404237937938432, 1685996547448561664); INSERT INTO `m_role_perm` VALUES (2049, 1890404237937938432, 1685996623386435584); INSERT INTO `m_role_perm` VALUES (2050, 1890404237937938432, 1673524365792530432); INSERT INTO `m_role_perm` VALUES (2051, 1890404237937938432, 1685996875623489536); INSERT INTO `m_role_perm` VALUES (2052, 1890404237937938432, 1685997536914235392); INSERT INTO `m_role_perm` VALUES (2053, 1890404237937938432, 1685997640341577728); INSERT INTO `m_role_perm` VALUES (2054, 1890404237937938432, 1685997732956004352); INSERT INTO `m_role_perm` VALUES (2055, 1890404237937938432, 1673524591861321728); INSERT INTO `m_role_perm` VALUES (2056, 1890405820998291456, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (2057, 1890405820998291456, 1685986566443687936); INSERT INTO `m_role_perm` VALUES (2058, 1890405820998291456, 1685986702834065408); INSERT INTO `m_role_perm` VALUES (2059, 1890405820998291456, 1685986806387236864); INSERT INTO `m_role_perm` VALUES (2060, 1890405820998291456, 1685986887102423040); INSERT INTO `m_role_perm` VALUES (2061, 1890405820998291456, 1673167646340120576); INSERT INTO `m_role_perm` VALUES (2062, 1890405820998291456, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (2063, 1890405820998291456, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (2064, 1890405820998291456, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (2065, 1890405820998291456, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (2066, 1890405820998291456, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (2067, 1890405820998291456, 1685996318275985408); INSERT INTO `m_role_perm` VALUES (2068, 1890405820998291456, 1685996426530971648); INSERT INTO `m_role_perm` VALUES (2069, 1890405820998291456, 1685996547448561664); INSERT INTO `m_role_perm` VALUES (2070, 1890405820998291456, 1685996623386435584); INSERT INTO `m_role_perm` VALUES (2071, 1890405820998291456, 1673524365792530432); INSERT INTO `m_role_perm` VALUES (2072, 1890405820998291456, 1685996875623489536); INSERT INTO `m_role_perm` VALUES (2073, 1890405820998291456, 1685997536914235392); INSERT INTO `m_role_perm` VALUES (2074, 1890405820998291456, 1685997640341577728); INSERT INTO `m_role_perm` VALUES (2075, 1890405820998291456, 1685997732956004352); INSERT INTO `m_role_perm` VALUES (2076, 1890405820998291456, 1673524591861321728); INSERT INTO `m_role_perm` VALUES (2077, 1890406866659250176, 1669336412647133184); INSERT INTO `m_role_perm` VALUES (2078, 1890406866659250176, 1685986566443687936); INSERT INTO `m_role_perm` VALUES (2079, 1890406866659250176, 1685986702834065408); INSERT INTO `m_role_perm` VALUES (2080, 1890406866659250176, 1685986806387236864); INSERT INTO `m_role_perm` VALUES (2081, 1890406866659250176, 1685986887102423040); INSERT INTO `m_role_perm` VALUES (2082, 1890406866659250176, 1673167646340120576); INSERT INTO `m_role_perm` VALUES (2083, 1890406866659250176, 1685985572129398784); INSERT INTO `m_role_perm` VALUES (2084, 1890406866659250176, 1685985875515990016); INSERT INTO `m_role_perm` VALUES (2085, 1890406866659250176, 1685985977349496832); INSERT INTO `m_role_perm` VALUES (2086, 1890406866659250176, 1685986276453703680); INSERT INTO `m_role_perm` VALUES (2087, 1890406866659250176, 1669338708936298496); INSERT INTO `m_role_perm` VALUES (2088, 1890406866659250176, 1685996318275985408); INSERT INTO `m_role_perm` VALUES (2089, 1890406866659250176, 1685996426530971648); INSERT INTO `m_role_perm` VALUES (2090, 1890406866659250176, 1685996547448561664); INSERT INTO `m_role_perm` VALUES (2091, 1890406866659250176, 1685996623386435584); INSERT INTO `m_role_perm` VALUES (2092, 1890406866659250176, 1673524365792530432); INSERT INTO `m_role_perm` VALUES (2093, 1890406866659250176, 1685996875623489536); INSERT INTO `m_role_perm` VALUES (2094, 1890406866659250176, 1685997536914235392); INSERT INTO `m_role_perm` VALUES (2095, 1890406866659250176, 1685997640341577728); INSERT INTO `m_role_perm` VALUES (2096, 1890406866659250176, 1685997732956004352); INSERT INTO `m_role_perm` VALUES (2097, 1890406866659250176, 1673524591861321728); -- ---------------------------- -- Table structure for m_storage -- ---------------------------- DROP TABLE IF EXISTS `m_storage`; CREATE TABLE `m_storage` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `storage_id` bigint(0) NOT NULL, `storage_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称', `storage_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '存储类型,用于标识存储平台,如本地、阿里云oss、七牛云oss等', `description` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '说明', `storage_config` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '存储配置,JSON数据', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `create_id` bigint(0) NULL DEFAULT 0 COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT 0 COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '存储管理表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_storage -- ---------------------------- INSERT INTO `m_storage` VALUES (1, 1843939697907720192, '本地存储测试', 'local', '1', '{\"storagePath\":\"D:/application/minimalist-saas/\"}', 1, 0, NULL, 0, '2025-03-12 21:43:52.000000', b'0', 2); INSERT INTO `m_storage` VALUES (2, 1844270972333924352, 'minio', 'minio', '2', '{\"accessKey\":\"5555\",\"secretKey\":\"5555\",\"endPoint\":\"5555\",\"bucketName\":\"5555\"}', 1, 0, NULL, 0, NULL, b'0', 0); INSERT INTO `m_storage` VALUES (4, 1891827317205766144, '七牛云2', 'qiniu', NULL, '{\"accessKey\":\"2222\",\"secretKey\":\"2222\",\"endPoint\":\"2222\",\"bucketName\":\"2222\",\"regionId\":\"2222\"}', 1, 0, '2025-02-18 20:29:15.000000', 0, '2025-02-18 20:29:56.000000', b'0', 2); -- ---------------------------- -- Table structure for m_tenant -- ---------------------------- DROP TABLE IF EXISTS `m_tenant`; CREATE TABLE `m_tenant` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `tenant_id` bigint(0) NOT NULL COMMENT '租户ID', `user_id` bigint(0) NOT NULL COMMENT '用户ID', `package_id` bigint(0) NOT NULL COMMENT '租户套餐ID', `tenant_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '租户名', `expire_time` datetime(6) NOT NULL COMMENT '租户过期时间', `account_count` int(0) NOT NULL DEFAULT 0 COMMENT '可创建账号数量', `data_isolation` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'column' COMMENT '数据隔离方式 column字段隔离(默认) db数据库隔离', `datasource` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'master' COMMENT '数据源名称 master(默认使用主库) ', `storage_id` bigint(0) NULL DEFAULT NULL COMMENT '存储ID 表示该租户使用哪个文件存储', `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `create_id` bigint(0) NULL DEFAULT NULL COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT NULL COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '租户表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_tenant -- ---------------------------- INSERT INTO `m_tenant` VALUES (1, 0, 0, 0, '系统租户', '2030-12-31 23:59:59.000000', 20, 'column', 'master', NULL, NULL, 1, 0, '2025-02-14 21:54:35.000000', 0, '2025-02-14 21:54:58.000000', b'0', 0); INSERT INTO `m_tenant` VALUES (3, 1834763883194494976, 1834763884364705792, 1676850220841287680, '东东胡辣汤', '2035-09-30 09:15:21.000000', 2, 'column', 'master', 1843939697907720192, NULL, 1, 0, '2025-02-14 21:54:38.000000', 0, '2025-02-18 21:56:23.000000', b'0', 2); INSERT INTO `m_tenant` VALUES (4, 1836055976968843264, 1836055978990497792, 1676850220841287680, '测试租户111', '2024-09-30 22:38:09.000000', 3, 'column', 'master', 1843939697907720192, NULL, 1, 0, '2025-02-14 21:54:41.000000', 0, '2025-02-18 21:56:32.000000', b'0', 2); INSERT INTO `m_tenant` VALUES (5, 1836056110565814272, 1836056110997827584, 1676850220841287680, '测试租户222', '2024-09-30 22:54:04.000000', 2, 'column', 'master', 1843939697907720192, NULL, 1, 0, '2025-02-14 21:54:43.000000', 0, '2025-02-18 21:56:39.000000', b'0', 2); INSERT INTO `m_tenant` VALUES (6, 1846431773459197952, 1846431773870239744, 1676850220841287680, '测试租户333', '2024-10-31 14:03:03.000000', 3, 'column', 'master', 1843939697907720192, NULL, 1, 0, '2025-02-14 21:54:46.000000', 0, '2025-02-18 21:56:42.000000', b'0', 2); INSERT INTO `m_tenant` VALUES (9, 1890406866181099520, 1890406866181099521, 1676850220841287680, '测试租户44', '2025-02-28 22:22:49.000000', 2, 'column', 'master', 1843939697907720192, NULL, 1, 0, '2025-02-14 22:24:53.000000', 0, '2025-02-19 11:01:00.000000', b'0', 6); -- ---------------------------- -- Table structure for m_tenant_datasource -- ---------------------------- DROP TABLE IF EXISTS `m_tenant_datasource`; CREATE TABLE `m_tenant_datasource` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `datasource_id` bigint(0) NOT NULL COMMENT '数据源ID', `tenant_id` bigint(0) NOT NULL COMMENT '租户ID', `datasource_name` varchar(24) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '数据源名称', `datasource_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '数据源连接', `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '数据源用户名', `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '数据源密码', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '租户数据源表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for m_tenant_package -- ---------------------------- DROP TABLE IF EXISTS `m_tenant_package`; CREATE TABLE `m_tenant_package` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `package_id` bigint(0) NOT NULL COMMENT '套餐ID', `package_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '套餐名称', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', `create_id` bigint(0) NULL DEFAULT NULL COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT NULL COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `unq_package_id`(`package_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '租户套餐表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_tenant_package -- ---------------------------- INSERT INTO `m_tenant_package` VALUES (5, 1676850220841287680, '基础套餐', 1, '基础套餐', 0, '2023-07-06 15:07:01.676599', 0, '2024-12-03 15:54:37.000000', b'0', 21); INSERT INTO `m_tenant_package` VALUES (9, 1863859488525045760, 'CRM套餐', 1, NULL, 0, '2024-12-03 16:15:05.000000', 0, '2024-12-03 16:15:05.000000', b'0', 0); -- ---------------------------- -- Table structure for m_tenant_package_perm -- ---------------------------- DROP TABLE IF EXISTS `m_tenant_package_perm`; CREATE TABLE `m_tenant_package_perm` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `package_id` bigint(0) NOT NULL COMMENT '租户套餐ID', `perm_id` bigint(0) NOT NULL COMMENT '权限ID', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 679 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '租户套餐与权限关联表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_tenant_package_perm -- ---------------------------- INSERT INTO `m_tenant_package_perm` VALUES (609, 1676850220841287680, 1669336412647133184); INSERT INTO `m_tenant_package_perm` VALUES (610, 1676850220841287680, 1685986566443687936); INSERT INTO `m_tenant_package_perm` VALUES (611, 1676850220841287680, 1685986702834065408); INSERT INTO `m_tenant_package_perm` VALUES (612, 1676850220841287680, 1685986806387236864); INSERT INTO `m_tenant_package_perm` VALUES (613, 1676850220841287680, 1685986887102423040); INSERT INTO `m_tenant_package_perm` VALUES (614, 1676850220841287680, 1673167646340120576); INSERT INTO `m_tenant_package_perm` VALUES (615, 1676850220841287680, 1685985572129398784); INSERT INTO `m_tenant_package_perm` VALUES (616, 1676850220841287680, 1685985875515990016); INSERT INTO `m_tenant_package_perm` VALUES (617, 1676850220841287680, 1685985977349496832); INSERT INTO `m_tenant_package_perm` VALUES (618, 1676850220841287680, 1685986276453703680); INSERT INTO `m_tenant_package_perm` VALUES (619, 1676850220841287680, 1669338708936298496); INSERT INTO `m_tenant_package_perm` VALUES (620, 1676850220841287680, 1685996318275985408); INSERT INTO `m_tenant_package_perm` VALUES (621, 1676850220841287680, 1685996426530971648); INSERT INTO `m_tenant_package_perm` VALUES (622, 1676850220841287680, 1685996547448561664); INSERT INTO `m_tenant_package_perm` VALUES (623, 1676850220841287680, 1685996623386435584); INSERT INTO `m_tenant_package_perm` VALUES (624, 1676850220841287680, 1673524365792530432); INSERT INTO `m_tenant_package_perm` VALUES (625, 1676850220841287680, 1685996875623489536); INSERT INTO `m_tenant_package_perm` VALUES (626, 1676850220841287680, 1685997536914235392); INSERT INTO `m_tenant_package_perm` VALUES (627, 1676850220841287680, 1685997640341577728); INSERT INTO `m_tenant_package_perm` VALUES (628, 1676850220841287680, 1685997732956004352); INSERT INTO `m_tenant_package_perm` VALUES (629, 1676850220841287680, 1673524591861321728); INSERT INTO `m_tenant_package_perm` VALUES (673, 1863859488525045760, 1669336412647133184); INSERT INTO `m_tenant_package_perm` VALUES (674, 1863859488525045760, 1669338708936298496); INSERT INTO `m_tenant_package_perm` VALUES (675, 1863859488525045760, 1685985572129398784); INSERT INTO `m_tenant_package_perm` VALUES (676, 1863859488525045760, 1685985875515990016); INSERT INTO `m_tenant_package_perm` VALUES (677, 1863859488525045760, 1685985977349496832); INSERT INTO `m_tenant_package_perm` VALUES (678, 1863859488525045760, 1685986276453703680); -- ---------------------------- -- Table structure for m_user -- ---------------------------- DROP TABLE IF EXISTS `m_user`; CREATE TABLE `m_user` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `user_id` bigint(0) NOT NULL COMMENT '用户ID', `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户账号', `password` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码', `salt` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '盐值', `nickname` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户昵称', `user_real_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户真实姓名', `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户邮箱', `phone` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号码', `user_sex` tinyint(0) NULL DEFAULT 1 COMMENT '用户性别 0未知 1男 2女', `user_avatar` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '头像base64编码', `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', `status` tinyint(0) NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `tenant_id` bigint(0) NULL DEFAULT NULL COMMENT '租户编号', `create_id` bigint(0) NULL DEFAULT 0 COMMENT '创建人ID', `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `update_id` bigint(0) NULL DEFAULT 0 COMMENT '更新人ID', `update_time` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '逻辑删除 0未删除 1已删除', `version` int(0) NULL DEFAULT 0 COMMENT '版本号', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `username_unq`(`username`) USING BTREE COMMENT '用户名唯一索引', INDEX `user_id_idx`(`user_id`) USING BTREE COMMENT '用户ID索引' ) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_user -- ---------------------------- INSERT INTO `m_user` VALUES (1, 0, 'admin', 'c43fc233541ac2183e68159618167149', 'admin', '无敌的我', '小太阳', '438562332@qq.com', '15011384542', 1, 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gIoSUNDX1BST0ZJTEUAAQEAAAIYAAAAAAIQAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAAHRyWFlaAAABZAAAABRnWFlaAAABeAAAABRiWFlaAAABjAAAABRyVFJDAAABoAAAAChnVFJDAAABoAAAAChiVFJDAAABoAAAACh3dHB0AAAByAAAABRjcHJ0AAAB3AAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFgAAAAcAHMAUgBHAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z3BhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABYWVogAAAAAAAA9tYAAQAAAADTLW1sdWMAAAAAAAAAAQAAAAxlblVTAAAAIAAAABwARwBvAG8AZwBsAGUAIABJAG4AYwAuACAAMgAwADEANv/bAEMADQkKCwoIDQsKCw4ODQ8TIBUTEhITJxweFyAuKTEwLiktLDM6Sj4zNkY3LC1AV0FGTE5SU1IyPlphWlBgSlFST//bAEMBDg4OExETJhUVJk81LTVPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT//AABEIAn8CfwMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAAAQYDBAUCB//EAEoQAAEDAgMEBwUFBAcHBAMAAAABAgMEEQUhMRJBUYEGEyIyYXGRFEJSofAHIzNisUNy0eEkNFNUc5LBFRY1NmOC8SUmk6JFg7L/xAAaAQEAAwEBAQAAAAAAAAAAAAAAAQMEAgUG/8QAKREBAAICAgIBBAMBAAMBAAAAAAECAxEEEiExMhMiQVEFFEJhIzNScf/aAAwDAQACEQMRAD8AugAPBbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3XtkAjcbAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEOWyKtyTXe7aVTqtVWW/WBXK5cyWO2VPBOpYydp3tsIt0JMUTr9kylVo1LbjtFqgAIdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEV3dQIAN4AAAJAAAAAAAAAAAAIXQmEMcrsrGNeViXLtLexHHItj0w5LdpQnIlPrMjkTyCsRbKi8DYRbpc1zLEq2VFIvC/BbU6ZAAVNgAAAAAAAAAAAAJQAxPnjZq668EMS1nwsL6cXLfzEKbcjHT3LaBhgmSVF3OTcZirJjtjnrZZS8XjdQAHDsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADZiYjWXtmpgjTaeiG0c3nUK7ShzEd3kMD4Vaiqi3Q2dUGhzF3MWaQNiSJHZpr4GBWq1c0VDuJiVkSgAEpAAEgAAAAAeJV7NuJ7MMqrtWud0jyqyzqrH9aDLPT0QDmWMIEt9IOZOfECLp9IemLZ1yEvxGYlNZ1LZQHli3ah6KZ9vRr5jYACEgAAAAAAYZp0iSyZu4FuPFbJbrVXe8UjcvcsjY23caUlQ990RdlvgY3OVzlc5cyM8/4nu8bg0xxu3t5Ofl2v4qcxzGYzsb4jXpk9vcT9iRF8TopmmRy8+J0KZ21EnFMjyP5PF6vD0uDk/wygA8V6YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyQJ95pobHMw09ruM5XefKq3sS1gQDhyk8uajkzselIETMDVexWa6Hk3FRHZKmprSMVi63QurbayttvAAJdAACQAADXdbaXQ2DXXU7ozcifDz9bh6fIniNy6ljKfW4ehGYS/AB9bhxFvBSdy5L6AZYVyVDIYYu9oZiu/tuwz9oADhaAAAAQ9yNaruBNazadQi06jbDUTdW2yL2lNG91uuu89Per3qrr5nn1PpeJxoxU3+Xh8jPOS3/AA5DiNOI46mtmPrUcgnMJoSH1qbdE7JzOGZqepno1tL5oY+bTtilp4tuuSG8AD5l7oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz0/dXzMpip0TY5mXiVW9qrewAHLkF1G8ACHN2mqikk7hHgaat2VVF3EGWoRNpF4mIvj0ugAASAAAay2uuZsmB7V2skunkd0UZ6zMPOX1Yg9bLkTS3JSLa/wACxk6yglBnxANSjIE5ntI1dnoE1rayIU7WpnPLW7Oh6KrT5bcVesAAOVgAABrVjtliNRe8bJqViLdqpoa+FETljbNyZmMctXmE8x5hND6d4ZlxG5RmNy6BBzACXCS6cTJAv3zfMx5nqNVSRFy1Ks8bpLvF84dMAHyk+30NfQADlIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANiBPu+ZlMUC/d8zLcqv7UyEEg5QgkgASR7qhVREuq2Q15JdrJNDqtZlMRKJnbb8l0PABatj0AAJAAAAAAABGixHIkE7k1CMk3EgDckRAACEgAAAAAeJGJIxWu0PYO6Wms9oRNYtGpc2WJY32XTcY7J4HUexHtVHGhLE6Jc9F0yPe4fNjJHW3t4/J4s0ntHpj3aoF0UcxzPRYhLAeoTz+QEZZntlttPM88z1Em1I1L7yrL8JWY/lDpgA+Ut8pfQ19AAOUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz0y9hUMyGCnXNyGb0K7x5Uz7F0JQeh4c9rUX9DiImUPZjfKjMkzUxPmV2TckMZZWmncVS97nr2lIAO3cQAAJAAAAASAwy1VPD+JKxvhc1JMZpGd1XPt8KHcY7SmKWn8OiDjux1P2dOv8A3ONd+N1K91kbfVSyMFlkYLysAK07F61dJGongxDw7E6xdZ3cksdf17O4411oBVvb6v8AvD/Uj2+r/vD/AFH9ayf6tlqBVm4jWN0ndzspkbi1amfWIvgrR/WsieNdZQV9uNVSL2mRu5KhnZjqZdZAvmi3OZwWcTx7w7IOfHjFI/vK5nmhtxTwzJ91I13kpXOO0K5paPcMoAOHIeXNR7VRyXuegTWZidwiYiY1LnzQLHmmbTFxyOrrkpqy0mqx+iqe1xefE/bd5efhzvtRqW8ByJc1WrZUXmQerFotHhgmsxPkMtM1HTJ6mI3KONUar3aqZeZlimKf3LRxcc2u2QAfMvcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAemP2HXMqztt3TABqEdYe3TOdkmSHgAERAAAkAAAGnU4jTU90V+074WnLqMZqH3SJEjb6qXVw2stphvb07skscTdqR7Wp4qaE2M0rL9WqyL4ZIcF8j5XbUj1c7xPHM0V48R7aacSP9OnNjU7l+6Y1ieqmlJVzy36yZy33Xy9DDzJLopWGmuKlfwjK448BqOP8Dp31SRkTzIzJScAmgHMBvJ3DmPAIQg3E8xuAgaak8xzCUEplnoN/wDIjcQiY22ocQqoV7EzlTguZ0IMcRcp4rfmacXfqTuK5xVt7VWwUstkFVBUNvDI1y703oZimtcrXXa5UVN6HSpMXmi7E33jOO9DPfjzHxZMnFtX4rADBTVUVSy8b0VeBnM0xNZZZrMe3lzUenaRFMTqWNdLoZwWUz5KepV2xUt7hgZSxsW65+ZnTQAi+W+T5SmuOtPiAArdAACQAAAAEANGuxfD8PRfa6qNi/AmbvRCvVnTumZdKOkfKvxPXZQ04+Llv6hE3iFvFz5vU9NMWmVepdFCn5Y7/rc0H9I8ZeqquITX/LknpY11/i8k+3E5IfVwfMqLpdi1NIiyz+0M3tkbn6oX/CMTgxWhbUwaLk5vwrwM2fh3w+ZdVtEt4AGR2AAAAAAAAAAAAAAAAAHKrMUfHI6OFtrZbS5iZiHVaTafDqi5XVxGrcv47uSIhHt9Un7d3yI7wt/r3WMXK8mJVf8Abf8A1QhcQq3Zdc5PJLfoO0H9e6xXPKvamrm+pWXSyPvtve7zU8Ed4dxxpWpHNXRbklURVTNFVDq4XWSPf1Mi7SWyVdUJi0S4vgmsbdYAEqAAAAAAAAAGrV10NKnbdd25qHDrMSnqbpfYj+FC7HhtZbjw2u69XisEF2tXrH8G6IcapxGoqLo5+yz4W5GoPU10xVq3Y+PWooyJ9QWtEeEDjoPUbtCQBOd9CPUByAJAgchvADkE3kkAASQACkgANw9SPUCUIzCX8SdwBPIBL8FI9QAJI4geo3ujejmOVrk3odmgxdHIkdVk7c7icTO4K744tHlTkw1v7XNFRUugK5QYm+mVGSdqLx3FghlZNGkkbtpqmHJimjzsmK2OfL2ACpWAAAAAABSOk3Sx6PfRYY+yJ2XzJqvgn8S/j8e+a2qubW07+MdI6DCkVkj+sn3RM158Ck4n0txKvuyKT2aJfdj1XzU4bnOcquc5yuVbqq3I3f8Ak9/BwMeOPMblRa8ylVuquc67lzup5JzGf1c3RWIjw4PQbhYepIFs+z+rVlfNSqvYkbtInihU8/q53OhiqnSKD9136GXl1i2G0Oqz5fTwAfKNIAAkAAAAAAAAAAAAAQuilXlzlev5lLTuKzUNVlTInBynN/TVxp8yxbtRkAUthkOYS/gPQBzA9LDMBfxN7CG7VXf4UNFMuB2MFitE+RfeWyHdI8qc9tUdMAFrzgABIAYKqqjpY1fIvkm9SYiZnwREzOoZXvaxiueqI1NVONXYxe7KTTe80q2vlq39pdmNNGoam7U2YsER5lvw8aI82enOV6qr1Vzl1VVPIBpa4iI9IJyJIJSEfInmAAsgJ3eAAjIZggMhdE/8mSKnmlt1cT3eSG1HhFY/VjWJ+ZTmb1j8q5yUr7lo6jI7DcCf787UXwb/ADMzcDhTvSSL8jic1Fc8mjg/Wo3fzLEmDUm/rF/7j2mE0X9kv+df4nP9irj+1RWsvpRkWRcIo10jc3yep5dgtIqZdYn/AHiORVP9qquZE5HcfgcfuTPTzS5gfgcyIuxKx3ndDqM1HVeTRysgbkuG1cf7La8W5mq5r2LZ7VavBTuLVn0tjJW3p5yJIJO3QAQEp3kAnmBGQyAAZcDZo62Skk2o1u3e2+prXBFqxaPLm1YtGpWulqo6qJHRr5pwNgqNPPJTybcbrKnzLHQ10dXHktnpq25hy4Zr5h5ubBNJ8NsAGdQAADhdMMQfQYK/q1s+Zerb/qfMfrU+ldNaJ9VgrnsRdqB23yPmuZ9F/FxX6Xhnye0egyG8lND01aMvAZE53HqBGXD5gnO4z+rgRkd7oUl+kUOXuuX5HC9SydA2bWOKqp3Y1Uz8vxhsmvt9HAB8k1AACQAAAAAAAAAAAAAK/ikexWu/NmWA5WNRXSOVE0yUiY8LsFtWcnKwyHHUeZQ9EsRlkTl4j1CDiMhxAEtbtORqJmuSFlpokhp2RpuQ4+EwdZUbap2WZ8zul1I1DFyb7nQADpmADRxGvSlZZtlkXROB1Ws2nUJrWbTqHqvr46RnxPXRtyuzzvqJVfKt1PEkj5ZFke5XOXep59T0MeKKQ9LDgikeTKykcT16kcS1oMggt4AITkRlncnI85WCU5AlEutkQ3qXCqieyuTq2/m1OZtFY8uL3rX20NxsU9HUVC/dxLZd6pZDvU2GU0GeztuTe7M3E8DNfk//ACyX5X/y48GBprPLyb/E34cPpYLbELVXiuam0Ci2W0s1st7ShEsmRIBXM7cAAIcgAAAAJAAAPD42SNVJGtcnih7BMTMJ250+D00iKrEWNfy6HOqMHqYrqxGyN8NSxAtrntVZXPeqnOarHWcio5NynnncttRSw1DbSxo7x3ocirwZ8aK+ncr0T3d5ppnrZrx8ms/JyRxPTmuY6z2q1d9zxbXIv9tUTEx4SlhzFs9BZPEmEmQTfYEcQh63nqKR0L0fGtnJoeMhkQTET4lZsOrm1cdl7MiaobpT4pHRSJJGuy5N5ZMPrm1cdlykb3kMWXDr7oebnwTWdw3AAZmd5ljbLE6ORLtcllRT5LjmHPwzFJqZydm+0xeLdx9cK100whK7D/aYmXmgS+XvN3oeh/H5/p5NT6lXeu42+c2+rEZcCeQyPpY8+mcyFkIy4ACchZLEE2QAW37PGItfVPt3WIl+ZUsi8fZ3HaCsktq5EMXOtrDLuntcwAfLtIAAAAAAAAAAAAAAAAa9bF1tK9u+10NggFZ1O1V43Gm82K6FYKp7dyrdDXzKJjy9Slu0RIigAh2X1zCdpbINxvYVTLNP1ju6zPzU6rG5cZLxWu3UoIOopWtXvLmpsgFzy5nc7kAMFVUMpoVkevknFSYiZnREb8QxYhWspYlst3u0QrUkj5Xq97lVy8T3UTvqJXSSLmu65i5noYscVh6eDDFI2ccyUIJTzLmhBB6IuA5jIcz3FHJNIjI2q5ynKJmKx5eDco8Nmqu1bYj+JTp0OExxWfUdt/Dch00S2SGfJn14qxZeT+KtWkw+CmTst2n73ONsAyWtNp8sc2mZ8gAOUAAAAAAAAAAAAAAAAgAASAAAAAMFTSQ1LbSsRV3LvODW4ZLTXe3tx8UTNCykF1MtqrceW1FORSOZ3q/CWyXkp+y/VW7lOG9j2PVj2q1yblNuPJF48PQx5q3h55gjkTu8CxcAWUADJDM+CRHxrZUPBBz/APqJiJjUrVQVjKuHabk5O8hslTpamSlmSRi+acSz007KiFska3RfkYc2LrO3l58XSWUhURUVF0XUkFMKHzLpbgy4ZiKyxN/o0y3avBd6HAy+rH2HE8PgxKifTVDcnJk7ei8T5VidBNhtbJSzou01clz7SblPo+ByoyV629wz3rqWpl9WIv8AWRPqPU9FwEZEgCD6N0Ci6vBHSW/EkVfQ+dep9W6MQdRgFKxdVZtLzPM/k76xaWYvbqgA+daAAAAAAAAAAAAAAAAAAAc7F4NuFJWpm3XyOLlwLS9iPYrV0XJSuVUK087o1vZM08iu8NnGv/lh8hu0GXiNckuVtT3HGsr2xsbm5SxUsCU8CRt3a+Zq4ZRdSzrZE+8dp4IdAurXTBmydp0AA6UPLnI1quctkTVSs4jVrVT8GNyan+pv41Wq3+jRqt1zf/A4qaKbePi1HaW7jYv9Sn0AINTaDcABCEpoNToYdhrqhyPlRWxJ/wDY5taKx5V3yRSNyw0VFLVvRGpZiauLFSUkVLHsxtz3u4mWNjY2IyNuy1NEPRgyZptLzsua15AAUqQAAAAAAAAAAAAAAAAAhzkY1XOWyIl1UmEK50k6VMweX2eCJJqhUut1s1pWHdOsYV10bTNTgjDjYzVOr8WqKjvbT12fJDSVqtWzm2Xgenjw0isbZ7Wna5UHT+oSRG4hTRvYvvRZKnJS908zKmnZNEt2Pajmr4HxE+vdGZOs6P0bv+miFHJxVrG4WY7TLqAAxLQAAAAANOuoI6tueUiaONwHVbTWfCa2ms7hUqinkp5NiVtl48TCWyrpYqqLYenku9CtVdLJSyqx6X4O4obsWWLPRw54t4lgJCAvaUWJ4ggCcuBuYbWLSy2X8N2qX0NIHNqxaNOL1i0alcWuRzUc1boulj0cTBa2y+zSu17qr+h2zzslJpZ5V6TSdBW+meD+30HtULPv4EvkneTgWQhURUsuh1gyziv2hVau4fFCfQ73S7CFw3Elkib/AEebtNXgu9Dgn1eHJGSkWhlmNScyCbrnmCwZaWFZ6qKFqZvcjT7FTxpDTxxp7jUafPug+GrVYmtU9F6qnz83bj6KfP8A8nli14pH4XYq+AAHlLgAAAAAAAAAAAAAAAAAADUr6NKqPLJ6d1TbATW01lW/Y6lHqzqX38sjpUGHdUvWT9p+5NyHSBEViFts9rRoABKkMFZUJTU75Happ5mc4GN1SyTdS1eyzXxUtxU7WWYqd7ac171ke57lzdmpCWIJPRiNQ9aI14RckjmSSlGXiECHQwugdUyJJIn3Tfmc2tFY3Li94pG5e8Lw3rlSWVLMTRPiO+1Ea1ERLImQa1rWo1qWRNLEnn5Mk3l5eTJN53IACpWFAxfptXw4jPBRJAkUb1a1ysuq/MuGN1raDCampdq1i281Pjyo+RznWVy3uq2NvFxxMbspyWlYm9OMZat1WB3nH/BSx9GelsuLVqUVTTsY9WqqPYuS8j5xzLB0G/5kh/ccaMuGnWZ04radvqQAPKaQAAAAAAAAAADmdJKn2TAquVFs5I7JnvU6ZVvtAn6vBGxXzlkT5FmGu7w5t6cPoBh7KrEJauZm0kKdm+m0p0ftFjjbQ0r0Y1Hq9UuieBl+zmNEwuok3uksYftI/q1El8tt36GyLTObSvX2qF6n1ToVKknRqn17F2+h8s5qfSPs+lV2BvYq9yRSzlR9jnH7WkAHltAAAAAAAAAYKqmjqolY9E8F3opnBMTMTsiZidwqVVTyU0yxycltqYUsWmvo21cCt99O6pWJGPikcxydpuSnoYckWh6eDL3jUoIyJBc0IFwpPMA1ytVFRc008CzYZWJVU6bS9tuTk4lYNmgqlpahHp3VyXyKs2OL1Z8+PtG4WoENcj2I5q3R2dyTzp8eHm+mjjGGw4rQSU0trqnYdbuu4nymuo5qCqfTVLNh7F0tqnE+yHLxrA6TGIbTN2JW9yVveT+R6HB5n0p629Kr036fKMvAy0tNLV1DKeBm1I9bIiJoWV/QXEeuVGVNOsd+8quTLysWfAOjtNg7Nu6y1CpnI7d5cD0838hjrTdfMqq4535bWCYZHheGx0zLK5Eu93xOOgAfPXvN7TazRHgABwkAAAAAAAAAAAAAAAAAAAAAAAAAAQw1c3s9M+RfdTIqb3K5yuXVVup2MenXsQIv5lsca5vwU6129Hi01GwWRdxJGRoaz0FtSQjVc5GtTNdCCfTPR0rqqdI25Imq8ELRDGyGJsbEs1qZGvh1IlLTonvuzcptmDNk7Tp5WbL3sAAoUgACFO+0Su6uhgo2rnK7bcnghv8AQ3C46TBGSPjaslSm066Xy4FT6bVPtXSJYUW6Q2j5rqfR6KNIqKCNNGsRPkbbbpjiFdfM7fMOmUEFP0gmZTMbG2yKqNTK5k6D3/3kh07rv0NXpTKs3SGscu6S3obXQZP/AHJDl7jjTO/pK/8AT6kADyWmAAAAAAAAAAACifaRMqvo4fN3+hez5z9ob74vCy/div8AM0cWPvV5PTpdAK6mhwuojmniiVsl+29G5czndO8Wpa+aCCjmbM2K6uc1bpcqfIjjkb4wxF+ynt40cS+/ZvLenrI76OR3yKFyLh9nMmziFTFfvRotuZHIjeOU0ny+hAA8lpAAAAAAAAAAAOVjNF1rOvjTtt1smp1SFS6WXRTul+s7dUvNZ2puXAWyN3E6X2apWydh+aGluPSrbtG3rUt2ruAW8EAOnZbyFvIkgId3A6raYtO9c25t8jrFRp5lgnbI3Vq3VC1wyJLE2RujkuYM9Os7edyMfW23sAGdlAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQq2RVXcSaeJzdTRSKi5uSyHdK9rJrHaYhX62b2irfJ42Q1+Z6I4np18Rp7FK9Y0ZcRzJz4gl0jLyOrgdL1kizuTst08zmRxrI9rW6uWyFrpIW09O2Nu5MyjNfrGmXk5NV6wzAA895wAAB5kekcbnro1FU9HPx6f2bBKuVFzSNU9TukblE+nymrqeuxaSqdmiy7XzPqMPSDCfYmy+302TLq3rERyZaW1Pke4jPienbFF4hni2mxiFR7VXVFQmkkiuTyO10Fz6SR/uO/QrvMsnQPPpGzwjcdZPGOUVny+nAA8dqgAAAAAAAAAAA+ZdPnqvSJWqvdiafTT5h08W/SWTP9m01cT5q8vpXB6jmSemoRdCydApNjpA1ufbjchXDtdDpFj6S0mfeVW+qFeWPslNfb6uADxmoAAAAAAAAAAAAAamJUyVNK5tu03NCsLdFVFLkVrFqdYKtVROzJmhr42T/LZxcnnq0RkCczY3o5kgcwIy4ncwKpux0DnZtzTyOJzMtJOtPUMkTRFz8irJXtXSnNTtRbQQ1yOajk0VLknnT4eUAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4mPSoskcSLpmp2yq4hL11ZK7gtjRx67tto41d321uRPoQSb3poJsAiXUgdPAqfbmdM5Mm6eZ3zVw6DqKRjd6pdTaPOy27WeRlv2sAAqVgAAFd6czdV0clamr3NaWIp/2iSImG08d+9Je3Itwf+yHN/T57wF9RyHHI9dmMyydAs+kbf8JxW+RZegP/ADEn+E4rzfCU19vpoAPHagAAAAAAAAAAD5b04dfpJN4NanyPqR8p6Yqq9Jarl+hr4nyVZPTh7kJ9BqRyPSUJOn0adsdIKJ3/AFEOXyN7A7/7ao1/6qHF/jKa+32QAHjT7a4AAQAAAAAAAAAAAHOxmHraNXNS6sW50Ty9qPY5q6KljvHbrbbqk9bbU7TcN57mjWOZ0aovZVUPB6cTuNvYpO42cidxAJSegG8JpvIFjwafraNGuXtMyXyOgV3BJurq9hVyflzLEefmrqzyc1et5AAUqkKtkuuhoTY5hsD1ZJVx7Sao27rFd6VYpO6rdRRPVsTE7VstrwK56nqYOB3r2supi3G30WHGsNndaOsiVV3OXZN5rkc1Fa5HIu9D5YZ6atqqV16eokjXgjsvQsv/ABsf5lM4f0+nApdD0sqolRtYxszOKZO/gWfD8Vo8QZenlTa3sXvJyMGXi5MfuFU0mrdABmcgAAAAAAeJJo4m7Ur2sbxVxOtkRMvYOVUdIcPgujZFldwYl/mcybpW9bpT0yJ4vU6ikrq8bJb1C0Apj+kuIu7qxt8mExdJa9i/edW9OCssT9Nb/Sy6XIHNwnFosSjWybErdWHSOJjTNas1nVgAEOWKpf1dNI/4UVSpKt3Kq5qualixqTYoVb8S2K4buPX7dt/Dr4mUkZAncaWxBtYbD19YxNyZqavjc7mAw2jkmVNVshVlt1rtTnt1o66AA8728oABAAAAUf7SHJsUbfFyl4KD9pCr7XRJdbbDl+Zo43zhXf0pe5BxF/EHqqAs3QD/AJh//U4rOu8tP2etVcbevCJSrN8JTX3D6SADx2oAAAAAAAAAAA+TdL1v0kq9e8n6H1k+S9LL/wC8dZn7xr4nylVk9OPuQZWCeZO5cz0lKDdwb/jNJ/it/U008zcwb/jFJn+1acX+JV9l3IAmgPHn21QAA5SAAAAAAAAAAAAAK5jUexXOW2T0uaB2sfZ2IpOCqhxD0sU7pD1OPbdIMgAWrwehOYCHqGTqpmSIvdW5bo3I+NHJo5LoU7OxZsJl62gYvDIy8ivjbHyqf6boAMcMD5zjb9vGKldF27GhkbuMf8Vqf8RTS3n0+L4Q3U+IALFjsS2pLHOjcjmOVqot0VFzI+rAaiY1KJjayYT0pliVIsQvJHp1id5PPiWulqYaqFJaeRsjF0VFPmBt4fiNTh8vWU71t7zV0U8/kcGtvNPam+L9PpQOZhGMwYnHZvYmanaYv+h0zxr47UnrZmmJiQ0MQxekoUVJX3k3MTX+RqY/iy0bEggX756Zr8KcSnvc57lc9yuVy3VV3nVaftt43E+pHa3p16zpHWT3bBswM8Eu5eZyZZZJnq+WR0jl3uzPNiN5bEQ9SmClPUFwSMyVxu1IvktwTn4gdTo29W4vHZdUVFLuUXAFVMXg81L0U5PbxedH/kAAVMTiY+/OKO+eanHOjjb9uu2fhahz7LbeelhjVIepx41SEAE552LV6EsWrDouqoo223XUrMDOsnYzi5C3NSzEb4GXk28aYeXb1CQAYmIAAAAACgfaP/XqL/DX9S/lB+0hP6XRORMthyfM0cX5q8npTBx0I4Djkeqzhbvs6T/1WoXhF/qVHkXP7OGf0uqkzyYiFOefsl1X2v4APIagAAAAAAAAAAD5N0u/5kq/3j6yfKumbFZ0lqctbL8jZw/lKrL6cLeTuUciD0VIb+AtV2N0bU161DQ5Fg6E0i1HSCKSy7MKK9VOMk6rKaxuX1IAHjS1AAIAAAAAAAAAAAAABoYyzaoHL8K3K4hacQbtUMyb1aVVOZu40/a38SftkyJIJ46mlsQNxNgBGR2sAkuksd9LKcbcup0MEk2a1G52clirLG6KORXdJWIAHnPKfOceRExipT85oeh0+kjdnG6jXNbnMt5n0+Dzjhup8QDjqM/EsdgAAAeosoHuCaSnlSWF6se1clQvmA4wzEoNl9m1DE7TU3+JQNDYoqqWiqEmhWzkSxm5HGjLX/qrJSLem1iEzqitlkfmquVORrZZ5GxXROhrZo3Jmj1Q1zxnsYtdI0cibJwBHIlYm3gOORGQAnLgRlwHmMuBA6OAp/6vBlvL2Ubo8iLi8PMvJVkeLzv/AGAAK4YVWxN23XyqnGxqmWrdtVUq31cpiQ9OnisPZxfCDkTu0UjIZWOnbdwePbr2flzLMcHAERamR3Bp3jDyJ+55nJndwAGdnAAAAAApf2jwq6mpJbZNcqF0OZ0gwxMVwmWlblIqbUa/mQtw3it9ubxuHyEjjqZ6uknop1hqonRyNWyoqGA9aLQza8nJS+fZvEvU1kv5kaUPI+mdAqZYMB6xyWWZ6u5FHIt9jukeVmAB5bQAAAAAAAAAAAfN/tBp1jxqOe3ZljT5H0g16qipa1rUq6eKZG6bbUWxdhyfTttzau3xXgTuU+wpgeFJ/wDjqb/40MrMLw+NUVlDTIqafdNNX9yv6VfTfJKDC63EpEZR08kl96JZqc9D6Z0ZwFmCUateqPqJM5HJ+h2UajURESyJoSUZeTN/DutNAAMywAAAAAAAAAAAAAAABiqUvTyJ+VSo28y4S/hO/dUqDu87zNnG9S28P8o9R6k5EZGttMvEnLh8iMicrbgBnoHbFZEv5jXy8D3EuzKxU3OQ5tHhzeN1lcAQ1btRfAk8yfbx59qJ0sjVuNOd8TWqcW3gWHpm22JRuRO8wrx9HxZ/8UNmP4g5DLwBesEGXAJYZALC3kMs1uPQByN/BsOfiVX1TVVGoiq5f0NFrVc5GtS7nZIh9A6P4YmHUKI5PvZO09bfIy8rP9Kvj2py36xpyOlVCrJ21bE7LsnZbyv8z6LV0zKumfDKnZchQq6kkoql0MiLlovFOJ4tLbht4WeJr0n21srakqCOOZ29AGXEXsm4lPMBzIy4gAdjowxHYq1eDFUuhVeiMd6meS2jbFqKMnt4fNneQIJIXQ4qywqEv40mfvLu8Twe5VXrX5+8v6nk9Svp69PjACMvAcTp07XR5MpneR2TkYAn3Mq+J1zzc3mzys3zkABUqAAAAAAAAeJYYpm7M0bJG8HNRxrphtAi3Sip/wD4k/gbYOu9kahijpoI/wAKCJn7rET9DKgAm0z7NQAA5SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAh4l/Cd5KVF3eXzLZU5U8i/lUqP1qbONHiW7ifkJy4/qQLmtuTzCaEcyQhBJHMghFvS4wLeCNeLUPZho12qSNfyoZjzLe3j29yqnTZmdNJuzaVXQunTKPaw5j7XVkhS+J7vAtvFDVhn7QBPAX8TYtAOYuAv4hBkdvo7gzq+ZJ5ktTsXNfiXgV5Mtcde1nFrdYb3RXB1VyV1S3JPw0Xf4lsIY1rWo1rUa1EsiISfPZ805b7ljtbtIc7F8MZiFOrckkbm11jogpidTspaazuHzieGSnmdHMmy9q5oY/FFLvjOEx18W02zZmp2XcfApk8MkEzo5Wq17eJorbb3ONyYyV1PtjHMgevqdNSeZGXEJ5fMfWoFv6Jw7OHyPt33ndOfgUXVYVCm9Uv6nQM958vnc1u2SZAAc1VqfL+NJn7y/qeeZlrG7NVKnBymE9SvqHsY/jCeZG5cwOR06dzo+v3MiePE65xej7spm+SnaPNzfJ5Wf5yAAqUgAAAAAAAAAAAAAAAAAAAAnSAADQAAgAAAAASAAAAAAAAAAAAAAAAAAAAANeuds0Uy8GlV0QsmMP2aB+euRWvU3caPtb+HH2yXJ5j61INLYkcyLDkoE8xkQmn8x4BE+lrw/8AqUX7psGvQf1OL902Dy7+3j39uZ0hh63Bp03tTaQ+e8/mfUZ4kmgkjXR7VQ+ZVEL4KiSJ6ZscqKer/HXjU1W4LMaefzGfED19T1Gk5/qOZ6jY+RyMjY5zl0RLqWfBui7lVs+IXRuqRXz5lOXPTFHlXbJFXPwPApcQcks20ymTVd7vIvMMUcELYom7LGpZEPTGtYxGsajWolkRCTwuRyLZbefTLa3aQAGZyAAAczGMJjxCLaREbM1Oy7j4KdME1nTqt5rPaHzeeGSnldHK1WvauaKY8rl5xnCWYhFtMs2dqdl3HwUpc8EtNKsczVY9F0U0Vt2h7XG5MZI1Ptj8z1EzrJWM+JUQ8nQwKBZ8UiREyYu0pK7LaK0mV3gZ1cLGJuaiGQAyz7fPT5kAAQrGKt2K+RNLrc07nTxxmzVtfuc05h6eOd0h62Cd0hJGVtR5Ena11MAciVMjV3tO8VnCZFZXx55OyLMYeRGrPM5NdXAAZ2cAAAAAAAABDnI1qucqIiaqqnLqsajju2BvWLxXJDumO1vTqlJt6dUwy1UEP4srW+FyuT4hVT325FRvBuSGrzNFeN+2qnFmfaxSYzSMWzdp3khrvx34IP8AM44uZJdGCsLo4tIdJ+N1Lu62NvK5idi1Yv7VrfJqGjnxGdzr6df07jBSPw2v9o1iot6h3I8+3Vf95k/zGDgRu1Jilf06+lT9Nhayq/vMv+dQlbVf3mT/ADKa/MknrU+nT9NlMQrE0qH87KekxStT9v6ohp+hO4jpU+lT9N9uM1aLmrF82mVmOTe/FGvktv4nLz4gicVJ/DmcFP07ceOxrbbhcni1bmePGKN+rnM/eaVwbtTicFVc8ak+ltiqoJfw5WO8lMyLcppliqqiL8OZzfC+XoVTxv0qtxJ/C2g4EONTNskzGvTimSnSp8Tpp7Ij9h3B2RTbDaqi2G9W6AlrAqVAAAAAAAAAAAAAIcrHn2pmMv3nHBv5HVx6W9QyNPdS5yz0cEapD1ONGqIBJHEuaAncB5WCEZaXGQTzPTM1RL6qRPpFvS2UqWpo0/KhlPMabMbU4Ih6PLtPmXjW9hzsRwWixHtTM2ZPjZkv8zogml5pO6yRMwqcnQ120vU1ibP5mZmWDodE116ire5ODGI3+JZwaJ5mXWtu/qWalBhtJQNtSwtau92rl5m2AZrXtbzZx7AAcgAAAAAAAAadfhtPXs2Zm9pNHJqhuAmJmE1tNZ3CpzdFqlH/AHE7HMvq/JTtYRhLMNiW7tuV2rjpA6nJMrr8i946zIADhQAADk49FeCN9u6tjh7i04hF11FK22drlVN/Htur0OJbddAJ9RxNDU9Qv6uZj01RULcx21Gjk3oU71LPhcvW0LFvmiWUy8mNxtj5Vfy3AAYmAAASAAAeXuRjHOVbI1LqejQxl6tw91lXtKiHdK7smkdp049fXyVb1ROzFfJvHxNPiCbHp1rFY8PXx0iseEbydxBBLtNr7gPUbl1CAch6gJORJBKAQEtwJ3gCPQnduIJAjkTu0HJR6hCORK6EepO5QIt4DIn1ICTkAnMbl1CHWweuekqU8rlVq91V3HdKhTqrZ41T4kLemhh5FdTt53JpFbAAMzMAAAAAAAAAGOZ/VQveuVkUmsbTVW8Sk62ukcm7JFNTdoenuVz1cqa5nk9Ssah6+OuqxAOJPqPU6doJyAAjLgZaZNupjS2rkMRt4Wzaro/BbnNp+2VeSdVlZ0yTIkA8uXkyAAhAAAAAAAAAAAAAAAAAAAAAAAAAAAIVLpZd5VK2LqauSPxuhbDi49B3J2p+VTRx7anTRx79bOOQMwbnpF/E62Az7Mj4VXvZocnmZaeVYJ2SNXNq5nF69q6VZa9qaW4HmNySRtemipdD0ebManTyp8SAAgAAANHF41koHonu2U3jy9qPY5qpkqWO6W1ZNZ62U4jcZqiJYJ3xqndWxi3anpxO3s0nddnjcZAnmSIJ3DUjOygSRzHMkCOBJFwAy4k7hvAScyNwzMscMsncYq+IRMxDFzJRTbbh0i957W/qZm4azV0jvkHE5aubck6iYfCmrnLzPSUNOiL2VXzX+YczmhyAdlKSn/s28wtJT/2acgfXhxr+IyOo+ghcnYVWqc2RixSOY7VA6rkizLQx9bWRNTjctiZIcPAYFWR8zkybkh3DDyLbtpg5Nu1gAGZnAAAAAAAADnY1N1dGrEXN62OiV7G5tuqSPcxC7BXtZbgp2u5xAJPResAjysTzCEb9QCQIyOpgTNqqe74W8Dl8zu4BHaB7195bFOadUlTyZ1R1gAec8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBVwe0Uz413pkZwTE6nZE6namuarHK1yZtWxHHI6mN03VzpM1Oy/JfM5Z6dLdo29bFfvU5Ekb/Eep0sd7BKnbhWB3eZmnih1SpUlQtNO2RNy5+Ra4npIxHt0cl0MGenW23m58fW23oAFDOAAAAAhx8cpVVEqGJe2T7HE3LkXF7EkY5r0uipZSrV1KtJUOjz2VzavgbePk3Gm/i5fHWWBPIakE8jU2I9CSOXyHHICSLeBPqABG5ckG4lrXPciNS7gIQzw0kk1lRuy34lNymoWs7cqbTvPJDcQKL5f01oaKKLNU2ncVNlNMsiSAom0ylONxcgLoHITzGfgQAG4D0JEOXZarl0Q4r1WeddnVy2Q3cRn/AGTf+4zYJR7SrUSJknd/iV3v1ja3f06bl1aKnSnpmxpqiZ+ZnAPNmd+WCZ3IADkAAAAAAAAeJHpHG5yrkiXKlNIssz5F1ctzvY3P1dMkbVzf+hXvU28amo7N3Ep47J36Dd4EDcam0JXQgeoQWFiSOY2kQtOGRdXQxpvVLlZp41lnYxEzcqJoW5ibLEam5LGXk28aYeVb8PQAMTEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw1UDamB0bt+ngVWWN0Ujo3pm1bFwORjVGr2+0Rpdze9behp4+TrOpaOPk6zqXDAJupuekhNx2cErES9NIviz+BxrnprlY5HMWzkzRSu9ItGleWneulxBqYdVpVQIt+23JyG2edavWdPKtXrOpAAcoAAANTEKRtXCrffTNqm2CaWms7TW01nanPYsb3MelnIuaEHfxag69izRJ941M04nAXeinpY7xeHqYcsZKouCeA3Fi5Fh9aC4RQJaiuciNS6nWpKVIGbTs3r8jDh9OiN61yZrobwZcuTzpPJRxG5CAoPr6yCEEpcByG4JcbgAAJAw1MzYY9pdV0QySSJGxXuXJDkSSSVU+V1vk1CJ8LMdPzL3SQPrKnZRdVu5fAtEbGxxoxqWRqWNbDqRtJAie+7Nym2efmydp0z5snadQAAoUgAAAAAAAABp4lUez0jl952SHVa7nRWO0uJilR7RWOVF7LeymZpkkbj0qx1jT2MdetdFkAuSduwjcpOhG7QBlxBNyMzkdDBYkkrEd8CXLGczAotmmdIqZvU6Zgz23Z5We3a0gAKVIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQqXRUXRSQBW8Uolpptpifdu08FNAt88LJ4XRyJdFKxW0r6WZWuTs7l4ob8GXtGpehx80WjrZr8xkShF8jQ1tiiqnUs6SN03pfVCzwSsmjbJGt0VCoaG9hlc6lk2HL927VOBnzYu3mGTkYd/dCyghrmvajmrdqpdCTDrXhgAAQgAAA42K4de9RA3P3mpv8Tsg7x3ms+HeO80ncKaQdrFMMVbz0yeLmp/ocVd6KejS8Wh6ePLF4Et4Eol3IhGfIm9ludrJdyNqNjaiJuPW7Qw0sqSwoqLmmSmbmGG3sQchv1J3BwchyI45jmSHIeSE8yOakJTyPD5GRsV71siHiepjhat17XBDlTzvnddy5bkJWUx7eqmodO/8m5Dr4RQdU3r5k7bk7KcEMOEYdtKlROmSd1FO35GPNl/EOM2X/FQAGNkAAAAAAAAAAAK5jFV11T1bV7MeXM7GJVPs1Kq3Tbdk0rHae7iqqa+PT/TXxse57ShLAlUztYGx6EICEkASQpO8bgPJ6Y1XvRqJm7LQG/g0Cy1iPVMo8zi89a7V5Lda7d+niSKBjE91EMgB5kzuXkTO5AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGvV0rKqFWOTPcvA2ATFpidpiZidwqNRTvppVjkTRfUxcci1VlJHVRK16WVNF4FbqaaSmkVkieS8T0MeWLQ9HBni3iWG3gMuBJBc0unhWIezr1Uy/drovA77VRzbot0Upvkp08LxLqLQzOXq10Xe0y5sO/MMWfB/qqwAhrmuaitW6LmhJj1phAAQAAAHMxDCknvLAiNk3pucdMHdLzSdwmtprO4U+WJ8L9iRmy5DxyLdNTxVDdmViOTicufBEW608tvyuQ105FZ9t1OTE/Jx4pXxP2mLZUN+LEUtaVll4oYpcMq4s+qV3i2ymq6N7L7bHN80L4vErZnHf8uu2sgX9oieeR6SeFdJWepxSLeR1tH0q/t3OvhT9oz1PDquBP2iL5Jc43yPbIZX9yN7vJCJtCPpUj8ug/EWJ3WOd5ms+unkTLsovA9w4VVy6s2E4uVDfgwNjc55Ff4NyQrtlpVzNsVHGjjkmfssY57uB2sPwhGWkqbK7czgdGCnigZsxMa1PAyma+ebemfJyJt4qIltAAZmcAAAAAAAAAAAhckuSc3GKxIIeqjXtv+SHdK9p06rWbTqHMxSq9oqbNvsMyQhsHs1Is8idt+TE4eJ7wuiWok6yRLRs3/EY8TqUmqLN7keSG+s6nVW6vuKVaY5AFrUZjkSMgIXyPcUSyK7cjUuq+B51OhURJR4cxi/iTLd3kc7iJ0rvfWoj8ufyLFg0HVUe0qdp+anCpIFqKpkSaKuZbGtRrUamiJYz8i+o6s3Kyf5SADExAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABhqaaOpiVkiXTcu9DMCYmYnwRMxO4VatopaR67SXYujkNUuMkbJGK2Ru01dynCr8JfEqyU6bTN7d6G3Fni3iW/DyInxZywTyPOWeSGhrjy6GG4i+mVGSdqP8A/ksMcjJWI9i7SLopTzZoq2Wkf2c2b2XM+XD28wy5uPvzVaga1JWw1TLxus7e1dUNkxzWY9sExMSAA5QAAAAABCoi6kgnaWN0ELlu6Ji+bUPPstP/AGEX+RDMDrvb9naf2xshhZ3Y2N8mohkS3AAibTKO0gAOQAAAAAAAAAAAAAACF0zAxzysghdI9cmldYyXEq1V+JbqvwoZsSq3VlQkEWbGrZPFTqUlPHQUiueudrvU11j6df8ArTWPp1/7LDiErKGibBCmbksn8TgGesqXVVQ6RdNGp4GuluBfirqNtmCnWu59pIHIz0lK+ql2G5IneXgWTOllrRWNywkGWpZGyocyJbtatrqeYYlmkbGxLqpG/GztHXs3sJpFnm6x6dhmfmp4xWbr6xbd1nZQ7D0bh+HORvut9VK7Ex1ROjES7nrmU1tuZsy0t3tN5/DsYDT7LHTu1dknkdcxwxpFE2NiZNSxkMmS3adseS3a2wAFbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc+uwuOou+OzJOPE4NRTS079mVip47i3HiSJkzFZIxHNXiaMeea+JaMXImnhTwderwZyXfTLdPgccp7HxvVsjVa5N1jZW9bem7Hmpf0Rvcx6OY5WuTgdejxlURGVSXT40/gcYC9It7MmKt/a3wzRztR0T0c3wUyFPjkfE7bjerXcUOjT43KxLTtSROKZKZb8aY+LHfjWj4u+DRhxall1fsLwcbjHskbdjmuTwzKJpaPbPNLR7egAc6cgAIAAAAAEAACQAAAAAAAAAAAAAOTi9dsJ7NF33a2/Q2MSrm0sey1byu7qcDRwuhdNJ7VUZpe6X3+Jox1iI7Sux1iI7WZ8Ioepb18qdtdPBDXxmtSRVp4l7Kd43cVrkpourYv3j9PAri3W91zVbl2Kvae0tGGk3nvJ9aBEyJ1y3/AKmxLRyRJExUvLJo3gX701WvFfEsMMT5pWxsS6qdyViUFAsUKXkcma2+ZloKJtHDtOS8rjSxapRqOhaqdY78ReCcCjv3vqGO2Sct9Q5HHW53sFo+qj6+RO2/S/A0cJolqZesf+Gz5qWJVRjFXREQjNk19sGfJ/iHFx6fNkDVy7zicCpc3VDk8Gmg9XV1flmr3WTwQssEaRRNjamSJY5vbpTq5vbpjisMgAMjKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYp6eKoZsSsRyceBlBMTMeiJmPTh1OCvbd1M7bT4XanLkifE7ZkY5rvFC4HiWKOZqtlY1yeJopyJj204+TavtUAdyowWJ11gerF4LmhzZ8PqoLq6Laam9uZprlrZrpnpZq+RLXOat2KrV4otjz5oPrU71tZqtmzHX1bO7UO55mwzGKtveRjvNpzuQtkczSsuZw0n8Ou3HZPfgavktjKzHY178D08lOHZOA3Ll8zn6FHE8aixsxmjdkrnN82qbMdZTy9yZq+F8yp2+rknE8asq7cSPwuQKpBW1MC/dyutwXNDr0WLtmVI502Hr7yaKU3wWqz3496uoAgM6gAAAAAAAAAAA1K6tZSR37z17rbnmvr2Urdhvamdo3+JrUmHPmk9pre05c0aXUpERuy2tY92a9DRS1sy1NTfYVb8LnUrKmOjp771ya091NRHSwq9+7JE4qalLSvnl9qrEu5e4xdGod9u3mfRNu3mfTiVKzPlV86ORzs8zDxzN/GXtfXORLdlLE4XQe1PV8ifdtX1NXeIrtujJ1xxMtjB6C6pUTJl7qKddYI1mSZW9tEsi3PbURqIiJZEMNXUspYXSOXyTiY7Xte3hgte2SzDiVYlLFZF+8d3U4HBpqeSsqNlN+bnBzpq6p02nOXJL6FioKRlJCjU7y95S2ZjFX/q+dYa/9ZIImQRNjjSzUQ1MZqOppFYneflyOgcKoa7EMV6tM42alOOO1u0/hTjjdtz+GfBKXYj9oembsm+R1iGNRjEa1MmpYk4yX7S4vbtOwAHDkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAhgmo6ef8WJqrxtmaEuBxLnDI5i8FzOsCyuW9Vlcl6+pVuXCKtl9lGyJ4OzNSSCaK/WRvb5oW8WLq8ifyvrybR7Uz61I+tS2yUlPLm+FjvG2ZrvwijdoxzF8HFkcmq2OXH6Vv61Gv/k7zsDg92WRPmYlwLhUr/k/md/Xq7/tUcb19SU+szrrgTv7yn+T+ZlgwSNjkWWRX+FrIJzVLcmmmzhL3yULFk10TyN08tajGo1qWRE04HowXmJnbzrTudgAOUAAAAGvWVcdJHtvzXc1N5NazaSImfDOqoiXXJOJzKnEnSP8AZ6Bu29dXcDUT2zFXrdVjgvyOvSUkVJHsxtuu93Eu61p7W6rSPLDQ4ckC9bMqyTLnddxsVNSymiV8i+Sb1FRUsp49p2ar3UTVVNenpXyy+1Vff9xm5hHmfMuffmUU1O+eVKmrzd7jPhNirnbT075HLmmSJczOVGtVVWyIV+okkxOsSOK/VtXJf9SaR2ncuqR2nc+mGjpZK6pVy5NvdziyRRsijaxiWa1MkPFLTspoUjjTJPme5ZWQxq+Rdlqbxe83nUGS83nUEsrIo3SSLZqFbqZ5sRqka1q2vZreBmqJ58UnSKFqpGmiL+p1qChZRx5dp66uU7jWOu/y7rrHXc+3nD6BlJHfWRdVN0Az2tNp3Ki1ptO5a1fP1FK5yd5cmp4mPC6X2eDaen3kmblPT4/aaxquT7uHROLjbOpt1rqE71GgAFbkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwTUkE0iSSx7Tm6XUzgmJmDaGojUsiWTdkeZZEijV7s0TROJ7IVEVc0TIRKGpBTukl9pqc3+62+TENzcDn4jVuZanp+1O/5HcbtLusdp01sSqn1MqUdNnde0qHQoKNlJCjW5uXvLxPOH0TaWO7u1I7Nym0umSZnV7eOsOr28da+mOonjp4lkldZE+ZyuoqcTk25rxQX7Ld6nT9ma+TrZe25NEXRORnIreKevbmtuvpiggjp40ZE2yfqZQCuZmZc7mZAumQBA8tajW2Q9ACfIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIa1ZU9QxGsTblf3WoeKKj6lVmlXanfm5eHgZo4EbI6Vy7Ujsr8E4GYsm2o1DrYACtAAAgAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/2Q==', '232332323', 1, 0, 0, '2023-05-09 22:25:26.000000', 0, '2024-10-25 15:40:31.000000', b'0', 24); INSERT INTO `m_user` VALUES (3, 1834763884364705792, 'dongdong', '5023047047573fd83145245f5201eeef', '8gb1qw', '东东', '东东', '11111111111', '11111111111', 1, NULL, NULL, 1, 1834763883194494976, 0, '2024-09-14 09:19:33.047847', 0, '2024-10-23 22:31:21.000000', b'0', 4); INSERT INTO `m_user` VALUES (4, 1834817021968625664, 'dongdong1', 'c0048f46ccbc7fd4079ef298e5e066db', 'uwgrap', '东东1号', '东东1号', '111', '111', 1, NULL, '1', 1, 1834763883194494976, 1834763884364705792, '2024-09-14 12:50:42.041340', 0, '2024-10-23 22:31:39.000000', b'0', 2); INSERT INTO `m_user` VALUES (5, 1836055978990497792, 'ceshi111', '41e43c75e3426adb407c05000f6f8501', 'et1t8b', '测试租户111', '测试租户111', '111', '111', 1, NULL, NULL, 1, 1836055976968843264, 0, '2024-09-17 22:53:52.392398', 1836055978990497792, '2024-09-17 23:17:41.221513', b'0', 1); INSERT INTO `m_user` VALUES (6, 1836056110997827584, 'ceshi222', 'c709119dd102a77fe92b972578ac226f', '5gxkja', '测试租户222', '测试租户222', '111', '111', 1, NULL, NULL, 1, 1836056110565814272, 0, '2024-09-17 22:54:23.866476', 0, '2024-09-17 22:54:23.866476', b'0', 0); INSERT INTO `m_user` VALUES (7, 1836059921829097472, 'ceshi111-1', '2dcc424ea713c122ae0dcf10ff90406f', 'sm74mg', 'ceshi111-1', '111', 'ceshi111-1', 'ceshi111-1', 1, NULL, NULL, 1, 1836055976968843264, 1836055978990497792, '2024-09-17 23:09:32.433005', 1836055978990497792, '2024-09-17 23:18:01.576329', b'0', 1); INSERT INTO `m_user` VALUES (8, 1836060007078326272, 'ceshi111-2', '8ffd827af99a14c8802e54ae1df6a5f2', '2l9538', 'ceshi111-2', 'ceshi111-2', 'ceshi111-2', 'ceshi111-2', 1, NULL, NULL, 1, 1836055976968843264, 1836055978990497792, '2024-09-17 23:09:52.749490', 1836055978990497792, '2024-09-17 23:18:09.068931', b'0', 1); INSERT INTO `m_user` VALUES (9, 1846431773870239744, 'test333', '32f7b6bf534219c83cfa97b2d3f53d53', 'qADvVl', '测试租户333', '测试租户333', NULL, '13888888888', 1, NULL, NULL, 1, 1846431773459197952, 0, '2024-10-16 14:03:34.624580', 0, '2024-10-16 14:03:34.624580', b'0', 0); INSERT INTO `m_user` VALUES (10, 1890404237300404224, 'test444', '3dc6fa0fbe21ce106f5b7bf078751558', 'B6pgBd', '测试租户444', '测试租户444', '123456@qq.com', '123456', 1, NULL, NULL, 1, 1890404237296209920, 0, '2025-02-14 22:14:26.000000', 0, '2025-02-14 22:14:26.000000', b'1', 0); INSERT INTO `m_user` VALUES (11, 1890405820369145856, 'test4', '6a9b52b45fbe14ec8fc34fb45f8c52df', 'mOUdML', '测试租户4', '4', '4', '4', 1, NULL, NULL, 1, 1890405820364951552, 0, '2025-02-14 22:20:43.000000', 0, '2025-02-14 22:20:43.000000', b'1', 0); INSERT INTO `m_user` VALUES (14, 1890406866181099521, 'test44', 'a8159b654d7cf51429c77eebca7b3afa', 'tqUSaV', '租户44', '租户44', '1', '1', 1, NULL, NULL, 1, 1890406866181099520, 0, '2025-02-14 22:24:53.000000', 0, '2025-02-14 22:24:53.000000', b'0', 0); -- ---------------------------- -- Table structure for m_user_dept -- ---------------------------- DROP TABLE IF EXISTS `m_user_dept`; CREATE TABLE `m_user_dept` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `user_id` bigint(0) NOT NULL COMMENT '用户ID', `dept_id` bigint(0) NOT NULL COMMENT '部门ID', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_dept_id`(`dept_id`) USING BTREE COMMENT '部门ID索引', INDEX `idx_user_id`(`user_id`) USING BTREE COMMENT '用户ID索引' ) ENGINE = InnoDB AUTO_INCREMENT = 70 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户与岗位关联表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_user_dept -- ---------------------------- INSERT INTO `m_user_dept` VALUES (19, 1679006018092986368, 1677964231673425920); INSERT INTO `m_user_dept` VALUES (20, 1679006018092986368, 1677964029214371840); INSERT INTO `m_user_dept` VALUES (21, 1679006018092986368, 1686021621496999936); INSERT INTO `m_user_dept` VALUES (22, 1679006018092986368, 1677964435873116160); INSERT INTO `m_user_dept` VALUES (32, 1836055978990497792, 1836060155556687872); INSERT INTO `m_user_dept` VALUES (33, 1836055978990497792, 1836060210875363328); INSERT INTO `m_user_dept` VALUES (34, 1836055978990497792, 1836060257859956736); INSERT INTO `m_user_dept` VALUES (35, 1836059921829097472, 1836060155556687872); INSERT INTO `m_user_dept` VALUES (36, 1836059921829097472, 1836060210875363328); INSERT INTO `m_user_dept` VALUES (37, 1836060007078326272, 1836060155556687872); INSERT INTO `m_user_dept` VALUES (38, 1836060007078326272, 1836060257859956736); INSERT INTO `m_user_dept` VALUES (60, 1834817021968625664, 1834774513448329216); INSERT INTO `m_user_dept` VALUES (61, 1834817021968625664, 1834773502369406976); INSERT INTO `m_user_dept` VALUES (62, 0, 1677964682431082496); INSERT INTO `m_user_dept` VALUES (63, 0, 1677964531410972672); INSERT INTO `m_user_dept` VALUES (64, 0, 1686349179535036416); INSERT INTO `m_user_dept` VALUES (65, 0, 1677964231673425920); INSERT INTO `m_user_dept` VALUES (66, 0, 1677964029214371840); INSERT INTO `m_user_dept` VALUES (67, 0, 1686019822887170048); INSERT INTO `m_user_dept` VALUES (68, 0, 1686349332929122304); INSERT INTO `m_user_dept` VALUES (69, 0, 1686021776396840960); -- ---------------------------- -- Table structure for m_user_post -- ---------------------------- DROP TABLE IF EXISTS `m_user_post`; CREATE TABLE `m_user_post` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `user_id` bigint(0) NOT NULL COMMENT '用户ID', `post_id` bigint(0) NOT NULL COMMENT '岗位ID', PRIMARY KEY (`id`) USING BTREE, INDEX `post_id_idx`(`post_id`) USING BTREE COMMENT '岗位ID索引', INDEX `user_id_idx`(`user_id`) USING BTREE COMMENT '用户ID索引' ) ENGINE = InnoDB AUTO_INCREMENT = 26 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户与岗位关联表 1用户-N岗位' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_user_post -- ---------------------------- INSERT INTO `m_user_post` VALUES (14, 1679006018092986368, 1676046492030717952); INSERT INTO `m_user_post` VALUES (17, 1836055978990497792, 1836060483333156864); INSERT INTO `m_user_post` VALUES (18, 1836059921829097472, 1836060404593487872); INSERT INTO `m_user_post` VALUES (19, 1836060007078326272, 1836060433332858880); INSERT INTO `m_user_post` VALUES (24, 0, 1676046492030717952); INSERT INTO `m_user_post` VALUES (25, 0, 1676044813214400512); -- ---------------------------- -- Table structure for m_user_role -- ---------------------------- DROP TABLE IF EXISTS `m_user_role`; CREATE TABLE `m_user_role` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `user_id` bigint(0) NOT NULL COMMENT '用户ID', `role_id` bigint(0) NOT NULL COMMENT '角色ID', PRIMARY KEY (`id`) USING BTREE, INDEX `role_id_idx`(`role_id`) USING BTREE COMMENT '角色ID索引', INDEX `user_id_idx`(`user_id`) USING BTREE COMMENT '用户ID索引' ) ENGINE = InnoDB AUTO_INCREMENT = 31 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户与角色关联表 1用户-N角色' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of m_user_role -- ---------------------------- INSERT INTO `m_user_role` VALUES (9, 1679006018092986368, 1677966412497596416); INSERT INTO `m_user_role` VALUES (16, 1836056110997827584, 1836056110565814273); INSERT INTO `m_user_role` VALUES (19, 1836055978990497792, 1836055976973037568); INSERT INTO `m_user_role` VALUES (20, 1836059921829097472, 1836057975659556864); INSERT INTO `m_user_role` VALUES (21, 1836060007078326272, 1836057975659556864); INSERT INTO `m_user_role` VALUES (24, 1846431773870239744, 1846431773459197953); INSERT INTO `m_user_role` VALUES (25, 1834763884364705792, 1834763883194494977); INSERT INTO `m_user_role` VALUES (26, 1834817021968625664, 1834790150900002816); INSERT INTO `m_user_role` VALUES (27, 0, 1671337763855073280); INSERT INTO `m_user_role` VALUES (30, 1890406866181099521, 1890406866659250176); SET FOREIGN_KEY_CHECKS = 1;