【升级】全新V3.0发布

pull/205/head v3.0
俞宝山 2024-05-07 04:29:18 +08:00
parent 3805aead41
commit f06cd305f4
584 changed files with 8188 additions and 9092 deletions

View File

@ -11,7 +11,7 @@ SnowySnowyAdmin是国内首个国密前后端分离快速开发平台
技术框架与密码结合,让更多的人认识密码,使用密码;更是让前后分离“密”不可分。 技术框架与密码结合,让更多的人认识密码,使用密码;更是让前后分离“密”不可分。
采用SpringBoot+MybatisPlus+AntDesignVue+Vite 等更多优秀组件及前沿技术开发,注释丰富,代码简洁,开箱即用! 采用SpringBoot+MybatisPlus+AntDesignVue+Vite 等更多组件及前沿技术开发,注释丰富,代码简洁,开箱即用!
Snowy谐音“小诺”恰应小诺团队名称意思为”下雪的、纯洁的“寓意框架追求简洁至上大道至简。 Snowy谐音“小诺”恰应小诺团队名称意思为”下雪的、纯洁的“寓意框架追求简洁至上大道至简。
@ -24,19 +24,19 @@ Snowy谐音“小诺”恰应小诺团队名称意思为”下雪的、纯
<img src="https://gitee.com/xiaonuobase/snowy/badge/fork.svg?theme=dark" alt="Gitee fork"> <img src="https://gitee.com/xiaonuobase/snowy/badge/fork.svg?theme=dark" alt="Gitee fork">
</a> </a>
<a href="https://www.antdv.com/docs/vue/introduce-cn/"> <a href="https://www.antdv.com/docs/vue/introduce-cn/">
<img src="https://img.shields.io/badge/vue-3.2-blue.svg" alt="bootstrap"> <img src="https://img.shields.io/badge/vue-3-blue.svg" alt="bootstrap">
</a> </a>
<a href="http://spring.io/projects/spring-boot"> <a href="http://spring.io/projects/spring-boot">
<img src="https://img.shields.io/badge/vite-2.8-green.svg" alt="spring-boot"> <img src="https://img.shields.io/badge/vite-5-green.svg" alt="spring-boot">
</a> </a>
<a href="https://www.antdv.com/docs/vue/introduce-cn/"> <a href="https://www.antdv.com/docs/vue/introduce-cn/">
<img src="https://img.shields.io/badge/vue--ant--design-3.2-blue.svg" alt="bootstrap"> <img src="https://img.shields.io/badge/vue--ant--design-4-blue.svg" alt="bootstrap">
</a> </a>
<a href="http://spring.io/projects/spring-boot"> <a href="http://spring.io/projects/spring-boot">
<img src="https://img.shields.io/badge/spring--boot-2.5-green.svg" alt="spring-boot"> <img src="https://img.shields.io/badge/spring--boot-3-green.svg" alt="spring-boot">
</a> </a>
<a href="http://mp.baomidou.com"> <a href="http://mp.baomidou.com">
<img src="https://img.shields.io/badge/mybatis--plus-3.5-blue.svg" alt="mybatis-plus"> <img src="https://img.shields.io/badge/mybatis--plus-3-blue.svg" alt="mybatis-plus">
</a> </a>
<a href="./LICENSE"> <a href="./LICENSE">
<img src="https://img.shields.io/badge/license-Apache%202-red" alt="license Apache 2.0"> <img src="https://img.shields.io/badge/license-Apache%202-red" alt="license Apache 2.0">
@ -62,9 +62,9 @@ github下载地址镜像[https://github.com/xiaonuobase/Snowy](https://
全栈工程师推荐idea 全栈工程师推荐idea
### 前端支撑 ### 前端支撑
| 插件 | 版本 | 用途 | | 插件 | 版本 | 用途 |
|--- | ----- | ----- | |--- |-----| ----- |
| node.js | ≥16 | JavaScript运行环境 | | node.js | ≥18 | JavaScript运行环境 |
### 启动前端 ### 启动前端
@ -75,12 +75,12 @@ npm install
npm run dev npm run dev
``` ```
### 后端支撑 ### 后端支撑
| 插件 | 版本 | 用途 | | 插件 | 版本 | 用途 |
| --- | ----- | ----- | | --- |-----------| ----- |
| jdk | 11 / 1.8 |java环境 | | jdk | 17 |java环境 |
| lombok | idea内 |代码简化插件 | | lombok | idea内 |代码简化插件 |
| maven | 最新版 |包管理工具 | | maven | 最新版 |包管理工具 |
| redis | 最新版 | 缓存库 | | redis | 最新版 | 缓存库 |
| mysql | 8.0 / 5.7 | 数据库 | | mysql | 8.0 / 5.7 | 数据库 |
### 启动后端 ### 启动后端
@ -88,7 +88,7 @@ npm run dev
## 代码结构 ## 代码结构
Snowy2.0框架对代码以插件化的模式进行分包使得包层级结构更加清晰合理同时降低了耦合度关于插件模块化开发的规范请查阅文档【SNOWY开源文档——前端手册or后端手册——开发规范】板块。 Snowy3.0框架对代码以插件化的模式进行分包使得包层级结构更加清晰合理同时降低了耦合度关于插件模块化开发的规范请查阅文档【SNOWY开源文档——前端手册or后端手册——开发规范】板块。
``` ```
snowy snowy
@ -141,6 +141,10 @@ snowy
1.x分支目前已停止新增功能只限于bug的维护推荐使用2x版本 1.x分支目前已停止新增功能只限于bug的维护推荐使用2x版本
- snowy2.5
2.x分支目前已停止新增功能只限于bug的维护可以平滑过渡至3x版本
## 视频教程 ## 视频教程
教程地址(免费开放):[https://space.bilibili.com/50101698/channel/collectiondetail?sid=739071](https://space.bilibili.com/50101698/channel/collectiondetail?sid=739071) 教程地址(免费开放):[https://space.bilibili.com/50101698/channel/collectiondetail?sid=739071](https://space.bilibili.com/50101698/channel/collectiondetail?sid=739071)

421
pom.xml
View File

@ -6,83 +6,23 @@
<groupId>vip.xiaonuo</groupId> <groupId>vip.xiaonuo</groupId>
<artifactId>snowy</artifactId> <artifactId>snowy</artifactId>
<name>snowy</name> <name>snowy</name>
<version>2.0.0</version> <version>3.0.0</version>
<description>snowy快速开发平台</description> <description>snowy快速开发平台</description>
<packaging>pom</packaging> <packaging>pom</packaging>
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.12</version> <version>3.2.1</version>
</parent> </parent>
<properties> <properties>
<java.version>1.8</java.version> <java.version>17</java.version>
<snowy.version>2.0.0</snowy.version> <snowy.version>3.0.0</snowy.version>
<spring-framework.version>5.3.26</spring-framework.version> <spring-boot.version>3.2.1</spring-boot.version>
<spring-framework.version>6.1.2</spring-framework.version>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 锁定依赖版本号 -->
<ali.oss.version>3.14.0</ali.oss.version>
<aliyun.sdk.dm.version>3.3.1</aliyun.sdk.dm.version>
<aliyun.sdk.dysmsapi.version>2.0.9</aliyun.sdk.dysmsapi.version>
<aliyun.sdk.ecs.version>3.1.0</aliyun.sdk.ecs.version>
<bcprov.jdk15on.version>1.70</bcprov.jdk15on.version>
<beetl.version>1.2.40.Beetl.RELEASE</beetl.version>
<checker.qual.version>3.31.0</checker.qual.version>
<commons.beanutils.version>1.9.4</commons.beanutils.version>
<commons.compress.version>1.22</commons.compress.version>
<commons.pool2.version>2.11.1</commons.pool2.version>
<druid.version>1.2.9</druid.version>
<dynamic.datasource.version>3.5.1</dynamic.datasource.version>
<easy.trans.version>2.1.7</easy.trans.version>
<easyexcel.version>3.2.1</easyexcel.version>
<easypoi.version>4.3.0</easypoi.version>
<fastjson.version>2.0.24</fastjson.version>
<gson.version>2.8.9</gson.version>
<guava.version>31.1-jre</guava.version>
<hutool.version>5.8.12</hutool.version>
<ip2region.version>2.6.3</ip2region.version>
<jackson.annotations.version>2.14.2</jackson.annotations.version>
<jackson.core.version>2.14.2</jackson.core.version>
<jackson.databind.version>2.14.2</jackson.databind.version>
<jackson.datatype.jdk8.version>2.14.2</jackson.datatype.jdk8.version>
<jackson.datatype.jsr310.version>2.14.2</jackson.datatype.jsr310.version>
<jackson.module.parameter.names.version>2.14.2</jackson.module.parameter.names.version>
<javax.mail.version>1.6.2</javax.mail.version>
<jettison.version>1.5.4</jettison.version>
<junit.version>4.13.2</junit.version>
<just.auth.version>1.16.5</just.auth.version>
<knife4j.version>2.0.9</knife4j.version>
<logback.classic.version>1.2.0</logback.classic.version>
<lombok.versin>1.18.22</lombok.versin>
<minio.version>8.5.2</minio.version>
<mssql.connector.java.version>9.2.1.jre8</mssql.connector.java.version>
<mybatis.plus.version>3.5.3.1</mybatis.plus.version>
<mybatis.version>3.5.10</mybatis.version>
<mysql.connector.java.version>8.0.28</mysql.connector.java.version>
<netty.common.version>4.1.89.Final</netty.common.version>
<netty.handler.version>4.1.89.Final</netty.handler.version>
<okhttp3.version>4.10.0</okhttp3.version>
<okio.version>3.3.0</okio.version>
<dm.connector.java.version>8.1.2.192</dm.connector.java.version>
<kingbase.connector.java.version>8.6.0</kingbase.connector.java.version>
<oracle.connector.java.version>21.5.0.0</oracle.connector.java.version>
<oracle.nls.orai18n.version>19.7.0.0</oracle.nls.orai18n.version>
<oshi.core.version>6.2.2</oshi.core.version>
<pinyin.version>2.5.1</pinyin.version>
<postgres.connector.java.version>42.2.25</postgres.connector.java.version>
<protobuf.java.version>3.21.12</protobuf.java.version>
<sa.token.version>1.31.0</sa.token.version>
<smcrypto.version>0.3.2</smcrypto.version>
<snakeyaml.version>2.0</snakeyaml.version>
<spring.context.version>5.3.19</spring.context.version>
<spring.security.crypto.version>5.8.9</spring.security.crypto.version>
<springfox.swagger2.version>2.10.5</springfox.swagger2.version>
<ten.cos.version>5.6.68</ten.cos.version>
<ten.sdk.ses.version>3.1.455</ten.sdk.ses.version>
<ten.sdk.sms.version>3.1.455</ten.sdk.sms.version>
<tomcat.embed.core.version>9.0.72</tomcat.embed.core.version>
</properties> </properties>
<modules> <modules>
@ -207,458 +147,282 @@
<version>${snowy.version}</version> <version>${snowy.version}</version>
</dependency> </dependency>
<!-- nashorn-core -->
<dependency>
<groupId>org.openjdk.nashorn</groupId>
<artifactId>nashorn-core</artifactId>
<version>15.4</version>
</dependency>
<!-- lombok --> <!-- lombok -->
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>${lombok.versin}</version> <version>1.18.30</version>
</dependency> </dependency>
<!-- druid --> <!-- druid -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId> <artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version> <version>1.2.21</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- mybatis-plus-core -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-core</artifactId>
<version>${mybatis.plus.version}</version>
</dependency> </dependency>
<!-- mybatis-plus --> <!-- mybatis-plus -->
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis.plus.version}</version> <version>3.5.5</version>
</dependency> </dependency>
<!-- easy-trans --> <!-- easy-trans -->
<dependency> <dependency>
<groupId>com.fhs-opensource</groupId> <groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-spring-boot-starter</artifactId> <artifactId>easy-trans-spring-boot-starter</artifactId>
<version>${easy.trans.version}</version> <version>3.0.0</version>
</dependency> </dependency>
<!-- easy-trans-mybatis-plus-extend --> <!-- easy-trans-mybatis-plus-extend -->
<dependency> <dependency>
<groupId>com.fhs-opensource</groupId> <groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-mybatis-plus-extend</artifactId> <artifactId>easy-trans-mybatis-plus-extend</artifactId>
<version>${easy.trans.version}</version> <version>3.0.0</version>
</dependency> </dependency>
<!-- redis --> <!-- redis -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId> <artifactId>commons-pool2</artifactId>
<version>${commons.pool2.version}</version> <version>2.12.0</version>
</dependency>
<!-- okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp3.version}</version>
</dependency>
<!-- okio -->
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>${okio.version}</version>
</dependency> </dependency>
<!-- hutool --> <!-- hutool -->
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>${hutool.version}</version> <version>5.8.25</version>
</dependency> </dependency>
<!-- pinyin4j --> <!-- pinyin4j -->
<dependency> <dependency>
<groupId>com.belerweb</groupId> <groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId> <artifactId>pinyin4j</artifactId>
<version>${pinyin.version}</version> <version>2.5.1</version>
</dependency> </dependency>
<!-- ip2region --> <!-- ip2region -->
<dependency> <dependency>
<groupId>org.lionsoul</groupId> <groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId> <artifactId>ip2region</artifactId>
<version>${ip2region.version}</version> <version>2.7.0</version>
</dependency> </dependency>
<!-- knife4j --> <!-- knife4j -->
<dependency> <dependency>
<groupId>com.github.xiaoymin</groupId> <groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId> <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version> <version>4.5.0</version>
</dependency> </dependency>
<!-- easy-poi --> <!-- easy-poi -->
<dependency> <dependency>
<groupId>cn.afterturn</groupId> <groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId> <artifactId>easypoi-spring-boot-starter</artifactId>
<version>${easypoi.version}</version> <version>4.4.0</version>
</dependency> </dependency>
<!-- sm-crypto --> <!-- sm-crypto -->
<dependency> <dependency>
<groupId>com.antherd</groupId> <groupId>com.antherd</groupId>
<artifactId>sm-crypto</artifactId> <artifactId>sm-crypto</artifactId>
<version>${smcrypto.version}</version> <version>0.3.2</version>
</dependency> </dependency>
<!-- easyexcel --> <!-- easyexcel -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId> <artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version> <version>3.3.3</version>
</dependency> </dependency>
<!-- sa-token-core --> <!-- Sa-token-core -->
<dependency> <dependency>
<groupId>cn.dev33</groupId> <groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId> <artifactId>sa-token-core</artifactId>
<version>${sa.token.version}</version> <version>1.37.0</version>
</dependency> </dependency>
<!-- sa-token --> <!-- Sa-token -->
<dependency> <dependency>
<groupId>cn.dev33</groupId> <groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId> <artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${sa.token.version}</version> <version>1.37.0</version>
</dependency> </dependency>
<!-- sa-token 整合 redis 使用jackson序列化方式 --> <!-- Sa-token 整合 redis 使用jackson序列化方式 -->
<dependency> <dependency>
<groupId>cn.dev33</groupId> <groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId> <artifactId>sa-token-redis-jackson</artifactId>
<version>${sa.token.version}</version> <version>1.37.0</version>
</dependency> </dependency>
<!-- Sa-Token插件权限缓存与业务缓存分离 --> <!-- Sa-Token插件权限缓存与业务缓存分离 -->
<dependency> <dependency>
<groupId>cn.dev33</groupId> <groupId>cn.dev33</groupId>
<artifactId>sa-token-alone-redis</artifactId> <artifactId>sa-token-alone-redis</artifactId>
<version>${sa.token.version}</version> <version>1.37.0</version>
</dependency> </dependency>
<!-- Sa-Token 插件整合SSO --> <!-- Sa-Token 插件整合SSO -->
<dependency> <dependency>
<groupId>cn.dev33</groupId> <groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId> <artifactId>sa-token-sso</artifactId>
<version>${sa.token.version}</version> <version>1.37.0</version>
</dependency> </dependency>
<!-- JustAuth 第三方登录 --> <!-- JustAuth 第三方登录 -->
<dependency> <dependency>
<groupId>me.zhyd.oauth</groupId> <groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId> <artifactId>JustAuth</artifactId>
<version>${just.auth.version}</version> <version>1.16.6</version>
</dependency> </dependency>
<!-- beetl模板引擎 --> <!-- beetl模板引擎 -->
<dependency> <dependency>
<groupId>com.ibeetl</groupId> <groupId>com.ibeetl</groupId>
<artifactId>beetl-framework-starter</artifactId> <artifactId>beetl-framework-starter</artifactId>
<version>${beetl.version}</version> <version>1.2.40.Beetl.RELEASE</version>
</dependency> </dependency>
<!--腾讯云上传文件客户端--> <!--x-file-storage文件sdk-->
<dependency>
<groupId>org.dromara.x-file-storage</groupId>
<artifactId>x-file-storage-spring</artifactId>
<version>2.1.0</version>
</dependency>
<!--腾讯云文件sdk-->
<dependency> <dependency>
<groupId>com.qcloud</groupId> <groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId> <artifactId>cos_api</artifactId>
<version>${ten.cos.version}</version> <version>5.6.199</version>
</dependency> </dependency>
<!--阿里云上传文件客户端--> <!--阿里云文件sdk-->
<dependency> <dependency>
<groupId>com.aliyun.oss</groupId> <groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId> <artifactId>aliyun-sdk-oss</artifactId>
<version>${ali.oss.version}</version> <version>3.15.1</version>
</dependency> </dependency>
<!--minio上传文件客户端--> <!--minio文件sdk-->
<dependency> <dependency>
<groupId>io.minio</groupId> <groupId>io.minio</groupId>
<artifactId>minio</artifactId> <artifactId>minio</artifactId>
<version>${minio.version}</version> <version>8.5.2</version>
</dependency> </dependency>
<!--java邮件发送--> <!--java邮件sdk-->
<dependency> <dependency>
<groupId>com.sun.mail</groupId> <groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId> <artifactId>jakarta.mail</artifactId>
<version>${javax.mail.version}</version> <version>2.0.1</version>
</dependency> </dependency>
<!--阿里云邮件发送--> <!--阿里云邮件sdk-->
<dependency> <dependency>
<groupId>com.aliyun</groupId> <groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dm</artifactId> <artifactId>dm20151123</artifactId>
<version>${aliyun.sdk.dm.version}</version> <version>1.0.6</version>
</dependency> </dependency>
<!-- 腾讯云邮件发送 --> <!-- 腾讯云邮件sdk -->
<dependency> <dependency>
<groupId>com.tencentcloudapi</groupId> <groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-ses</artifactId> <artifactId>tencentcloud-sdk-java-ses</artifactId>
<version>${ten.sdk.ses.version}</version> <version>3.1.944</version>
</dependency> </dependency>
<!--阿里云短信发送--> <!--阿里云短信sdk-->
<dependency> <dependency>
<groupId>com.aliyun</groupId> <groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId> <artifactId>dysmsapi20170525</artifactId>
<version>${aliyun.sdk.dysmsapi.version}</version> <version>2.0.24</version>
</dependency> </dependency>
<!--腾讯云短信发送--> <!--腾讯云短信sdk-->
<dependency> <dependency>
<groupId>com.tencentcloudapi</groupId> <groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-sms</artifactId> <artifactId>tencentcloud-sdk-java-sms</artifactId>
<version>${ten.sdk.sms.version}</version> <version>3.1.893</version>
</dependency>
<!-- sms4j短信sdk -->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-javase-plugin</artifactId>
<version>3.1.1</version>
</dependency> </dependency>
<!--系统硬件信息--> <!--系统硬件信息-->
<dependency> <dependency>
<groupId>com.github.oshi</groupId> <groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId> <artifactId>oshi-core</artifactId>
<version>${oshi.core.version}</version> <version>6.4.11</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.classic.version}</version>
</dependency>
<!-- gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<!-- guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- netty-common -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>${netty.common.version}</version>
</dependency>
<!-- netty-common -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>${netty.handler.version}</version>
</dependency>
<!-- jettison -->
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>${jettison.version}</version>
</dependency>
<!-- snakeyaml -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
</dependency>
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.context.version}</version>
</dependency>
<!-- spring-security-crypto -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
<version>${spring.security.crypto.version}</version>
</dependency>
<!-- springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.swagger2.version}</version>
</dependency>
<!-- tomcat-embed-core -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.embed.core.version}</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.annotations.version}</version>
</dependency>
<!-- jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.core.version}</version>
</dependency>
<!-- jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.databind.version}</version>
</dependency>
<!-- jackson-datatype -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>${jackson.datatype.jdk8.version}</version>
</dependency>
<!-- jackson-jsr310 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.datatype.jsr310.version}</version>
</dependency>
<!-- jackson-module-parameter-names -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
<version>${jackson.module.parameter.names.version}</version>
</dependency>
<!-- commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>${commons.beanutils.version}</version>
</dependency>
<!-- commons-compress -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${commons.compress.version}</version>
</dependency>
<!-- protobuf-java -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.java.version}</version>
</dependency>
<!-- checker-qual -->
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
<version>${checker.qual.version}</version>
</dependency>
<!-- bcprov-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bcprov.jdk15on.version}</version>
</dependency> </dependency>
<!-- dynamic-datasource --> <!-- dynamic-datasource -->
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId> <artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${dynamic.datasource.version}</version> <version>4.3.0</version>
</dependency> </dependency>
<!-- mysql --> <!-- mysql -->
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-j</artifactId>
<version>${mysql.connector.java.version}</version> <version>8.3.0</version>
</dependency> </dependency>
<!-- postgresql --> <!-- postgresql -->
<!--<dependency> <!--<dependency>
<groupId>org.postgresql</groupId> <groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
<version>${postgres.connector.java.version}</version> <version>42.7.1</version>
</dependency>--> </dependency>-->
<!-- 达梦数据库 --> <!-- 达梦数据库 -->
<!--<dependency> <!--<dependency>
<groupId>com.dameng</groupId> <groupId>com.dameng</groupId>
<artifactId>DmJdbcDriver18</artifactId> <artifactId>DmJdbcDriver18</artifactId>
<version>${dm.connector.java.version}</version> <version>8.1.3.62</version>
</dependency>--> </dependency>-->
<!-- 人大金仓数据库 --> <!-- 人大金仓数据库 -->
<!--<dependency> <!--<dependency>
<groupId>cn.com.kingbase</groupId> <groupId>cn.com.kingbase</groupId>
<artifactId>kingbase8</artifactId> <artifactId>kingbase8</artifactId>
<version>${kingbase.connector.java.version}</version> <version>8.6.0</version>
</dependency>--> </dependency>-->
<!-- oracle --> <!-- oracle -->
<!--<dependency> <!--<dependency>
<groupId>com.oracle.database.jdbc</groupId> <groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId> <artifactId>ojdbc10</artifactId>
<version>${oracle.connector.java.version}</version> <version>19.21.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.oracle.database.nls</groupId> <groupId>com.oracle.database.nls</groupId>
<artifactId>orai18n</artifactId> <artifactId>orai18n</artifactId>
<version>${oracle.nls.orai18n.version}</version> <version>23.3.0.23.09</version>
</dependency>--> </dependency>-->
<!-- mssql --> <!-- mssql -->
<!--<dependency> <!--<dependency>
<groupId>com.microsoft.sqlserver</groupId> <groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId> <artifactId>mssql-jdbc</artifactId>
<version>${mssql.connector.java.version}</version> <version>12.4.2.jre11</version>
</dependency>--> </dependency>-->
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
@ -668,16 +432,19 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version> <version>3.12.1</version>
<configuration> <configuration>
<source>1.8</source> <compilerArgs>
<target>1.8</target> <arg>-parameters</arg>
</compilerArgs>
<source>17</source>
<target>17</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version> <version>3.3.0</version>
<configuration> <configuration>
<attach>true</attach> <attach>true</attach>
</configuration> </configuration>
@ -694,10 +461,6 @@
<resources> <resources>
<resource> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<excludes>
<exclude>_sql/*</exclude>
<exclude>*.md</exclude>
</excludes>
</resource> </resource>
<resource> <resource>
<directory>src/main/java</directory> <directory>src/main/java</directory>

View File

@ -7,7 +7,7 @@
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<title>Snowy</title> <title>Snowy</title>
<style> <style>
.dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}} .dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1677FF;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}
.app-loading {position: absolute;top:0px;left:0px;right:0px;bottom:0px;display: flex;justify-content: center;align-items: center;flex-direction: column;background: #fff;} .app-loading {position: absolute;top:0px;left:0px;right:0px;bottom:0px;display: flex;justify-content: center;align-items: center;flex-direction: column;background: #fff;}
.app-loading__logo {margin-bottom: 30px;} .app-loading__logo {margin-bottom: 30px;}
.app-loading__logo img {width: 90px;vertical-align: bottom;} .app-loading__logo img {width: 90px;vertical-align: bottom;}

View File

@ -1,6 +1,6 @@
{ {
"name": "snowy-admin-web", "name": "snowy-admin-web",
"version": "1.0.0", "version": "3.0.0",
"private": true, "private": true,
"description": "小诺团队旗下Snowy前端基于Antdv3.2+Vue3.2+Vite2.8", "description": "小诺团队旗下Snowy前端基于Antdv3.2+Vue3.2+Vite2.8",
"repository": { "repository": {
@ -24,10 +24,10 @@
"@chenfengyuan/vue-qrcode": "2.0.0", "@chenfengyuan/vue-qrcode": "2.0.0",
"@highlightjs/vue-plugin": "2.1.0", "@highlightjs/vue-plugin": "2.1.0",
"@tinymce/tinymce-vue": "5.1.1", "@tinymce/tinymce-vue": "5.1.1",
"@vue-office/docx": "1.3.2", "@vue-office/docx": "1.6.0",
"@vue-office/excel": "1.4.7", "@vue-office/excel": "1.7.1",
"@vue-office/pdf": "1.5.5", "@vue-office/pdf": "1.6.4",
"ant-design-vue": "3.2.14", "ant-design-vue": "4.1.2",
"axios": "1.6.2", "axios": "1.6.2",
"cropperjs": "1.6.1", "cropperjs": "1.6.1",
"dayjs": "1.11.10", "dayjs": "1.11.10",
@ -48,12 +48,12 @@
"snowflake-id": "1.1.0", "snowflake-id": "1.1.0",
"sortablejs": "1.15.1", "sortablejs": "1.15.1",
"tinymce": "6.8.1", "tinymce": "6.8.1",
"vue": "3.3.10", "vue": "3.4.21",
"vue-cropper": "1.1.1", "vue-cropper": "1.1.1",
"vue-demi": "0.13.11", "vue-demi": "0.14.7",
"vue-i18n": "9.8.0", "vue-i18n": "9.8.0",
"vue-router": "4.2.5", "vue-router": "4.3.0",
"vue3-colorpicker": "2.2.3", "vue3-colorpicker": "2.3.0",
"vue3-tree-org": "4.2.2", "vue3-tree-org": "4.2.2",
"vuedraggable-es": "4.1.1" "vuedraggable-es": "4.1.1"
}, },
@ -79,7 +79,7 @@
"typescript": "5.3.3", "typescript": "5.3.3",
"unplugin-auto-import": "0.17.2", "unplugin-auto-import": "0.17.2",
"unplugin-vue-components": "0.26.0", "unplugin-vue-components": "0.26.0",
"vite": "5.1.4", "vite": "5.1.6",
"vite-plugin-compression": "0.5.1", "vite-plugin-compression": "0.5.1",
"vite-plugin-vue-setup-extend": "0.4.0", "vite-plugin-vue-setup-extend": "0.4.0",
"vue-eslint-parser": "9.3.2" "vue-eslint-parser": "9.3.2"

View File

@ -1,14 +1,40 @@
<template> <template>
<a-config-provider :locale="locale"> <a-config-provider
<router-view /> :locale="locale"
:theme="{
algorithm: store.theme === 'realDark' ? theme.darkAlgorithm : theme.defaultAlgorithm,
token: {
colorPrimary: `${store.themeColor}`,
borderRadius: roundedCornerStyleOpen ? 6 : 2
}
}"
>
<a-watermark
:content="loginUserWatermarkOpen && userInfo ? [userInfo.name, userInfo.account] : undefined"
class="admin-ui-main"
>
<router-view />
</a-watermark>
</a-config-provider> </a-config-provider>
</template> </template>
<script setup name="App"> <script setup name="App">
import i18n from '@/locales' import i18n from '@/locales'
import { globalStore } from '@/store' import { globalStore } from '@/store'
import { theme } from 'ant-design-vue'
const store = globalStore() const store = globalStore()
store.initTheme() store.initTheme()
const locale = i18n.global.messages.value[i18n.global.locale.value].lang const locale = i18n.global.messages.value[i18n.global.locale.value].lang
//
const userInfo = computed(() => {
return store.userInfo
})
//
const loginUserWatermarkOpen = computed(() => {
return store.loginUserWatermarkOpen
})
//
const roundedCornerStyleOpen = computed(() => {
return store.roundedCornerStyleOpen
})
</script> </script>

View File

@ -30,6 +30,10 @@ export default {
smsSendTencent(data) { smsSendTencent(data) {
return request('sendTencent', data) return request('sendTencent', data)
}, },
// 发送短信——小诺短信
smsSendXiaonuo(data) {
return request('sendXiaonuo', data)
},
// 删除短信 // 删除短信
smsDelete(data) { smsDelete(data) {
return request('delete', data) return request('delete', data)

View File

@ -97,5 +97,9 @@ export default {
// 根据id集合获取角色集合 // 根据id集合获取角色集合
userCenterGetRoleListByIdList(data) { userCenterGetRoleListByIdList(data) {
return request('getRoleListByIdList', data) return request('getRoleListByIdList', data)
},
// 根据id获取头像
userCenterGtAvatarById(data) {
return request('getAvatarById', data)
} }
} }

View File

@ -20,7 +20,7 @@
angleField: 'sold', angleField: 'sold',
colorField: 'sex', colorField: 'sex',
radius: 0.66, radius: 0.66,
color: ['#1890ff', '#f04864'], color: ['#1677FF', '#f04864'],
label: { label: {
content: (obj) => { content: (obj) => {
const group = new G.Group({}) const group = new G.Group({})
@ -46,7 +46,7 @@
text: obj.sex, text: obj.sex,
textAlign: 'center', textAlign: 'center',
textBaseline: 'top', textBaseline: 'top',
fill: obj.sex === '男' ? '#1890ff' : '#f04864' fill: obj.sex === '男' ? '#1677FF' : '#f04864'
} }
}) })
return group return group

View File

@ -20,7 +20,7 @@
}, },
areaStyle: () => { areaStyle: () => {
return { return {
fill: 'l(270) 0:#ffffff 0.5:#7ec2f3 1:#1890ff' fill: 'l(270) 0:#ffffff 0.5:#7ec2f3 1:#1677FF'
} }
} }
}) })

View File

@ -13,7 +13,7 @@
const props = defineProps({ const props = defineProps({
value: { value: {
type: String, type: String,
default: '#1890ff' default: '#1677FF'
} }
}) })
@ -22,11 +22,17 @@
} }
const update = (val) => { const update = (val) => {
showTxt(val)
emit('update:value', val)
}
onMounted(() => {
showTxt(props.value)
})
const showTxt = (val) => {
const currentColor = document.querySelector('.current-color') const currentColor = document.querySelector('.current-color')
if (currentColor) { if (currentColor) {
currentColor.textContent = val currentColor.textContent = val
} }
emit('update:value', val)
} }
</script> </script>

View File

@ -71,31 +71,31 @@ export const data = {
month: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], month: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
week: [ week: [
{ {
value: '1', value: '0',
label: '周日' label: '周日'
}, },
{ {
value: '2', value: '1',
label: '周一' label: '周一'
}, },
{ {
value: '3', value: '2',
label: '周二' label: '周二'
}, },
{ {
value: '4', value: '3',
label: '周三' label: '周三'
}, },
{ {
value: '5', value: '4',
label: '周四' label: '周四'
}, },
{ {
value: '6', value: '5',
label: '周五' label: '周五'
}, },
{ {
value: '7', value: '6',
label: '周六' label: '周六'
} }
], ],

View File

@ -22,7 +22,7 @@
</a-input> </a-input>
<a-modal <a-modal
title="CRON规则生成器" title="CRON规则生成器"
v-model:visible="modalVisible" v-model:open="modalVisible"
:width="580" :width="580"
@cancel="modalVisible = false" @cancel="modalVisible = false"
@ok="submit" @ok="submit"
@ -35,9 +35,7 @@
<template #tab> <template #tab>
<div class="cron-num"> <div class="cron-num">
<h2></h2> <h2></h2>
<a-tag :color="activeKey === '1' ? `var(--primary-color)` : ''" style="margin-right: 0px">{{ <a-tag :color="activeKey === '1' ? `var(--primary-color)` : ''" class="xn-mr">{{ value_second }}</a-tag>
value_second
}}</a-tag>
</div> </div>
</template> </template>
<a-form> <a-form>
@ -56,7 +54,7 @@
:max="59" :max="59"
controls-position="right" controls-position="right"
></a-input-number> ></a-input-number>
<span style="padding: 0 15px">-</span> <span class="xn-pd">-</span>
<a-input-number <a-input-number
v-model:value="dateValue.second.range.end" v-model:value="dateValue.second.range.end"
:min="0" :min="0"
@ -79,7 +77,7 @@
<a-select <a-select
v-model:value="dateValue.second.appoint" v-model:value="dateValue.second.appoint"
multiple multiple
style="width: 100%" class="xn-wd"
mode="multiple" mode="multiple"
placeholder="请选择" placeholder="请选择"
> >
@ -92,9 +90,7 @@
<template #tab> <template #tab>
<div class="cron-num"> <div class="cron-num">
<h2>分钟</h2> <h2>分钟</h2>
<a-tag :color="activeKey === '2' ? `var(--primary-color)` : ''" style="margin-right: 0px">{{ <a-tag :color="activeKey === '2' ? `var(--primary-color)` : ''" class="xn-mr">{{ value_minute }}</a-tag>
value_minute
}}</a-tag>
</div> </div>
</template> </template>
<a-form> <a-form>
@ -113,7 +109,7 @@
:max="59" :max="59"
controls-position="right" controls-position="right"
/> />
<span style="padding: 0 15px">-</span> <span class="xn-pd">-</span>
<a-input-number v-model:value="dateValue.minute.range.end" :min="0" :max="59" controls-position="right" /> <a-input-number v-model:value="dateValue.minute.range.end" :min="0" :max="59" controls-position="right" />
</a-form-item> </a-form-item>
<a-form-item label="间隔" v-if="dateValue.minute.type === '2'"> <a-form-item label="间隔" v-if="dateValue.minute.type === '2'">
@ -131,7 +127,7 @@
<a-select <a-select
v-model:value="dateValue.minute.appoint" v-model:value="dateValue.minute.appoint"
multiple multiple
style="width: 100%" class="xn-wd"
mode="multiple" mode="multiple"
placeholder="请选择" placeholder="请选择"
> >
@ -144,9 +140,7 @@
<template #tab> <template #tab>
<div class="cron-num"> <div class="cron-num">
<h2>小时</h2> <h2>小时</h2>
<a-tag :color="activeKey === '3' ? `var(--primary-color)` : ''" style="margin-right: 0px">{{ <a-tag :color="activeKey === '3' ? `var(--primary-color)` : ''" class="xn-mr">{{ value_hour }}</a-tag>
value_hour
}}</a-tag>
</div> </div>
</template> </template>
<a-form> <a-form>
@ -160,7 +154,7 @@
</a-form-item> </a-form-item>
<a-form-item label="范围" v-if="dateValue.hour.type === '1'"> <a-form-item label="范围" v-if="dateValue.hour.type === '1'">
<a-input-number v-model:value="dateValue.hour.range.start" :min="0" :max="23" controls-position="right" /> <a-input-number v-model:value="dateValue.hour.range.start" :min="0" :max="23" controls-position="right" />
<span style="padding: 0 15px">-</span> <span class="xn-pd">-</span>
<a-input-number v-model:value="dateValue.hour.range.end" :min="0" :max="23" controls-position="right" /> <a-input-number v-model:value="dateValue.hour.range.end" :min="0" :max="23" controls-position="right" />
</a-form-item> </a-form-item>
<a-form-item label="间隔" v-if="dateValue.hour.type === '2'"> <a-form-item label="间隔" v-if="dateValue.hour.type === '2'">
@ -173,7 +167,7 @@
<a-select <a-select
v-model:value="dateValue.hour.appoint" v-model:value="dateValue.hour.appoint"
multiple multiple
style="width: 100%" class="xn-wd"
mode="multiple" mode="multiple"
placeholder="请选择" placeholder="请选择"
> >
@ -186,9 +180,7 @@
<template #tab> <template #tab>
<div class="cron-num"> <div class="cron-num">
<h2></h2> <h2></h2>
<a-tag :color="activeKey === '4' ? `var(--primary-color)` : ''" style="margin-right: 0px">{{ <a-tag :color="activeKey === '4' ? `var(--primary-color)` : ''" class="xn-mr">{{ value_day }}</a-tag>
value_day
}}</a-tag>
</div> </div>
</template> </template>
<a-form> <a-form>
@ -204,7 +196,7 @@
</a-form-item> </a-form-item>
<a-form-item label="范围" v-if="dateValue.day.type === '1'"> <a-form-item label="范围" v-if="dateValue.day.type === '1'">
<a-input-number v-model:value="dateValue.day.range.start" :min="1" :max="31" controls-position="right" /> <a-input-number v-model:value="dateValue.day.range.start" :min="1" :max="31" controls-position="right" />
<span style="padding: 0 15px">-</span> <span class="xn-pd">-</span>
<a-input-number v-model:value="dateValue.day.range.end" :min="1" :max="31" controls-position="right" /> <a-input-number v-model:value="dateValue.day.range.end" :min="1" :max="31" controls-position="right" />
</a-form-item> </a-form-item>
<a-form-item label="间隔" v-if="dateValue.day.type === '2'"> <a-form-item label="间隔" v-if="dateValue.day.type === '2'">
@ -217,7 +209,7 @@
<a-select <a-select
v-model:value="dateValue.day.appoint" v-model:value="dateValue.day.appoint"
multiple multiple
style="width: 100%" class="xn-wd"
mode="multiple" mode="multiple"
placeholder="请选择" placeholder="请选择"
> >
@ -230,9 +222,7 @@
<template #tab> <template #tab>
<div class="cron-num"> <div class="cron-num">
<h2></h2> <h2></h2>
<a-tag :color="activeKey === '5' ? `var(--primary-color)` : ''" style="margin-right: 0px">{{ <a-tag :color="activeKey === '5' ? `var(--primary-color)` : ''" class="xn-mr">{{ value_month }}</a-tag>
value_month
}}</a-tag>
</div> </div>
</template> </template>
<a-form> <a-form>
@ -251,7 +241,7 @@
:max="12" :max="12"
controls-position="right" controls-position="right"
/> />
<span style="padding: 0 15px">-</span> <span class="xn-pd">-</span>
<a-input-number v-model:value="dateValue.month.range.end" :min="1" :max="12" controls-position="right" /> <a-input-number v-model:value="dateValue.month.range.end" :min="1" :max="12" controls-position="right" />
</a-form-item> </a-form-item>
<a-form-item label="间隔" v-if="dateValue.month.type === '2'"> <a-form-item label="间隔" v-if="dateValue.month.type === '2'">
@ -264,7 +254,7 @@
<a-select <a-select
v-model:value="dateValue.month.appoint" v-model:value="dateValue.month.appoint"
multiple multiple
style="width: 100%" class="xn-wd"
mode="multiple" mode="multiple"
placeholder="请选择" placeholder="请选择"
> >
@ -277,9 +267,7 @@
<template #tab> <template #tab>
<div class="cron-num"> <div class="cron-num">
<h2></h2> <h2></h2>
<a-tag :color="activeKey === '6' ? `var(--primary-color)` : ''" style="margin-right: 0px">{{ <a-tag :color="activeKey === '6' ? `var(--primary-color)` : ''" class="xn-mr">{{ value_week }}</a-tag>
value_week
}}</a-tag>
</div> </div>
</template> </template>
<a-form> <a-form>
@ -303,7 +291,7 @@
:value="item.value" :value="item.value"
/> />
</a-select> </a-select>
<span style="padding: 0 15px">-</span> <span class="xn-pd">-</span>
<a-select v-model:value="dateValue.week.range.end" placeholder="请选择"> <a-select v-model:value="dateValue.week.range.end" placeholder="请选择">
<a-select-option <a-select-option
v-for="(item, index) in data.week" v-for="(item, index) in data.week"
@ -331,7 +319,7 @@
<a-select <a-select
v-model:value="dateValue.week.appoint" v-model:value="dateValue.week.appoint"
multiple multiple
style="width: 100%" class="xn-wd"
mode="multiple" mode="multiple"
placeholder="请选择" placeholder="请选择"
> >
@ -360,9 +348,7 @@
<template #tab> <template #tab>
<div class="cron-num"> <div class="cron-num">
<h2></h2> <h2></h2>
<a-tag :color="activeKey === '7' ? `var(--primary-color)` : ''" style="margin-right: 0px">{{ <a-tag :color="activeKey === '7' ? `var(--primary-color)` : ''" class="xn-mr">{{ value_year }}</a-tag>
value_year
}}</a-tag>
</div> </div>
</template> </template>
<a-form> <a-form>
@ -377,7 +363,7 @@
</a-form-item> </a-form-item>
<a-form-item label="范围" v-if="dateValue.year.type === '1'"> <a-form-item label="范围" v-if="dateValue.year.type === '1'">
<a-input-number v-model:value="dateValue.year.range.start" controls-position="right" /> <a-input-number v-model:value="dateValue.year.range.start" controls-position="right" />
<span style="padding: 0 15px">-</span> <span class="xn-pd">-</span>
<a-input-number v-model:value="dateValue.year.range.end" controls-position="right" /> <a-input-number v-model:value="dateValue.year.range.end" controls-position="right" />
</a-form-item> </a-form-item>
<a-form-item label="间隔" v-if="dateValue.year.type === '2'"> <a-form-item label="间隔" v-if="dateValue.year.type === '2'">
@ -390,7 +376,7 @@
<a-select <a-select
v-model:value="dateValue.year.appoint" v-model:value="dateValue.year.appoint"
multiple multiple
style="width: 100%" class="xn-wd"
mode="multiple" mode="multiple"
placeholder="请选择" placeholder="请选择"
> >
@ -580,6 +566,9 @@
} }
}) })
watch(props, (newValue) => { watch(props, (newValue) => {
if (newValue.modelValue === '') {
defaultValue.value = ''
}
if (newValue.modelValue) { if (newValue.modelValue) {
defaultValue.value = newValue.modelValue defaultValue.value = newValue.modelValue
} }
@ -758,4 +747,10 @@
font-size: 12px; font-size: 12px;
font-weight: normal; font-weight: normal;
} }
.xn-mr {
margin-right: 0px;
}
.xn-pd {
padding: 0 15px;
}
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<a-modal ref="cropmodal" v-model:visible="visible" :width="700" title="头像裁剪" @cancel="handleClear" @ok="cropOk"> <a-modal v-model:open="visible" :width="700" title="头像裁剪" @cancel="handleClear" @ok="cropOk">
<a-row :gutter="10"> <a-row :gutter="10">
<!-- 裁剪区 --> <!-- 裁剪区 -->
<a-col :span="17"> <a-col :span="17">
@ -26,27 +26,27 @@
/> />
</a-col> </a-col>
<a-col :span="7"> <a-col :span="7">
<div style="width: 165px; height: 165px; border: 1px solid #e9e9e9; border-radius: 2px"> <div class="xn-cj">
<a-image :src="previewUrl" /> <a-image :src="previewUrl" />
</div> </div>
<div style="padding-top: 10px; display: flex"> <div class="xn-cj-two">
<div style="height: 100px; width: 100px; border: 1px solid #e9e9e9; border-radius: 2px"> <div>
<a-image :src="previewUrl" /> <a-image :src="previewUrl" />
</div> </div>
<div style="height: 60px; width: 60px; border: 1px solid #e9e9e9; margin-left: 5px; border-radius: 2px"> <div>
<a-image :src="previewUrl" /> <a-image :src="previewUrl" />
</div> </div>
</div> </div>
</a-col> </a-col>
</a-row> </a-row>
<div style="text-align: center; padding-top: 10px"> <div class="xn-tl">
<a-space> <a-space>
<a-button @click="cropper.changeScale(1)"></a-button> <a-button @click="cropper.changeScale(1)"></a-button>
<a-button @click="cropper.changeScale(-1)"></a-button> <a-button @click="cropper.changeScale(-1)"></a-button>
<a-button @click="cropper.rotateLeft()"></a-button> <a-button @click="cropper.rotateLeft()"></a-button>
<a-button @click="cropper.rotateRight()"></a-button> <a-button @click="cropper.rotateRight()"></a-button>
</a-space> </a-space>
<div style="padding-top: 10px"> <div class="xn-pt">
<a-upload <a-upload
name="file" name="file"
:show-upload-list="false" :show-upload-list="false"
@ -60,7 +60,7 @@
</a-button> </a-button>
</a-upload> </a-upload>
</div> </div>
<div style="padding-top: 10px">请上传图片文件建议不超过2M</div> <div class="xn-pt">请上传图片文件建议不超过2M</div>
</div> </div>
</a-modal> </a-modal>
</template> </template>
@ -152,4 +152,35 @@
.cropper { .cropper {
height: 280px; height: 280px;
} }
.xn-cj {
width: 165px;
height: 165px;
border: 1px solid #e9e9e9;
border-radius: 2px
}
.xn-pt {
padding-top: 10px;
}
.xn-tl {
text-align: center;
padding-top: 10px
}
.xn-cj-two {
padding-top: 10px;
display: flex
}
.xn-cj-two > div:first-child {
height: 100px;
width: 100px;
border: 1px solid #e9e9e9;
border-radius: 2px
}
.xn-cj-two > div:nth-child(2) {
height: 60px;
width: 60px;
border: 1px solid #e9e9e9;
margin-left: 5px;
border-radius: 2px
}
</style> </style>

View File

@ -1,7 +1,7 @@
<template> <template>
<a-modal <a-modal
:class="['my-modal', modalClass, simpleClass]" :class="['my-modal', modalClass, simpleClass]"
:visible="visible" :open="visible"
v-bind="props" v-bind="props"
:width="modalWidth" :width="modalWidth"
:wrap-class-name="wrapClassName + fullscreenClass" :wrap-class-name="wrapClassName + fullscreenClass"

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="baiduMap" :style="{ height: `${height}px` }"> <div class="baiduMap" :style="{ height: `${height}px` }">
<div :id="`container-${mid}`" style="width: 100%; height: 100%">地图资源加载中...</div> <div :id="`container-${mid}`" class="xn-wh">地图资源加载中...</div>
</div> </div>
</template> </template>
<!--BMapGL官网https://lbsyun.baidu.com/index.php?title=jspopularGL--> <!--BMapGL官网https://lbsyun.baidu.com/index.php?title=jspopularGL-->
@ -332,6 +332,10 @@
</script> </script>
<style lang="less"> <style lang="less">
.xn-wh {
width: 100%;
height: 100%
}
.baiduMap { .baiduMap {
padding: 0; padding: 0;
margin: 0; margin: 0;

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="gaodeMap" :style="{ height: `${height}px` }"> <div class="gaodeMap" :style="{ height: `${height}px` }">
<div :id="`container-${mid}`" style="width: 100%; height: 100%">地图资源加载中...</div> <div :id="`container-${mid}`" class="xn-wh">地图资源加载中...</div>
</div> </div>
</template> </template>
<!--AMap官网https://lbs.amap.com/api/javascript-api-v2/summary--> <!--AMap官网https://lbs.amap.com/api/javascript-api-v2/summary-->
@ -353,6 +353,10 @@
</script> </script>
<style lang="less"> <style lang="less">
.xn-wh {
width: 100%;
height: 100%;
}
.gaodeMap { .gaodeMap {
padding: 0; padding: 0;
margin: 0; margin: 0;

View File

@ -44,5 +44,43 @@
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import './index.less'; .ant-pro-number-info-subtitle {
color: @text-color-secondary;
font-size: @font-size-base;
height: 22px;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
white-space: nowrap;
}
.number-info-value {
margin-top: 4px;
font-size: 0;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
white-space: nowrap;
& > span {
color: @heading-color;
display: inline-block;
line-height: 32px;
height: 32px;
font-size: 24px;
margin-right: 32px;
}
.sub-total {
color: @text-color-secondary;
font-size: @font-size-lg;
vertical-align: top;
margin-right: 0;
i {
font-size: 12px;
transform: scale(0.82);
margin-left: 4px;
}
}
}
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<a-modal <a-modal
v-model:visible="visible" v-model:open="visible"
title="移动端图标选择" title="移动端图标选择"
:mask-closable="false" :mask-closable="false"
:width="800" :width="800"

View File

@ -1,6 +1,6 @@
<template> <template>
<a-modal <a-modal
v-model:visible="visible" v-model:open="visible"
title="图标选择" title="图标选择"
:mask-closable="false" :mask-closable="false"
:width="800" :width="800"

View File

@ -1,6 +1,6 @@
<template> <template>
<a-modal <a-modal
v-model:visible="visible" v-model:open="visible"
title="机构选择" title="机构选择"
:width="1000" :width="1000"
:mask-closable="false" :mask-closable="false"
@ -22,7 +22,7 @@
</a-card> </a-card>
</a-col> </a-col>
<a-col :span="11"> <a-col :span="11">
<div class="table-operator" style="margin-bottom: 10px"> <div class="table-operator xn-mb10">
<a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState"> <a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="12"> <a-col :span="12">
@ -32,7 +32,7 @@
</a-col> </a-col>
<a-col :span="12"> <a-col :span="12">
<a-button type="primary" class="primarySele" @click="loadData()"> </a-button> <a-button type="primary" class="primarySele" @click="loadData()"> </a-button>
<a-button class="snowy-buttom-left" @click="() => reset()"> 重置 </a-button> <a-button class="snowy-button-left" @click="() => reset()"> 重置 </a-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
@ -50,7 +50,7 @@
> >
<template #title> <template #title>
<span>待选择列表 {{ tableRecordNum }} </span> <span>待选择列表 {{ tableRecordNum }} </span>
<div v-if="!radioModel" style="float: right"> <div v-if="!radioModel" class="xn-fd">
<a-button type="dashed" size="small" @click="addAllPageRecord"></a-button> <a-button type="dashed" size="small" @click="addAllPageRecord"></a-button>
</div> </div>
</template> </template>
@ -59,7 +59,7 @@
{{ $TOOL.dictTypeData('ORG_CATEGORY', record.category) }} {{ $TOOL.dictTypeData('ORG_CATEGORY', record.category) }}
</template> </template>
<template v-if="column.dataIndex === 'action'"> <template v-if="column.dataIndex === 'action'">
<a-button type="dashed" size="small" @click="addRecord(record)"></a-button> <a-button type="dashed" size="small" @click="addRecord(record)"><PlusOutlined /></a-button>
</template> </template>
</template> </template>
</a-table> </a-table>
@ -89,13 +89,13 @@
> >
<template #title> <template #title>
<span>已选择: {{ selectedData.length }}</span> <span>已选择: {{ selectedData.length }}</span>
<div v-if="!radioModel" style="float: right"> <div v-if="!radioModel" class="xn-fd">
<a-button type="dashed" danger size="small" @click="delAllRecord"></a-button> <a-button type="dashed" danger size="small" @click="delAllRecord"></a-button>
</div> </div>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'action'"> <template v-if="column.dataIndex === 'action'">
<a-button type="dashed" danger size="small" @click="delRecord(record)"></a-button> <a-button type="dashed" danger size="small" @click="delRecord(record)"><MinusOutlined /></a-button>
</template> </template>
</template> </template>
</a-table> </a-table>
@ -116,7 +116,7 @@
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
width: 80 width: 50
}, },
{ {
title: '机构名', title: '机构名',
@ -134,7 +134,7 @@
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
width: 80 width: 50
}, },
{ {
title: '机构名', title: '机构名',
@ -250,10 +250,7 @@
loadData() loadData()
} }
const judge = () => { const judge = () => {
if (radioModel && selectedData.value.length > 0) { return !(radioModel && selectedData.value.length > 0)
return false
}
return true
} }
// //
const addRecord = (record) => { const addRecord = (record) => {
@ -377,6 +374,12 @@
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.xn-mb10 {
margin-bottom: 10px;
}
.xn-fd {
float: right;
}
.selectorTreeDiv { .selectorTreeDiv {
max-height: 500px; max-height: 500px;
overflow: auto; overflow: auto;

View File

@ -1,6 +1,6 @@
<template> <template>
<a-modal <a-modal
v-model:visible="visible" v-model:open="visible"
title="职位选择" title="职位选择"
:width="1000" :width="1000"
:mask-closable="false" :mask-closable="false"
@ -22,7 +22,7 @@
</a-card> </a-card>
</a-col> </a-col>
<a-col :span="11"> <a-col :span="11">
<div class="table-operator" style="margin-bottom: 10px"> <div class="table-operator xn-mb10">
<a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState"> <a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="12"> <a-col :span="12">
@ -32,7 +32,7 @@
</a-col> </a-col>
<a-col :span="12"> <a-col :span="12">
<a-button type="primary" class="primarySele" @click="loadData()"> </a-button> <a-button type="primary" class="primarySele" @click="loadData()"> </a-button>
<a-button class="snowy-buttom-left" @click="() => reset()"> 重置 </a-button> <a-button class="snowy-button-left" @click="() => reset()"> 重置 </a-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
@ -50,13 +50,13 @@
> >
<template #title> <template #title>
<span>待选择列表 {{ tableRecordNum }} </span> <span>待选择列表 {{ tableRecordNum }} </span>
<div v-if="!radioModel" style="float: right"> <div v-if="!radioModel" class="xn-fdr">
<a-button type="dashed" size="small" @click="addAllPageRecord"></a-button> <a-button type="dashed" size="small" @click="addAllPageRecord"></a-button>
</div> </div>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'action'"> <template v-if="column.dataIndex === 'action'">
<a-button type="dashed" size="small" @click="addRecord(record)"></a-button> <a-button type="dashed" size="small" @click="addRecord(record)"><PlusOutlined /></a-button>
</template> </template>
<template v-if="column.dataIndex === 'category'"> <template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('POSITION_CATEGORY', record.category) }} {{ $TOOL.dictTypeData('POSITION_CATEGORY', record.category) }}
@ -89,13 +89,13 @@
> >
<template #title> <template #title>
<span>已选择: {{ selectedData.length }}</span> <span>已选择: {{ selectedData.length }}</span>
<div v-if="!radioModel" style="float: right"> <div v-if="!radioModel" class="xn-fdr">
<a-button type="dashed" danger size="small" @click="delAllRecord"></a-button> <a-button type="dashed" danger size="small" @click="delAllRecord"></a-button>
</div> </div>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'action'"> <template v-if="column.dataIndex === 'action'">
<a-button type="dashed" danger size="small" @click="delRecord(record)"></a-button> <a-button type="dashed" danger size="small" @click="delRecord(record)"><MinusOutlined /></a-button>
</template> </template>
</template> </template>
</a-table> </a-table>
@ -116,7 +116,7 @@
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
width: 80 width: 50
}, },
{ {
title: '职位名', title: '职位名',
@ -134,7 +134,7 @@
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
width: 80 width: 50
}, },
{ {
title: '职位名', title: '职位名',
@ -251,10 +251,7 @@
loadData() loadData()
} }
const judge = () => { const judge = () => {
if (radioModel && selectedData.value.length > 0) { return !(radioModel && selectedData.value.length > 0)
return false
}
return true
} }
// //
const addRecord = (record) => { const addRecord = (record) => {

View File

@ -1,6 +1,6 @@
<template> <template>
<a-modal <a-modal
v-model:visible="visible" v-model:open="visible"
title="角色选择" title="角色选择"
:width="1000" :width="1000"
:mask-closable="false" :mask-closable="false"
@ -22,7 +22,7 @@
</a-card> </a-card>
</a-col> </a-col>
<a-col :span="11"> <a-col :span="11">
<div class="table-operator" style="margin-bottom: 10px"> <div class="table-operator xn-mb10">
<a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState"> <a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="12"> <a-col :span="12">
@ -32,7 +32,7 @@
</a-col> </a-col>
<a-col :span="12"> <a-col :span="12">
<a-button type="primary" class="primarySele" @click="loadData()"> </a-button> <a-button type="primary" class="primarySele" @click="loadData()"> </a-button>
<a-button class="snowy-buttom-left" @click="() => reset()"> 重置 </a-button> <a-button class="snowy-button-left" @click="() => reset()"> 重置 </a-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
@ -50,13 +50,13 @@
> >
<template #title> <template #title>
<span>待选择列表 {{ tableRecordNum }} </span> <span>待选择列表 {{ tableRecordNum }} </span>
<div v-if="!radioModel" style="float: right"> <div v-if="!radioModel" class="xn-fdr">
<a-button type="dashed" size="small" @click="addAllPageRecord"></a-button> <a-button type="dashed" size="small" @click="addAllPageRecord"></a-button>
</div> </div>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'action'"> <template v-if="column.dataIndex === 'action'">
<a-button type="dashed" size="small" @click="addRecord(record)"></a-button> <a-button type="dashed" size="small" @click="addRecord(record)"><PlusOutlined /></a-button>
</template> </template>
<template v-if="column.dataIndex === 'category'"> <template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('ROLE_CATEGORY', record.category) }} {{ $TOOL.dictTypeData('ROLE_CATEGORY', record.category) }}
@ -89,13 +89,13 @@
> >
<template #title> <template #title>
<span>已选择: {{ selectedData.length }}</span> <span>已选择: {{ selectedData.length }}</span>
<div v-if="!radioModel" style="float: right"> <div v-if="!radioModel" class="xn-fdr">
<a-button type="dashed" danger size="small" @click="delAllRecord"></a-button> <a-button type="dashed" danger size="small" @click="delAllRecord"></a-button>
</div> </div>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'action'"> <template v-if="column.dataIndex === 'action'">
<a-button type="dashed" danger size="small" @click="delRecord(record)"></a-button> <a-button type="dashed" danger size="small" @click="delRecord(record)"><MinusOutlined /></a-button>
</template> </template>
</template> </template>
</a-table> </a-table>
@ -116,7 +116,7 @@
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
width: 80 width: 50
}, },
{ {
title: '角色名', title: '角色名',
@ -134,7 +134,7 @@
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
width: 80 width: 50
}, },
{ {
title: '角色名', title: '角色名',
@ -298,10 +298,7 @@
loadData() loadData()
} }
const judge = () => { const judge = () => {
if (radioModel && selectedData.value.length > 0) { return !(radioModel && selectedData.value.length > 0)
return false
}
return true
} }
// //
const addRecord = (record) => { const addRecord = (record) => {

View File

@ -1,6 +1,6 @@
<template> <template>
<a-modal <a-modal
v-model:visible="visible" v-model:open="visible"
title="用户选择" title="用户选择"
:width="1000" :width="1000"
:mask-closable="false" :mask-closable="false"
@ -22,7 +22,7 @@
</a-card> </a-card>
</a-col> </a-col>
<a-col :span="11"> <a-col :span="11">
<div class="table-operator" style="margin-bottom: 10px"> <div class="table-operator xn-mb10">
<a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState"> <a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="12"> <a-col :span="12">
@ -32,7 +32,7 @@
</a-col> </a-col>
<a-col :span="12"> <a-col :span="12">
<a-button type="primary" class="primarySele" @click="loadData()"> </a-button> <a-button type="primary" class="primarySele" @click="loadData()"> </a-button>
<a-button class="snowy-buttom-left" @click="reset()"> </a-button> <a-button class="snowy-button-left" @click="reset()"> </a-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
@ -50,13 +50,16 @@
> >
<template #title> <template #title>
<span>待选择列表 {{ tableRecordNum }} </span> <span>待选择列表 {{ tableRecordNum }} </span>
<div v-if="!radioModel" style="float: right"> <div v-if="!radioModel" class="xn-fdr">
<a-button type="dashed" size="small" @click="addAllPageRecord"></a-button> <a-button type="dashed" size="small" @click="addAllPageRecord"></a-button>
</div> </div>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'avatar'">
<a-avatar :src="record.avatar" style="margin-bottom: -5px; margin-top: -5px" />
</template>
<template v-if="column.dataIndex === 'action'"> <template v-if="column.dataIndex === 'action'">
<a-button type="dashed" size="small" @click="addRecord(record)"></a-button> <a-button type="dashed" size="small" @click="addRecord(record)"><PlusOutlined /></a-button>
</template> </template>
<template v-if="column.dataIndex === 'category'"> <template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('ROLE_CATEGORY', record.category) }} {{ $TOOL.dictTypeData('ROLE_CATEGORY', record.category) }}
@ -89,13 +92,13 @@
> >
<template #title> <template #title>
<span>已选择: {{ selectedData.length }}</span> <span>已选择: {{ selectedData.length }}</span>
<div v-if="!radioModel" style="float: right"> <div v-if="!radioModel" class="xn-fdr">
<a-button type="dashed" danger size="small" @click="delAllRecord"></a-button> <a-button type="dashed" danger size="small" @click="delAllRecord"></a-button>
</div> </div>
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'action'"> <template v-if="column.dataIndex === 'action'">
<a-button type="dashed" danger size="small" @click="delRecord(record)"></a-button> <a-button type="dashed" danger size="small" @click="delRecord(record)"><MinusOutlined /></a-button>
</template> </template>
</template> </template>
</a-table> </a-table>
@ -116,7 +119,12 @@
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
width: 80 width: 50
},
{
title: '头像',
dataIndex: 'avatar',
width: 50
}, },
{ {
title: '用户名', title: '用户名',
@ -134,7 +142,7 @@
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
width: 80 width: 50
}, },
{ {
title: '用户名', title: '用户名',
@ -252,10 +260,7 @@
loadData() loadData()
} }
const judge = () => { const judge = () => {
if (radioModel && selectedData.value.length > 0) { return !(radioModel && selectedData.value.length > 0)
return false
}
return true
} }
// //
const addRecord = (record) => { const addRecord = (record) => {

View File

@ -26,7 +26,7 @@
} }
}) })
// //
const colorList = ['#7265E6', '#FFBF00', '#00A2AE', '#F56A00', '#1890FF', '#606D80'] const colorList = ['#7265E6', '#FFBF00', '#00A2AE', '#F56A00', '#1677FF', '#606D80']
// //
const randomColor = () => { const randomColor = () => {
if (props.color) { if (props.color) {

View File

@ -112,7 +112,7 @@ export default {
<!-- #bodyCell 放入column表格列需要显示的数据可以通过判断进行一个自定义显示 --> <!-- #bodyCell 放入column表格列需要显示的数据可以通过判断进行一个自定义显示 -->
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template > <template >
<a-avatar style="width: 25px; height: 25px" /> <a-avatar class="xn-wh25" />
</template> </template>
<template v-if="column.dataIndex === 'status'"> <template v-if="column.dataIndex === 'status'">
<!-- 进行自定义显示内容 --> <!-- 进行自定义显示内容 -->
@ -199,7 +199,8 @@ const edit = (row) => {
| -------------- | ----------------------------------------------- | ----------------- | ------ | | -------------- | ----------------------------------------------- | ----------------- | ------ |
| alert | 设置是否显示表格信息栏 | [object, boolean] | null | | alert | 设置是否显示表格信息栏 | [object, boolean] | null |
| showPagination | 显示分页选择器,可传 'auto' \| boolean | [string, boolean] | 'auto' | | showPagination | 显示分页选择器,可传 'auto' \| boolean | [string, boolean] | 'auto' |
| data | 加载数据方法 必须为 `Promise` 对象 **必须绑定** | Promise | - | | data | 加载数据方法 必须为 `Promise` 对象 **必须绑定** | Promise | - |
| lineSelection | 是否开启点击行高亮显示并选中 | Boolean | 'false' |
`alert` 属性对象: `alert` 属性对象:
@ -245,6 +246,7 @@ result.then((r) => {
data.localLoading = false data.localLoading = false
return return
} }
// 获取分页数据及分页的显示内容
data.localPagination = data.localPagination =
(props.showPagination && (props.showPagination &&
Object.assign({}, data.localPagination, { Object.assign({}, data.localPagination, {
@ -270,31 +272,35 @@ result.then((r) => {
loadData() loadData()
return return
} }
// 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
try { try {
/* // 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
if ((['auto', true].includes(props.showPagination) && r.total <= (r.pages * data.localPagination.size))) { // 没有数据或只有一页数据时隐藏分页栏
data.localPagination.hideOnSinglePage = true // if ((['auto', true].includes(props.showPagination) && r.total <= (r.pages * data.localPagination.pageSize))) {
} // data.localPagination.hideOnSinglePage = true
*/ // }
if (!props.showPagination) { if (!props.showPagination) {
data.localPagination.hideOnSinglePage = true data.localPagination.hideOnSinglePage = true
} }
} catch (e) { } catch (e) {
data.localPagination = false data.localPagination = false
} }
// if (props.showPagination === false) {
// // 既然配置了不分页,那么我们这里接收到肯定是数组
// console.log(r);
// data.localDataSource = []
// if (r instanceof Array) {
// data.localDataSource = r
// }
// } else {
// data.localDataSource = r.records
// }
// 返回结果中的数组数据 // 返回结果中的数组数据
if (props.showPagination === false) { data.localDataSource = r.records
// 既然配置了不分页,那么我们这里接收到肯定是数组
data.localDataSource = []
if (r instanceof Array) {
data.localDataSource = r
}
} else {
data.localDataSource = r.records
}
data.localLoading = false data.localLoading = false
getTableProps() // 获取到后端返回的数据后需要调用一下获取table的props的方法去刷新table getTableProps()
}) })
``` ```
返回 JSON 例子: 返回 JSON 例子:

View File

@ -89,3 +89,36 @@
emit('columnChange', columnsSetting.value) emit('columnChange', columnsSetting.value)
} }
</script> </script>
<style lang="less" scoped>
.s-tool-column-item {
display: flex;
align-items: center;
padding: 4px 16px 4px 4px;
.ant-checkbox-wrapper {
flex: 1;
}
.s-tool-column-handle {
opacity: 0.8;
cursor: move;
.anticon-more {
font-size: 12px;
& + .anticon-more {
margin: 0px 4px 0 -8px;
}
}
}
}
.s-tool-column-header {
padding: 5px 16px 10px 24px;
min-width: 180px;
}
.s-tool-column {
.ant-divider {
margin: 0;
}
.ant-checkbox-group {
padding: 4px 0;
display: block;
}
}
</style>

View File

@ -1,57 +0,0 @@
.table-wrapper{
}
.table-striped td {
background-color: var(--table-row-hover-bg);
}
.s-table-tool{
display: flex;
margin-bottom: 16px;
.s-table-tool-left{
flex: 1;
}
.s-table-tool-right{
.s-tool-item{
font-size: 16px;
@apply ml-4;
cursor: pointer;
}
}
}
.s-tool-column-item{
display: flex;
align-items: center;
padding: 4px 16px 4px 4px;
.ant-checkbox-wrapper{
flex: 1;
}
.s-tool-column-handle{
opacity: .8;
cursor: move;
.anticon-more{
font-size: 12px;
& + .anticon-more{
margin: 0px 4px 0 -8px;
}
}
}
}
.s-tool-column-header{
padding: 5px 16px 10px 24px;
min-width: 180px;
}
.s-tool-column{
.ant-divider{
margin: 0;
}
.ant-checkbox-group{
padding: 4px 0;
display: block;
}
}
.s-table-column-settings .ant-popover-inner-content{
padding: 0;
}

View File

@ -10,7 +10,7 @@
<div className="layout-items-center ml-4" v-show="props.toolConfig.striped"> <div className="layout-items-center ml-4" v-show="props.toolConfig.striped">
<a-checkbox :checked="data.localSettings.rowClassNameSwitch" @change="changeRowClass"> </a-checkbox> <a-checkbox :checked="data.localSettings.rowClassNameSwitch" @change="changeRowClass"> </a-checkbox>
</div> </div>
<span v-for="item in tool"> <span v-for="item in tool" :key="item.name">
<!-- 刷新 --> <!-- 刷新 -->
<a-tooltip <a-tooltip
v-if="item.name === 'refresh' && props.toolConfig.refresh" v-if="item.name === 'refresh' && props.toolConfig.refresh"
@ -37,7 +37,7 @@
</a-tooltip> </a-tooltip>
</a-popover> </a-popover>
<!-- 密度 --> <!-- 密度 -->
<a-dropdown trigger="click" v-if="item.isDropdown && item.name == 'height' && props.toolConfig.height"> <a-dropdown trigger="click" v-if="item.isDropdown && item.name === 'height' && props.toolConfig.height">
<template #overlay> <template #overlay>
<a-menu selectable :selectedKeys="[data.customSize]" @click="changeHeight"> <a-menu selectable :selectedKeys="[data.customSize]" @click="changeHeight">
<a-menu-item key="default">默认</a-menu-item> <a-menu-item key="default">默认</a-menu-item>
@ -93,29 +93,35 @@
<!-- 表格 --> <!-- 表格 -->
<a-table <a-table
v-bind="{ ...renderTableProps, ...data.localSettings }" v-bind="{ ...renderTableProps }"
@change="loadData"
:loading="data.localLoading" :loading="data.localLoading"
:row-key="(record) => record.id" @change="loadData"
@expand=" @expand="
(expanded, record) => { (expanded, record) => {
emit('expand', expanded, record) emit('expand', expanded, record)
} }
" "
:rowClassName="
(record, index) => (data.localSettings.rowClassNameSwitch ? ((index + 1) % 2 == 0 ? 'odd' : '') : null)
"
> >
<template #[item]="scope" v-for="item in renderSlots"> <template #[item]="scope" v-for="item in renderSlots">
<slot v-if="item && renderTableProps.columns.length > 0" :name="item" :scope="scope" v-bind="scope || {}"></slot> <slot
v-if="item && renderTableProps.columns && renderTableProps.columns.length > 0"
:name="item"
:scope="scope"
v-bind="scope || {}"
/>
</template> </template>
</a-table> </a-table>
</div> </div>
</template> </template>
<script setup> <script setup>
import './index.less'
import { tableProps } from 'ant-design-vue/es/table/Table.js' import { tableProps } from 'ant-design-vue/es/table/Table.js'
import columnSetting from './columnSetting.vue' import columnSetting from './columnSetting.vue'
import { get } from 'lodash-es'
import { useSlots } from 'vue' import { useSlots } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { get } from 'lodash-es'
const slots = useSlots() const slots = useSlots()
const route = useRoute() const route = useRoute()
const emit = defineEmits(['expand']) const emit = defineEmits(['expand'])
@ -191,10 +197,8 @@
} }
}) })
) )
const data = reactive({ const data = reactive({
needTotalList: [], needTotalList: [],
localLoading: false,
localDataSource: [], localDataSource: [],
localPagination: Object.assign({}, props.pagination), localPagination: Object.assign({}, props.pagination),
isFullscreen: false, isFullscreen: false,
@ -275,11 +279,9 @@
getTableProps() getTableProps()
} }
// //
const changeRowClass = (value) => { const changeRowClass = (v) => {
const val = value.target.checked data.localSettings.rowClassNameSwitch = v.target.checked
data.localSettings.rowClassNameSwitch = val getTableProps()
const evenClass = val ? (_record, index) => (index % 2 === 1 ? 'table-striped' : null) : props.rowClassName
data.localSettings.rowClassName = evenClass
} }
// //
const changeHeight = (v) => { const changeHeight = (v) => {
@ -287,13 +289,12 @@
getTableProps() getTableProps()
} }
// //
const columnChange = (val) => { const columnChange = (v) => {
data.columnsSetting = val data.columnsSetting = v
getTableProps() getTableProps()
} }
// //
const rowClear = (callback) => { const rowClear = (callback) => {
callback
clearSelected() clearSelected()
} }
// //
@ -317,6 +318,7 @@
data.columnsSetting = props.columns data.columnsSetting = props.columns
loadData() loadData()
} }
const initTotalList = (columns) => { const initTotalList = (columns) => {
const totalList = [] const totalList = []
columns && columns &&
@ -331,9 +333,12 @@
}) })
return totalList return totalList
} }
// //
const loadData = (pagination, filters, sorter) => { const loadData = (pagination, filters, sorter) => {
// loading
data.localLoading = true data.localLoading = true
//
const parameter = Object.assign( const parameter = Object.assign(
{ {
current: current:
@ -359,6 +364,7 @@
...filters ...filters
} }
) )
//
const result = props.data(parameter) const result = props.data(parameter)
if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') { if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') {
result.then((r) => { result.then((r) => {
@ -366,6 +372,7 @@
data.localLoading = false data.localLoading = false
return return
} }
//
data.localPagination = data.localPagination =
(props.showPagination && (props.showPagination &&
Object.assign({}, data.localPagination, { Object.assign({}, data.localPagination, {
@ -379,38 +386,32 @@
pageSize: (pagination && pagination.pageSize) || data.localPagination.pageSize pageSize: (pagination && pagination.pageSize) || data.localPagination.pageSize
})) || })) ||
false false
// recordsnull // recordsnull
if (r.records == null) { if (r.records == null) {
r.records = [] r.records = []
} }
// 0 , // 0 ,
if (r.records.length === 0 && props.showPagination && data.localPagination.current > 1) { if (r.records.length === 0 && props.showPagination && data.localPagination.current > 1) {
data.localPagination.current-- data.localPagination.current--
loadData() loadData()
return return
} }
// table
try { try {
/* // table
if ((['auto', true].includes(props.showPagination) && r.total <= (r.pages * data.localPagination.size))) { //
data.localPagination.hideOnSinglePage = true // if ((['auto', true].includes(props.showPagination) && r.total <= (r.pages * data.localPagination.pageSize))) {
} // data.localPagination.hideOnSinglePage = true
*/ // }
if (!props.showPagination) { if (!props.showPagination) {
data.localPagination.hideOnSinglePage = true data.localPagination.hideOnSinglePage = true
} }
} catch (e) { } catch (e) {
data.localPagination = false data.localPagination = false
} }
// //
if (props.showPagination === false) { if (props.showPagination === false) {
// data.localDataSource = r instanceof Array ? r : r.records
data.localDataSource = []
if (r instanceof Array) {
data.localDataSource = r
}
} else { } else {
data.localDataSource = r.records data.localDataSource = r.records
} }
@ -419,33 +420,37 @@
}) })
} }
} }
// props
// tableprops
const getTableProps = () => { const getTableProps = () => {
let renderProps = {} let renderProps = {}
const localKeys = Object.keys(data) const localKeys = Object.keys(data)
Object.keys(tableProps()).forEach((k) => { // antdAPI
Object.keys(Object.assign(tableProps(), props)).forEach((k) => {
// localdataAPI
const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}` const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}`
// table props
if (localKeys.includes(localKey)) { if (localKeys.includes(localKey)) {
renderProps[k] = data[localKey] renderProps[k] = data[localKey]
return renderProps[k] return
} }
// alert rowSelection
// rowSelection
if (k === 'rowSelection') { if (k === 'rowSelection') {
if (props.rowSelection) { renderProps[k] = props.rowSelection
// 使alert rowSelection ? {
renderProps[k] = { ...props.rowSelection,
...props.rowSelection, onChange: (selectedRowKeys, selectedRows) => {
onChange: (selectedRowKeys, selectedRows) => { updateSelect(selectedRowKeys, selectedRows)
updateSelect(selectedRowKeys, selectedRows) typeof props[k].onChange !== 'undefined' && props[k].onChange(selectedRowKeys, selectedRows)
typeof props[k].onChange !== 'undefined' && props[k].onChange(selectedRowKeys, selectedRows) }
} }
} : null
return renderProps[k] return
} else if (!props.rowSelection) {
// rowSelection
renderProps[k] = null
return renderProps[k]
}
} }
// ,
if (k === 'customRow') { if (k === 'customRow') {
if (props.lineSelection && props.rowSelection) { if (props.lineSelection && props.rowSelection) {
// customRow // customRow
@ -488,19 +493,18 @@
return renderProps[k] return renderProps[k]
} }
} }
data[k] && (renderProps[k] = data[k]) renderProps[k] = props[k]
//
renderProps = {
...renderProps,
scroll: props.scroll,
bordered: props.bordered,
size: data.customSize, // sizea-tablecompSize
columns: data.columnsSetting.filter((value) => value.checked === undefined || value.checked)
}
return renderProps[k]
}) })
renderTableProps.value = renderProps renderProps = {
...renderProps,
size: data.customSize, // sizea-tablecompSize
columns: data.columnsSetting.filter((value) => value.checked === undefined || value.checked),
...data.localSettings
}
// undefined null tableprops
renderTableProps.value = Object.entries(renderProps).reduce((x, [y, z]) => (z == null ? x : ((x[y] = z), x)), {})
} }
// total // total
const updateSelect = (selectedRowKeys, selectedRows) => { const updateSelect = (selectedRowKeys, selectedRows) => {
if (props.rowSelection) { if (props.rowSelection) {
@ -544,3 +548,19 @@
init() init()
}) })
</script> </script>
<style lang="less" scoped>
.s-table-tool {
display: flex;
margin-bottom: 16px;
.s-table-tool-left {
flex: 1;
}
.s-table-tool-right {
.s-tool-item {
font-size: 16px;
@apply ml-4;
cursor: pointer;
}
}
}
</style>

View File

@ -2,7 +2,7 @@
<a-tree-select <a-tree-select
v-model:value="defaultSelectKeys" v-model:value="defaultSelectKeys"
show-search show-search
style="width: 100%" class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择菜单" placeholder="请选择菜单"
:field-names="treeFieldNames" :field-names="treeFieldNames"

View File

@ -32,5 +32,33 @@
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import './index.less'; .up,
.down {
margin-left: 4px;
position: relative;
top: 1px;
i {
font-size: 12px;
transform: scale(0.83);
}
}
.item-text {
display: inline-block;
margin-left: 8px;
color: rgba(0, 0, 0, 0.85);
}
.up {
color: @red-6;
}
.down {
color: @green-6;
top: -1px;
}
&.reverse-color .up {
color: @green-6;
}
&.reverse-color .down {
color: @red-6;
}
</style> </style>

View File

@ -1,10 +1,5 @@
<template> <template>
<a-popconfirm <a-popconfirm title="批量处理此信息?" :open="batchVisible" @openChange="batchVisibleChange" @confirm="deleteBatch">
title="批量处理此信息?"
:visible="batchVisible"
@visibleChange="batchVisibleChange"
@confirm="deleteBatch"
>
<a-button :type="props.buttonType" :danger="props.buttonDanger" :size="props.size" :loading="buttonLoading"> <a-button :type="props.buttonType" :danger="props.buttonDanger" :size="props.size" :loading="buttonLoading">
<template #icon v-if="props.icon"> <template #icon v-if="props.icon">
<component :is="props.icon" :style="{ color: props.color }" /> <component :is="props.icon" :style="{ color: props.color }" />
@ -30,11 +25,11 @@
}, },
buttonType: { buttonType: {
type: String, type: String,
default: () => '' default: () => undefined
}, },
icon: { icon: {
type: String, type: String,
default: () => '' default: () => undefined
}, },
size: { size: {
type: String, type: String,
@ -74,7 +69,7 @@
emit('batchCallBack', params) emit('batchCallBack', params)
} }
// loading // loading
const loading = () => { const openLoading = () => {
buttonLoading.value = true buttonLoading.value = true
} }
// loading // loading

View File

@ -1,8 +1,8 @@
<template> <template>
<a-popconfirm <a-popconfirm
title="删除此信息?" title="删除此信息?"
:visible="deleteVisible" :open="deleteVisible"
@visibleChange="deleteVisibleChange" @openChange="deleteVisibleChange"
@confirm="deleteBatch" @confirm="deleteBatch"
> >
<a-button danger> <a-button danger>

View File

@ -1,47 +1,49 @@
<template> <template>
<a-space class="go-back-button"> <a-space class="go-back-button">
<a-button type="primary" :href="props.src" target="_blank"> <a-button :href="props.src" size="small" target="_blank">
<template #icon><download-outlined /></template> <template #icon><download-outlined /></template>
</a-button> </a-button>
<a-button type="primary" @click="emit('goBack')"> <a-button type="primary" size="small" @click="emit('goBack')">
<template #icon><rollback-outlined /></template> <template #icon><rollback-outlined /></template>
返回 返回
</a-button> </a-button>
</a-space> </a-space>
<a-card :bordered="false" :body-style="{ padding: '0px' }"> <a-card :bordered="false" :body-style="{ padding: '0px' }">
<vue-office-docx <a-spin :spinning="loading">
v-if="props.fileType.toLowerCase() === 'doc' || props.fileType.toLowerCase() === 'docx'" <vue-office-docx
:src="props.src" v-if="fileType === 'doc' || fileType === 'docx'"
style="height: 82vh" :src="props.src"
@rendered="renderedHandler" class="xn-ht82"
/> @rendered="renderedHandler"
<vue-office-excel />
v-else-if="props.fileType.toLowerCase() === 'xls' || props.fileType.toLowerCase() === 'xlsx'" <vue-office-excel
:src="props.src" v-else-if="fileType === 'xls' || fileType === 'xlsx'"
style="height: 82vh" :src="props.src"
@rendered="renderedHandler" class="xn-ht82"
@error="errorHandler" @rendered="renderedHandler"
/> @error="errorHandler"
<vue-office-pdf />
v-else-if="props.fileType.toLowerCase() === 'pdf'" <vue-office-pdf
:src="props.src" v-else-if="fileType === 'pdf'"
@rendered="renderedHandler" :src="props.src"
@error="errorHandler" @rendered="renderedHandler"
/> @error="errorHandler"
<img />
v-else-if=" <img
props.fileType.toLowerCase() === 'png' || v-else-if="
props.fileType.toLowerCase() === 'jpg' || fileType === 'png' ||
props.fileType.toLowerCase() === 'gif' || fileType === 'jpg' ||
props.fileType.toLowerCase() === 'bmp' || fileType === 'gif' ||
props.fileType.toLowerCase() === 'jpeg' || fileType === 'bmp' ||
props.fileType.toLowerCase() === 'ico' || fileType === 'jpeg' ||
props.fileType.toLowerCase() === 'svg' fileType === 'ico' ||
" fileType === 'svg'
:src="props.src" "
style="max-width: 100%" :src="props.src"
/> class="xn-mwh"
<a-result v-else status="warning" title="不支持预览的文件类型" /> />
<a-result v-else status="warning" title="不支持预览的文件类型" />
</a-spin>
</a-card> </a-card>
</template> </template>
@ -58,6 +60,7 @@
//VueOfficePdf //VueOfficePdf
import VueOfficePdf from '@vue-office/pdf' import VueOfficePdf from '@vue-office/pdf'
const loading = ref(false)
const emit = defineEmits({ goBack: null }) const emit = defineEmits({ goBack: null })
const props = defineProps({ const props = defineProps({
src: { src: {
@ -72,8 +75,31 @@
required: false required: false
} }
}) })
const fileType = ref()
watch(
() => props.src,
() => {
fileType.value = props.fileType.toLowerCase()
}
)
watch(
() => props.src,
() => {
if (
fileType.value === 'doc' ||
fileType.value === 'docx' ||
fileType.value === 'xls' ||
fileType.value === 'xlsx' ||
fileType.value === 'pdf'
) {
loading.value = true
}
}
)
// //
const renderedHandler = () => {} const renderedHandler = () => {
loading.value = false
}
// //
const errorHandler = () => { const errorHandler = () => {
message.warning('渲染失败,请尝试重新打开!') message.warning('渲染失败,请尝试重新打开!')
@ -81,6 +107,12 @@
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.xn-mwh {
max-width: 100%;
}
.xn-ht82 {
height: 82vh;
}
.go-back-button { .go-back-button {
position: absolute; position: absolute;
float: right; float: right;

View File

@ -1,10 +1,10 @@
<template> <template>
<a-modal v-if="isModal" :visible="visible" @cancel="cancel" v-bind="$attrs"> <a-modal v-if="isModal" :open="visible" @cancel="cancel" v-bind="$attrs">
<template v-for="slotKey in slotKeys" #[slotKey]> <template v-for="slotKey in slotKeys" #[slotKey]>
<slot :name="slotKey" /> <slot :name="slotKey" />
</template> </template>
</a-modal> </a-modal>
<a-drawer v-else :visible="visible" v-bind="$attrs" @close="cancel" :footer-style="{ textAlign: 'right' }"> <a-drawer v-else :open="visible" v-bind="$attrs" @close="cancel" :footer-style="{ textAlign: 'right' }">
<template v-for="slotKey in slotKeys" #[slotKey]> <template v-for="slotKey in slotKeys" #[slotKey]>
<slot :name="slotKey" /> <slot :name="slotKey" />
</template> </template>
@ -13,23 +13,20 @@
<script setup> <script setup>
import { useSlots } from 'vue' import { useSlots } from 'vue'
const slots = useSlots()
import { globalStore } from '@/store' import { globalStore } from '@/store'
const slots = useSlots()
const store = globalStore() const store = globalStore()
const props = defineProps({ const props = defineProps({
visible: { visible: {
type: Boolean, type: Boolean,
default: false, default: false,
required: true required: false
} }
}) })
const FormContainerTypeEnum = { const FormContainerTypeEnum = {
DRAWER: 'drawer', DRAWER: 'drawer',
MODAL: 'modal' MODAL: 'modal'
} }
const formStyle = computed(() => { const formStyle = computed(() => {
return store.formStyle return store.formStyle
}) })
@ -44,7 +41,6 @@
emit('close') emit('close')
} }
</script> </script>
<script> <script>
// //
export default { export default {

View File

@ -1,15 +1,16 @@
<template> <template>
<!-- 本组件这兄弟写的很好 请参照https://blog.csdn.net/weixin_41897680/article/details/124925222--> <!-- 本组件这兄弟写的很好 请参照https://blog.csdn.net/weixin_41897680/article/details/124925222-->
<div class="hljs-container" :codetype="props.language"> <div class="hljs-container" :codetype="props.language">
<a-button v-if="props.copy" size="small" type="primary" class="hljs-copy" @click="codeCopy">
<CopyOutlined />
拷贝
</a-button>
<highlightjs :language="props.language" :autodetect="!props.language" :code="props.code" /> <highlightjs :language="props.language" :autodetect="!props.language" :code="props.code" />
</div> </div>
</template> </template>
<script setup name="XnHighlightjs"> <script setup name="XnHighlightjs">
/*import 'highlight.js/styles/atom-one-dark.css' import { message } from 'ant-design-vue'
import 'highlight.js/lib/common'
import hljsVuePlugin from '@highlightjs/vue-plugin'*/
const props = defineProps({ const props = defineProps({
language: { language: {
type: String, type: String,
@ -18,41 +19,27 @@
code: { code: {
type: String, type: String,
default: () => '无' default: () => '无'
},
copy: {
type: Boolean,
default: () => false
} }
}) })
const codeCopy = () => {
copyTextToClipboard(props.code).then(() => {
message.success('拷贝成功')
})
}
const copyTextToClipboard = async (text) => {
try {
await navigator.clipboard.writeText(text)
} catch (err) {
message.warning('拷贝失败')
}
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
/* 语法高亮 */
/*.hljs-container {
position: relative;
display: block;
padding: 30px 5px 2px;
overflow-x: hidden;
line-height: 20px;
text-align: left;
background: #21252b;
box-shadow: 0 10px 30px 0 rgb(0 0 0 / 40%);
}*/
/** 3个点 */
/*.hljs-container::before {
position: absolute;
top: 10px;
left: 15px;
width: 12px;
height: 12px;
overflow: visible;
font-weight: 700;
font-size: 16px;
line-height: 12px;
white-space: nowrap;
text-indent: 75px;
background-color: #fc625d;
border-radius: 16px;
box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
content: attr(codetype);
}*/
/** 滚动条 */ /** 滚动条 */
:deep(.hljs, .hljs-container) { :deep(.hljs, .hljs-container) {
max-height: 300px !important; max-height: 300px !important;
@ -88,4 +75,12 @@
::-webkit-scrollbar-button { ::-webkit-scrollbar-button {
display: none; display: none;
} }
/** 复制样式 */
.hljs-copy {
float: right;
top: 10px;
right: 10px;
position: absolute;
z-index: 9;
}
</style> </style>

View File

@ -4,7 +4,7 @@
v-model:value="modelValue" v-model:value="modelValue"
:options="options" :options="options"
:field-names="{ label: 'name', value: 'id' }" :field-names="{ label: 'name', value: 'id' }"
style="width: 100%" class="xn-wd"
:placeholder="props.placeholder" :placeholder="props.placeholder"
:allow-clear="props.allowClear" :allow-clear="props.allowClear"
:disabled="props.disabled" :disabled="props.disabled"

View File

@ -1,17 +1,10 @@
<template> <template>
<xn-form-container <xn-form-container :visible="visible" :width="700" title="电子签名" @close="handleClear" @ok="handleOk">
ref="signModel"
v-model:visible="visible"
:width="700"
title="电子签名"
@close="handleClear"
@ok="handleOk"
>
<a-row :gutter="5"> <a-row :gutter="5">
<a-col :span="15"> <a-col :span="15">
<div style="border: 1px solid rgb(236 236 236)"> <div class="xn-bdr236">
<vue-esign <vue-esign
ref="esign" ref="esignRef"
v-model:bgColor="bgColor" v-model:bgColor="bgColor"
:width="800" :width="800"
:height="400" :height="400"
@ -23,12 +16,12 @@
</div> </div>
</a-col> </a-col>
<a-col :span="9"> <a-col :span="9">
<div style="height: 90px; width: auto"> <div class="xn-h90wat">
<img :src="resultImg" style="height: 90px; width: 100%; border: 1px solid rgb(236 236 236)" /> <img :src="resultImg" class="xn-bdr236 xn-h90w100" />
</div> </div>
</a-col> </a-col>
</a-row> </a-row>
<div style="margin-top: 10px"> <div class="xn-mt10">
<a-space> <a-space>
<a-form> <a-form>
<a-row :gutter="16"> <a-row :gutter="16">
@ -39,7 +32,7 @@
</a-col> </a-col>
<a-col :span="12"> <a-col :span="12">
<a-form-item> <a-form-item>
<div style="padding-right: 50px">是否裁剪<a-checkbox v-model:checked="isCrop"></a-checkbox></div> <div class="xn-pr50">是否裁剪<a-checkbox v-model:checked="isCrop"></a-checkbox></div>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@ -49,7 +42,7 @@
</a-space> </a-space>
</div> </div>
<template #footer> <template #footer>
<a-button style="margin-right: 8px" @click="handleClear"></a-button> <a-button class="xn-mr8" @click="handleClear"></a-button>
<a-button type="primary" @click="handleOk"></a-button> <a-button type="primary" @click="handleOk"></a-button>
</template> </template>
</xn-form-container> </xn-form-container>
@ -57,13 +50,12 @@
<script setup> <script setup>
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import vueEsign from './vueEsign.vue' import VueEsign from './vueEsign.vue'
const signModel = ref(false)
const visible = ref(false) const visible = ref(false)
const esign = ref(false) const esignRef = ref(false)
const resultImg = ref('') const resultImg = ref('')
const isCrop = ref(false) const isCrop = ref(false)
const lineWidth = ref(6) const lineWidth = ref(10)
const lineColor = ref('#000000') const lineColor = ref('#000000')
const bgColor = ref('') const bgColor = ref('')
const props = defineProps(['image']) const props = defineProps(['image'])
@ -74,11 +66,11 @@
visible.value = true visible.value = true
} }
const handleReset = () => { const handleReset = () => {
esign.value.reset() esignRef.value.reset()
resultImg.value = '' resultImg.value = ''
} }
const handleGenerate = () => { const handleGenerate = () => {
esign.value esignRef.value
.generate() .generate()
.then((res) => { .then((res) => {
resultImg.value = res resultImg.value = res
@ -91,7 +83,7 @@
visible.value = false visible.value = false
} }
const handleOk = () => { const handleOk = () => {
esign.value esignRef.value
.generate() .generate()
.then((res) => { .then((res) => {
emit('successful', res) emit('successful', res)
@ -107,7 +99,24 @@
</script> </script>
<style scoped> <style scoped>
.xn-h90w100 {
height: 90px;
width: 100%;
}
.xn-mt10 {
margin-top: 10px;
}
.xn-h90wat {
height: 90px;
width: auto;
}
.xn-bdr236 {
border: 1px solid rgb(236 236 236);
}
.ant-form-item { .ant-form-item {
margin-bottom: 0px !important; margin-bottom: 0px !important;
} }
.xn-pr50 {
padding-right: 50px;
}
</style> </style>

View File

@ -87,7 +87,9 @@
canvas.value.height = props.height canvas.value.height = props.height
canvas.value.width = props.width canvas.value.width = props.width
canvas.value.style.background = myBg.value canvas.value.style.background = myBg.value
$_resizeHandler() setTimeout(() => {
$_resizeHandler()
})
// //
document.onmouseup = () => { document.onmouseup = () => {
isDrawing.value = false isDrawing.value = false

View File

@ -0,0 +1,36 @@
## 小诺人员选择器
### 说明
改组件为小诺人员选择器可返回id用逗号隔离的字符串或id数组类型的数据格式
@author yubaoshan
@data 2024年4月13日23:59:23
### props定义
| 序号 | 编码 | 类型 | 说明 | 默认 |
|-----|---------------------|---------------|------------------------------|--------|
| 1 | radioModel | Boolean | 是否单选与addShow隐藏同时可用 | false |
| 2 | dataIsConverterFlw | Boolean | 是否为工作流格式 | false |
| 3 | orgTreeApi | function | 机构树接口 | - |
| 4 | userPageApi | function | 用户分页接口 | - |
| 5 | userListByIdListApi | function | 通过id数组查询list数据接口 | - |
| 6 | value | object或string | 通过v-model:value绑定数据 | - |
| 7 | dataType | string | 数据类型object或string | string |
| 8 | userShow | Boolean | 是否显示已选择用户(非表单内、单纯的选择用户需要隐藏) | true |
| 9 | addShow | Boolean | 是否默认的增加人员按钮与radioModel为或的关系 | true |
### emits定义
| 序号 | 方法名 | 参数类型 | 说明 |
|----|--------|----------------|---------------------------------|
| 1 | value | 根据 dataType 而定 | 当选择用户后通过v-model:value绑定到组件上 |
| 2 | onBack | 根据 dataType 而定 | 通过@onBack 方法返回选中的数据,触发点为选中或删除用户 |
### slot定义
| 序号 | 插槽名 | 用途 | 用途 |
|----|--------|-------------------|-------------------|
| 1 | button | 在人员新增按钮后可以插入自定义按钮 | 不满足新增人员按钮样式,可以自定义 |

View File

@ -0,0 +1,622 @@
<template>
<!-- 这是引入后展示的样式 -->
<div style="display: flex" v-if="props.userShow">
<div
class="user-container"
v-for="(user, index) in userObj"
:key="user.id"
@mouseover="onMouseEnter(index)"
@mouseleave="onMouseLeave(index)"
>
<span class="user-delete">
<CloseCircleFilled
:class="index === deleteShow ? 'show-delete-icon' : ''"
class="delete-icon"
@click="deleteUser(user)"
/>
<a-avatar :src="user.avatar" />
</span>
<span class="user-name">{{ user.name }}</span>
</div>
<a-button shape="circle" @click="openModal" v-if="(props.radioModel ? userObj.length !== 1 : true) && addShow">
<PlusOutlined />
</a-button>
<slot name="button"></slot>
</div>
<!-- 以下是弹窗内容 -->
<a-modal
v-model:open="visible"
title="用户选择"
:width="1000"
:mask-closable="false"
:destroy-on-close="true"
@ok="handleOk"
@cancel="handleClose"
>
<a-row :gutter="10">
<a-col :span="7">
<a-card size="small" :loading="cardLoading" class="selectorTreeDiv">
<a-tree
v-if="treeData"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
>
</a-tree>
</a-card>
</a-col>
<a-col :span="11">
<div class="table-operator xn-mb10">
<a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item name="searchKey">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入用户名" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-button type="primary" class="xn-mr-10" @click="loadData()"> </a-button>
<a-button @click="reset()"> </a-button>
</a-col>
</a-row>
</a-form>
</div>
<div class="user-table">
<a-table
ref="tableRef"
size="small"
:columns="commons"
:data-source="tableData"
:expand-row-by-click="true"
:loading="pageLoading"
bordered
:pagination="false"
>
<template #title>
<span>待选择列表 {{ tableRecordNum }} </span>
<div v-if="!radioModel" class="xn-fdr">
<a-button type="dashed" size="small" @click="addAllPageRecord"></a-button>
</div>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'avatar'">
<a-avatar :src="record.avatar" style="margin-bottom: -5px; margin-top: -5px" />
</template>
<template v-if="column.dataIndex === 'action'">
<a-button type="dashed" size="small" @click="addRecord(record)"><PlusOutlined /></a-button>
</template>
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('ROLE_CATEGORY', record.category) }}
</template>
</template>
</a-table>
<div class="mt-2">
<a-pagination
v-if="!isEmpty(tableData)"
v-model:current="current"
v-model:page-size="pageSize"
:total="total"
size="small"
showSizeChanger
@change="paginationChange"
/>
</div>
</div>
</a-col>
<a-col :span="6">
<div class="user-table">
<a-table
ref="selectedTable"
size="small"
:columns="selectedCommons"
:data-source="selectedData"
:expand-row-by-click="true"
:loading="selectedTableListLoading"
bordered
>
<template #title>
<span>已选择: {{ selectedData.length }}</span>
<div v-if="!radioModel" class="xn-fdr">
<a-button type="dashed" danger size="small" @click="delAllRecord"></a-button>
</div>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'action'">
<a-button type="dashed" danger size="small" @click="delRecord(record)"><MinusOutlined /></a-button>
</template>
</template>
</a-table>
</div>
</a-col>
</a-row>
</a-modal>
</template>
<script setup name="userSelector">
import { message } from 'ant-design-vue'
import { remove, isEmpty, cloneDeep } from 'lodash-es'
//
const visible = ref(false)
const deleteShow = ref('')
// common
const commons = [
{
title: '操作',
dataIndex: 'action',
align: 'center',
width: 50
},
{
title: '头像',
dataIndex: 'avatar',
width: 50
},
{
title: '用户名',
dataIndex: 'name',
ellipsis: true
},
{
title: '账号',
dataIndex: 'account'
}
]
// common
const selectedCommons = [
{
title: '操作',
dataIndex: 'action',
align: 'center',
width: 50
},
{
title: '用户名',
dataIndex: 'name',
ellipsis: true
}
]
const props = defineProps({
radioModel: {
type: Boolean,
default: () => false
},
dataIsConverterFlw: {
type: Boolean,
default: () => false
},
orgTreeApi: {
type: Function,
default: () => undefined
},
userPageApi: {
type: Function,
default: () => undefined
},
userListByIdListApi: {
type: Function,
default: () => undefined
},
value: {
default: () => ''
},
dataType: {
type: String,
default: () => 'string'
},
userShow: {
type: Boolean,
default: () => true
},
addShow: {
type: Boolean,
default: () => true
}
})
// ref
const tableRef = ref()
// ref
const selectedTable = ref()
const tableRecordNum = ref()
const searchFormState = ref({})
const searchFormRef = ref()
const cardLoading = ref(true)
const pageLoading = ref(false)
const selectedTableListLoading = ref(false)
// treeNode title,key,children
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
//
const treeData = ref()
// id
const defaultExpandedKeys = ref([])
const emit = defineEmits(['update:value', 'onBack'])
const tableData = ref([])
const selectedData = ref([])
const recordIds = ref([])
//
const current = ref(0) //
const pageSize = ref(20) //
const total = ref(0) //
//
const showUserPlusModal = (ids = []) => {
const data = goDataConverter(ids)
recordIds.value = data
getUserAvatarById(data)
openModal()
}
const onMouseEnter = (index) => {
deleteShow.value = index
}
const onMouseLeave = (index) => {
deleteShow.value = ''
}
const openModal = () => {
if (typeof props.orgTreeApi !== 'function') {
message.warning('未配置选择器需要的orgTreeApi接口')
return
}
if (typeof props.userPageApi !== 'function') {
message.warning('未配置选择器需要的userPageApi接口')
return
}
if (typeof props.userListByIdListApi !== 'function') {
message.warning('未配置选择器需要的userListByIdListApi接口')
return
}
visible.value = true
//
props
.orgTreeApi()
.then((data) => {
if (data !== null) {
treeData.value = data
// 2
treeData.value.forEach((item) => {
// 0
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
}
})
}
})
.finally(() => {
cardLoading.value = false
})
searchFormState.value.size = pageSize.value
loadData()
if (props.userListByIdListApi) {
if (isEmpty(recordIds.value)) {
return
}
const param = {
idList: recordIds.value
}
selectedTableListLoading.value = true
props
.userListByIdListApi(param)
.then((data) => {
selectedData.value = data
})
.finally(() => {
selectedTableListLoading.value = false
})
}
}
//
const deleteUser = (user) => {
//
remove(userObj.value, (item) => item.id === user.id)
//
remove(recordIds.value, (item) => item === user.id)
const value = []
const showUser = []
userObj.value.forEach((item) => {
const obj = {
id: item.id,
name: item.name
}
value.push(item.id)
// obj
const objClone = cloneDeep(obj)
objClone.avatar = item.avatar
showUser.push(objClone)
})
userObj.value = showUser
//
const resultData = outDataConverter(value)
emit('update:value', resultData)
emit('onBack', resultData)
}
//
const loadData = () => {
pageLoading.value = true
props
.userPageApi(searchFormState.value)
.then((data) => {
current.value = data.current
// pageSize.value = data.size
total.value = data.total
//
tableData.value = []
tableRecordNum.value = 0
tableData.value = data.records
if (data.records) {
tableRecordNum.value = data.records.length
} else {
tableRecordNum.value = 0
}
})
.finally(() => {
pageLoading.value = false
})
}
// pageSize
const paginationChange = (page, pageSize) => {
searchFormState.value.current = page
searchFormState.value.size = pageSize
loadData()
}
const judge = () => {
return !(props.radioModel && selectedData.value.length > 0)
}
//
const addRecord = (record) => {
if (!judge()) {
message.warning('只可选择一条')
return
}
const selectedRecord = selectedData.value.filter((item) => item.id === record.id)
if (selectedRecord.length === 0) {
selectedData.value.push(record)
} else {
message.warning('该记录已存在')
}
}
//
const addAllPageRecord = () => {
let newArray = selectedData.value.concat(tableData.value)
let list = []
for (let item1 of newArray) {
let flag = true
for (let item2 of list) {
if (item1.id === item2.id) {
flag = false
}
}
if (flag) {
list.push(item1)
}
}
selectedData.value = list
}
//
const delRecord = (record) => {
remove(selectedData.value, (item) => item.id === record.id)
}
//
const delAllRecord = () => {
selectedData.value = []
}
//
const treeSelect = (selectedKeys) => {
searchFormState.value.current = 0
if (selectedKeys.length > 0) {
searchFormState.value.orgId = selectedKeys.toString()
} else {
delete searchFormState.value.orgId
}
loadData()
}
const userObj = ref([])
//
const handleOk = () => {
userObj.value = []
const value = []
const showUser = []
selectedData.value.forEach((item) => {
const obj = {
id: item.id,
name: item.name
}
value.push(item.id)
// obj
const objClone = cloneDeep(obj)
objClone.avatar = item.avatar
showUser.push(objClone)
})
userObj.value = showUser
//
const resultData = outDataConverter(value)
emit('update:value', resultData)
emit('onBack', resultData)
handleClose()
}
//
const reset = () => {
delete searchFormState.value.searchKey
loadData()
}
const handleClose = () => {
searchFormState.value = {}
tableRecordNum.value = 0
tableData.value = []
current.value = 0
pageSize.value = 20
total.value = 0
selectedData.value = []
// userObj.value = []
visible.value = false
}
//
const goDataConverter = (data) => {
if (props.dataIsConverterFlw) {
const resultData = []
//
if (!isEmpty(data.value)) {
const values = data.value.split(',')
if (values.length > 0) {
values.forEach((id) => {
resultData.push(id)
})
} else {
resultData.push(data.value)
}
} else {
//
if (!isEmpty(data) && !isEmpty(data[0]) && !isEmpty(data[0].value)) {
const values = data[0].value.split(',')
for (let i = 0; i < values.length; i++) {
resultData.push(values[i])
}
}
}
return resultData
} else {
if (getValueType() !== 'string') {
return data
}
if (data.length > 1) {
const resultData = []
data.split(',').forEach((id) => {
resultData.push(id)
})
return resultData
} else {
return data
}
}
}
//
const outDataConverter = (data) => {
if (props.dataIsConverterFlw) {
data = userObj.value
const obj = {}
let label = ''
let value = ''
for (let i = 0; i < data.length; i++) {
if (data.length === i + 1) {
label = label + data[i].name
value = value + data[i].id
} else {
label = label + data[i].name + ','
value = value + data[i].id + ','
}
}
obj.key = 'USER'
obj.label = label
obj.value = value
obj.extJson = ''
return obj
} else {
if (getValueType() !== 'string') {
return data
}
let resultData = ''
data.forEach((id) => {
resultData = resultData + ',' + id
})
resultData = resultData.substring(1, resultData.length)
return resultData
}
}
//
const getValueType = () => {
if (props.dataType) {
return props.dataType
} else {
if (props.radioModel) {
return 'string'
}
return typeof typeof props.value
}
}
const getUserAvatarById = (ids) => {
if (isEmpty(userObj.value) && !isEmpty(ids)) {
const param = {
idList: recordIds.value
}
//
props.userListByIdListApi(param).then((data) => {
userObj.value = data
})
}
}
watch(
() => props.value,
(newValue) => {
if (!isEmpty(props.value)) {
const ids = goDataConverter(newValue)
recordIds.value = ids
getUserAvatarById(ids)
}
},
{
immediate: true //
}
)
defineExpose({
showUserPlusModal
})
</script>
<style lang="less" scoped>
.xn-mr-5 {
margin-right: 5px;
}
.xn-mr-10 {
margin-right: 10px;
}
.selectorTreeDiv {
max-height: 500px;
overflow: auto;
}
.ant-form-item {
margin-bottom: 0 !important;
}
.user-table {
overflow: auto;
max-height: 450px;
}
.user-container {
display: flex;
align-items: center; /* 垂直居中 */
flex-direction: column;
margin-right: 10px;
text-align: center;
}
.user-avatar {
width: 30px;
border-radius: 50%; /* 设置为50%以创建圆形头像 */
}
.user-name {
font-size: 12px;
max-width: 50px;
white-space: nowrap;
overflow: hidden;
}
.user-delete {
z-index: 99;
color: rgba(0, 0, 0, 0.25);
position: relative;
display: flex;
flex-direction: column;
}
.delete-icon {
position: absolute;
right: -2px;
z-index: 5;
top: -3px;
cursor: pointer;
visibility: hidden;
}
.show-delete-icon {
visibility: visible;
}
</style>

View File

@ -0,0 +1,62 @@
<template>
<a-card>
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
表单的值{{ formData }}
<a-form-item name="userIdList">
<xn-user-selector
ref="userSelectorPlusProRef"
:org-tree-api="selectorApiFunction.orgTreeApi"
:user-page-api="selectorApiFunction.userPageApi"
:user-list-by-id-list-api="selectorApiFunction.userListByIdListApi"
v-model:value="formData.userIdList"
@onBack="userSelectorOnBack"
/>
</a-form-item>
</a-form>
<a-button type="primary" @click="onSubmit"></a-button>
</a-card>
</template>
<script setup name="userTest">
import bizOrgApi from '@/api/biz/bizOrgApi'
import userCenterApi from '@/api/sys/userCenterApi'
import { required } from '@/utils/formRules'
const formRef = ref()
const formData = ref({
userIdList: '1543837863788879871,1543837863788879873'
// userIdList: ['1543837863788879871', '1543837863788879873']
})
const formRules = {
userIdList: [required('请选择用户')]
}
const onSubmit = () => {
formRef.value
.validate()
.then((result) => {
console.log('最终表单数据:' + JSON.stringify(result))
})
.catch(() => {})
}
// API
const selectorApiFunction = {
orgTreeApi: (param) => {
return bizOrgApi.orgTreeSelector(param).then((data) => {
return Promise.resolve(data)
})
},
userPageApi: (param) => {
return bizOrgApi.orgUserSelector(param).then((data) => {
return Promise.resolve(data)
})
},
userListByIdListApi: (param) => {
return userCenterApi.userCenterGetUserListByIdList(param).then((data) => {
return Promise.resolve(data)
})
}
}
// v-model:value
const userSelectorOnBack = (data) => {
console.log('返回的:' + JSON.stringify(data))
}
</script>

View File

@ -30,7 +30,7 @@ const DEFAULT_CONFIG = {
// 请求是否开启缓存 // 请求是否开启缓存
REQUEST_CACHE: false, REQUEST_CACHE: false,
// 布局 经典classical双排菜单doublerow // 布局 经典classical双排菜单doublerow, 顶栏菜单top
SNOWY_LAYOUT: 'doublerow', SNOWY_LAYOUT: 'doublerow',
// 菜单是否折叠 // 菜单是否折叠
@ -54,11 +54,20 @@ const DEFAULT_CONFIG = {
// 侧边菜单是否排他展开 // 侧边菜单是否排他展开
SNOWY_SIDE_UNIQUE_OPEN: true, SNOWY_SIDE_UNIQUE_OPEN: true,
// 登录用户水印
SNOWY_LOGIN_USER_WATERMARK_OPEN: false,
// 页脚版权信息
SNOWY_FOOTER_COPYRIGHT_OPEN: true,
// 圆角风格
SNOWY_ROUNDED_CORNER_STYLE_OPEN: true,
// 语言 // 语言
LANG: 'zh-cn', LANG: 'zh-cn',
// 主题颜色 // 主题颜色
COLOR: '#1890FF', COLOR: '#1677FF',
// 默认整体主题 // 默认整体主题
SNOWY_THEME: 'dark', SNOWY_THEME: 'dark',
@ -66,15 +75,6 @@ const DEFAULT_CONFIG = {
// 整体表单风格 // 整体表单风格
SNOWY_FORM_STYLE: 'drawer', SNOWY_FORM_STYLE: 'drawer',
// 成功色
success: '#52c41a',
// 警告色
warning: '#faad14',
// 错误色
error: '#f5222f',
// 系统基础配置,这些是数据库中保存起来的 // 系统基础配置,这些是数据库中保存起来的
SYS_BASE_CONFIG: { SYS_BASE_CONFIG: {
// 默认logo // 默认logo

View File

@ -39,7 +39,7 @@ const colorList = [
}, },
{ {
key: '拂晓蓝(默认)', key: '拂晓蓝(默认)',
color: '#1890FF' color: '#1677FF'
}, },
{ {
key: '极客蓝', key: '极客蓝',

View File

@ -1,5 +1,5 @@
<template> <template>
<div v-if="navMenus.length <= 0" style="padding: 20px"> <div v-if="navMenus.length <= 0" class="xn-pd20">
<a-alert message="无任何菜单" type="info" :closable="false" /> <a-alert message="无任何菜单" type="info" :closable="false" />
</div> </div>
<template v-for="navMenu in navMenus" :key="navMenu"> <template v-for="navMenu in navMenus" :key="navMenu">
@ -26,6 +26,8 @@
</template> </template>
<script setup> <script setup>
import { globalStore } from '@/store'
const store = globalStore()
const props = defineProps({ const props = defineProps({
navMenus: { navMenus: {
type: Array, type: Array,
@ -44,3 +46,20 @@
return false return false
} }
</script> </script>
<style>
.ant-menu-light.ant-menu-horizontal > .ant-menu-submenu-selected {
background-color: var(--primary-1);
}
.ant-menu-dark.ant-menu-horizontal > .ant-menu-submenu-selected {
background-color: var(--primary-5);
}
.ant-menu-light.ant-menu-horizontal > .ant-menu-item-selected {
background-color: none;
}
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item-selected {
background-color: var(--primary-5);
}
.xn-pd20 {
padding: 20px;
}
</style>

View File

@ -0,0 +1,53 @@
<template>
<div class="admin-ui-breadcrumb">
<div class="left-panel">
<a-breadcrumb>
<template v-for="item in breadList" :key="item.title">
<a-breadcrumb-item v-if="item.path !== '/' && !item.meta.hiddenBreadcrumb" :key="item.meta.title">{{
item.meta.title
}}</a-breadcrumb-item>
</template>
</a-breadcrumb>
</div>
<div class="center-panel"></div>
<div class="right-panel">
<slot></slot>
</div>
</div>
</template>
<script setup>
import { watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const breadList = ref([])
watch(route, () => {
getBreadcrumb()
})
onBeforeMount(() => {
getBreadcrumb()
})
const getBreadcrumb = () => {
breadList.value = route.meta.breadcrumb
}
</script>
<style scoped>
.admin-ui-breadcrumb {
padding-left: 15px;
background: var(--breadcrumb-background);
min-height: 40px;
display: flex;
border-bottom: 1px solid var(--header-bottom);
}
.admin-ui-breadcrumb .left-panel {
display: flex;
align-items: center;
}
.admin-ui-breadcrumb .right-panel {
display: flex;
align-items: center;
}
</style>

View File

@ -3,7 +3,7 @@
<a-badge :count="unreadMessageNum" class="badge"> <a-badge :count="unreadMessageNum" class="badge">
<comment-outlined /> <comment-outlined />
</a-badge> </a-badge>
<a-drawer v-model:visible="msgVisible" title="新消息" placement="right" :width="500"> <a-drawer v-model:open="msgVisible" title="新消息" placement="right" :width="500">
<a-list :data-source="messageList" size="small" class="mb-3" :loading="miniMessageLoading"> <a-list :data-source="messageList" size="small" class="mb-3" :loading="miniMessageLoading">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item> <a-list-item>
@ -15,12 +15,12 @@
</a-list-item> </a-list-item>
</template> </template>
</a-list> </a-list>
<a-space style="float: right"> <a-space class="xn-fdr">
<a-button v-if="unreadMessageNum > 0" @click="markRead"></a-button> <a-button v-if="unreadMessageNum > 0" @click="markRead"></a-button>
<a-button type="primary" @click="leaveFor('/usercenter')"></a-button> <a-button type="primary" @click="leaveFor('/usercenter')"></a-button>
</a-space> </a-space>
</a-drawer> </a-drawer>
<xn-form-container title="详情" :width="700" :visible="visible" :destroy-on-close="true" @close="onClose"> <xn-form-container title="详情" :width="700" :open="visible" :destroy-on-close="true" @close="onClose">
<a-form ref="formRef" :model="formData" layout="vertical"> <a-form ref="formRef" :model="formData" layout="vertical">
<a-form-item label="主题:" name="subject"> <a-form-item label="主题:" name="subject">
<span>{{ formData.subject }}</span> <span>{{ formData.subject }}</span>
@ -43,8 +43,8 @@
> >
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'read'"> <template v-if="column.dataIndex === 'read'">
<span v-if="record.read" style="color: #d9d9d9"></span> <span v-if="record.read" class="xn-color-d9d9d9"></span>
<span v-else style="color: #ff4d4f">未读</span> <span v-else class="xn-color-ff4d4f">未读</span>
</template> </template>
</template> </template>
</s-table> </s-table>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="layout-items-center" v-if="moduleUnfoldOpen"> <div class="layout-items-center" v-if="moduleUnfoldOpen && layout !== layoutEnum.TOP">
<a-menu <a-menu
v-model:selectedKeys="selectedKeys" v-model:selectedKeys="selectedKeys"
mode="horizontal" mode="horizontal"
@ -10,14 +10,14 @@
<a-menu-item <a-menu-item
v-for="item in menu" v-for="item in menu"
:key="item.id" :key="item.id"
class="!px-3" class="xn-pxn-r"
style="position: relative"
@click="moduleClick(item.id)" @click="moduleClick(item.id)"
:class="{ 'ant-menu-item-select': item.id === module }"
> >
<template #icon> <template #icon>
<component :is="item.meta.icon" /> <component :is="item.meta.icon" />
</template> </template>
<span style="margin-left: -5px">{{ item.meta.title }}</span> <span class="xn-ml-5">{{ item.meta.title }}</span>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
</div> </div>
@ -27,7 +27,12 @@
<a-row :gutter="[0, 5]" class="module-row"> <a-row :gutter="[0, 5]" class="module-row">
<div v-for="item in menu" :key="item.id"> <div v-for="item in menu" :key="item.id">
<a-col :span="6"> <a-col :span="6">
<a-tag class="module-card" :color="item.color" @click="moduleClick(item.id)"> <a-tag
class="module-card"
:class="roundedCornerStyleOpen ? 'module-card-radius-round' : 'module-card-radius-default'"
:color="item.color"
@click="moduleClick(item.id)"
>
<component :is="item.meta.icon" class="module-card-icon" /> <component :is="item.meta.icon" class="module-card-icon" />
<div class="module-card-font">{{ item.meta.title }}</div> <div class="module-card-font">{{ item.meta.title }}</div>
</a-tag> </a-tag>
@ -48,33 +53,69 @@
import { globalStore } from '@/store' import { globalStore } from '@/store'
import { watch } from 'vue' import { watch } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { layoutEnum } from '@/layout/enum/layoutEnum'
const store = globalStore() const store = globalStore()
const { moduleUnfoldOpen, topHeaderThemeColorOpen } = storeToRefs(store) const { moduleUnfoldOpen, topHeaderThemeColorOpen } = storeToRefs(store)
const moduleBackColor = ref(topHeaderThemeColorOpen) const moduleBackColor = ref(topHeaderThemeColorOpen)
const layout = ref()
const module = computed(() => { const module = computed(() => {
return store.module return store.module
}) })
const isMobile = computed(() => { const isMobile = computed(() => {
return store.isMobile return store.isMobile
}) })
const themeColor = computed(() => {
return store.themeColor
})
const theme = computed(() => {
return store.theme
})
//
const roundedCornerStyleOpen = computed(() => {
return store.roundedCornerStyleOpen
})
// //
watch(moduleUnfoldOpen, (newValue) => { watch(moduleUnfoldOpen, () => {
nextTick(() => { nextTick(() => {
setModuleBackColor() setModuleBackColor()
}) })
}) })
//
watch(module, (newValue) => { watch(module, (newValue) => {
selectedKeys.value = [newValue] selectedKeys.value = [newValue]
setSelectedKeys() setSelectedKeys()
}) })
//
watch(themeColor, () => {
nextTick(() => {
setModuleBackColor()
})
})
//
watch(theme, () => {
nextTick(() => {
setModuleBackColor()
})
})
//
watch(isMobile, (newValue) => {
if (!newValue) {
nextTick(() => {
setModuleBackColor()
})
}
})
// //
watch(topHeaderThemeColorOpen, (newValue) => { watch(topHeaderThemeColorOpen, (newValue) => {
moduleBackColor.value = newValue moduleBackColor.value = newValue
setModuleBackColor() setModuleBackColor()
}) })
//
watch(roundedCornerStyleOpen, () => {
nextTick(() => {
setModuleBackColor()
})
})
const emit = defineEmits({ switchModule: null }) const emit = defineEmits({ switchModule: null })
const menu = router.getMenu() const menu = router.getMenu()
const selectedKeys = ref([module.value]) const selectedKeys = ref([module.value])
@ -85,9 +126,9 @@
setSelectedKeys() setSelectedKeys()
}) })
} }
onMounted(() => { onMounted(() => {
setModuleBackColor() setModuleBackColor()
layout.value = tool.data.get('SNOWY_LAYOUT')
}) })
// //
const setModuleBackColor = () => { const setModuleBackColor = () => {
@ -112,26 +153,33 @@
</script> </script>
<style lang="less"> <style lang="less">
.xn-pxn-r {
position: relative;
}
.module-row { .module-row {
max-width: 357px; max-width: 357px;
} }
.module-card { .module-card {
width: 80px; width: 70px;
height: 80px; height: 70px;
background-color: #0d84ff; background-color: #0d84ff;
text-align: center; text-align: center;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
}
.module-card-radius-default {
border-radius: 2px; border-radius: 2px;
} }
.module-card-radius-round {
border-radius: 6px;
}
.module-card-icon { .module-card-icon {
color: white; color: white;
font-size: 20px; font-size: 16px;
margin-top: 20px; margin-top: 15px;
} }
.module-card-font { .module-card-font {
color: white; color: white;
font-size: 8px;
} }
.ant-menu-horizontal > .ant-menu-item::after, .ant-menu-horizontal > .ant-menu-item::after,
.ant-menu-horizontal > .ant-menu-submenu::after { .ant-menu-horizontal > .ant-menu-submenu::after {
@ -139,7 +187,7 @@
} }
.module-menu { .module-menu {
line-height: 50px; line-height: 50px;
border-bottom: 0px; border-bottom: 0;
width: 105%; width: 105%;
flex: 0 0 auto; flex: 0 0 auto;
} }
@ -153,4 +201,15 @@
.module-card-scope { .module-card-scope {
height: 49px; height: 49px;
} }
.ant-menu-item-select {
color: #ccc;
background-color: var(--primary-7);
}
.xn-ml-5 {
margin-left: -5px;
}
.ant-menu-horizontal > .ant-menu-item::after,
.ant-menu-horizontal > .ant-menu-submenu::after {
display: none;
}
</style> </style>

View File

@ -22,8 +22,7 @@
<a-input <a-input
ref="inputRef" ref="inputRef"
v-model="searchText" v-model="searchText"
class="search-box" class="search-box xn-wd"
style="width: 100%"
allowClear allowClear
placeholder="搜索页面(支持拼音检索)" placeholder="搜索页面(支持拼音检索)"
@change="querySearch" @change="querySearch"
@ -39,7 +38,8 @@
@mouseleave="onCardOut" @mouseleave="onCardOut"
@keypress.up="handleKeyUp" @keypress.up="handleKeyUp"
@keypress.down="handleKeyDown" @keypress.down="handleKeyDown"
style="margin: 10px 0" class="xn-mn10p0"
> >
<div ref="cardListRef" class="search-card beauty-scroll"> <div ref="cardListRef" class="search-card beauty-scroll">
<a-list size="small" :data-source="resultsList"> <a-list size="small" :data-source="resultsList">
@ -47,8 +47,7 @@
<a-list-item <a-list-item
@click="handleSelect(item.fullPath)" @click="handleSelect(item.fullPath)"
@mouseover="onCardItemHover(index)" @mouseover="onCardItemHover(index)"
:class="{ active: index === cardIndex }" :class="{ active: index === cardIndex },'xn-pr10'"
style="padding-right: 10px"
> >
<template #actions> <template #actions>
<a> <a>
@ -279,6 +278,12 @@
:deep(.ant-list-item.active) { :deep(.ant-list-item.active) {
background-color: var(--primary-1); background-color: var(--primary-1);
} }
.xn-mn10p0 {
margin: 10px 0;
}
.xn-pr10 {
padding-right: 10px;
}
.search-box { .search-box {
width: 100%; width: 100%;
} }
@ -321,7 +326,10 @@
padding-bottom: 2px; padding-bottom: 2px;
margin: 0px 4px; margin: 0px 4px;
border-radius: 2px; border-radius: 2px;
box-shadow: inset 0 -2px #cdcde6, inset 0 0 1px 1px #fff, 0 1px 2px 1px #1e235a66; box-shadow:
inset 0 -2px #cdcde6,
inset 0 0 1px 1px #fff,
0 1px 2px 1px #1e235a66;
font-weight: bold; font-weight: bold;
} }
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="setting-drawer-index-content"> <div class="setting-drawer-index-content">
<div class="scrollbar"> <div class="scrollbar">
<h3>整体风格设置</h3> <h3 class="setting-item-title">整体风格设置</h3>
<div class="snowy-setting-checkbox"> <div class="snowy-setting-checkbox">
<a-tooltip v-for="(a, i) in sideStyleList" :key="i" placement="top"> <a-tooltip v-for="(a, i) in sideStyleList" :key="i" placement="top">
<template #title> <template #title>
@ -12,7 +12,7 @@
</div> </div>
</a-tooltip> </a-tooltip>
</div> </div>
<h3>整体界面布局</h3> <h3 class="setting-item-title">整体界面布局</h3>
<div class="snowy-setting-checkbox"> <div class="snowy-setting-checkbox">
<a-tooltip v-for="(a, i) in layoutList" :key="i" placement="top"> <a-tooltip v-for="(a, i) in layoutList" :key="i" placement="top">
<template #title> <template #title>
@ -27,7 +27,7 @@
</div> </div>
<a-divider /> <a-divider />
<div class="mb-4"> <div class="mb-4">
<h3>主题色</h3> <h3 class="setting-item-title">主题色</h3>
<div class="h-[50px]"> <div class="h-[50px]">
<a-tooltip v-for="(item, index) in colorList" :key="index" class="snowy-setting-theme-color-colorBlock"> <a-tooltip v-for="(item, index) in colorList" :key="index" class="snowy-setting-theme-color-colorBlock">
<template #title> <template #title>
@ -39,23 +39,35 @@
</a-tooltip> </a-tooltip>
</div> </div>
</div> </div>
<div class="mb-4 layout-slide"> <div class="mb-4 layout-slide" v-if="!topHeaderThemeColorOpenDisabled" style="padding-top: 10px">
<h4 class="">顶栏应用主题色</h4> <h4 class="setting-item-title">顶栏应用主题色</h4>
<a-switch :checked="topHeaderThemeColorOpen" @change="changeTopHanderThemeColorOpen" />
</div>
<div class="mb-4 layout-slide">
<h4>顶栏主题色通栏</h4>
<a-switch <a-switch
style="float: right" :checked="topHeaderThemeColorOpen"
:checked="topHeaderThemeColorSpread" @change="changeTopHeaderThemeColorOpen"
:disabled="!topHeaderThemeColorOpen" :disabled="topHeaderThemeColorOpenDisabled"
@change="changeTopHanderThemeColorSpread"
/> />
</div> </div>
<div class="mb-4 layout-slide" v-if="!topHeaderThemeColorSpreadDisabled">
<h4 class="setting-item-title">顶栏主题色通栏</h4>
<a-switch
class="xn-fdr"
:checked="topHeaderThemeColorSpread"
:disabled="!topHeaderThemeColorOpen || topHeaderThemeColorSpreadDisabled"
@change="changeTopHeaderThemeColorSpread"
/>
</div>
<a-divider /> <a-divider />
<a-form ref="formRef" class="text-right"> <a-form ref="formRef" class="text-right">
<a-form-item label="模块坞"> <a-form-item label="模块坞" v-if="!moduleUnfoldDisabled">
<a-switch :checked="moduleUnfoldOpen" @change="toggleState('moduleUnfoldOpen')" /> <a-switch
:checked="moduleUnfoldOpen"
@change="toggleState('moduleUnfoldOpen')"
:disabled="moduleUnfoldDisabled"
/>
</a-form-item>
<a-form-item label="固定宽度" v-if="layout == layoutEnum.TOP">
<a-switch :checked="fixedWidth" @change="toggleState('fixedWidth')" />
</a-form-item> </a-form-item>
<a-form-item label="面包屑"> <a-form-item label="面包屑">
<a-switch :checked="breadcrumbOpen" @change="toggleState('breadcrumbOpen')" /> <a-switch :checked="breadcrumbOpen" @change="toggleState('breadcrumbOpen')" />
@ -63,11 +75,28 @@
<a-form-item label="多标签"> <a-form-item label="多标签">
<a-switch :checked="layoutTagsOpen" @change="toggleState('layoutTagsOpen')" /> <a-switch :checked="layoutTagsOpen" @change="toggleState('layoutTagsOpen')" />
</a-form-item> </a-form-item>
<a-form-item label="折叠菜单"> <a-form-item label="折叠菜单" v-if="!menuIsCollapseDisabled">
<a-switch :checked="menuIsCollapse" @change="toggleState('menuIsCollapse')" /> <a-switch
:checked="menuIsCollapse"
@change="toggleState('menuIsCollapse')"
:disabled="menuIsCollapseDisabled"
/>
</a-form-item> </a-form-item>
<a-form-item label="菜单排他展开"> <a-form-item label="菜单排他展开" v-if="!sideUniqueOpenDisabled">
<a-switch :checked="sideUniqueOpen" @change="toggleState('sideUniqueOpen')" /> <a-switch
:checked="sideUniqueOpen"
@change="toggleState('sideUniqueOpen')"
:disabled="sideUniqueOpenDisabled"
/>
</a-form-item>
<a-form-item label="登录用户水印">
<a-switch :checked="loginUserWatermarkOpen" @change="toggleState('loginUserWatermarkOpen')" />
</a-form-item>
<a-form-item label="页脚版权信息">
<a-switch :checked="footerCopyrightOpen" @change="toggleState('footerCopyrightOpen')" />
</a-form-item>
<a-form-item label="圆角风格">
<a-switch :checked="roundedCornerStyleOpen" @change="toggleState('roundedCornerStyleOpen')" />
</a-form-item> </a-form-item>
<a-form-item label="表单风格"> <a-form-item label="表单风格">
<a-select <a-select
@ -88,50 +117,63 @@
</template> </template>
<script setup> <script setup>
import { colorList } from '@/config/settingConfig' import { colorList } from '@/config/settingConfig'
import { ThemeModeEnum } from '@/utils/enum' import { themeEnum } from '@/layout/enum/themeEnum'
import { layoutEnum } from '@/layout/enum/layoutEnum'
import { globalStore } from '@/store' import { globalStore } from '@/store'
import tool from '@/utils/tool' import tool from '@/utils/tool'
const store = globalStore() const store = globalStore()
const topHeaderThemeColorOpenDisabled = ref(false)
const topHeaderThemeColorSpreadDisabled = ref(false)
const moduleUnfoldDisabled = ref(false)
const menuIsCollapseDisabled = ref(false)
const sideUniqueOpenDisabled = ref(false)
const toolDataNameMap = { const toolDataNameMap = {
menuIsCollapse: 'MENU_COLLAPSE', menuIsCollapse: 'MENU_COLLAPSE',
sideUniqueOpen: 'SIDE_UNIQUE_OPEN', sideUniqueOpen: 'SIDE_UNIQUE_OPEN',
layoutTagsOpen: 'LAYOUT_TAGS_OPEN', layoutTagsOpen: 'LAYOUT_TAGS_OPEN',
breadcrumbOpen: 'BREADCRUMD_OPEN', breadcrumbOpen: 'BREADCRUMD_OPEN',
fixedWidth: 'FIXEDWIDTH_OPEN',
topHeaderThemeColorOpen: 'TOP_HEADER_THEME_COLOR_OPEN', topHeaderThemeColorOpen: 'TOP_HEADER_THEME_COLOR_OPEN',
topHeaderThemeColorSpread: 'TOP_HEADER_THEME_COLOR_SPREAD', topHeaderThemeColorSpread: 'TOP_HEADER_THEME_COLOR_SPREAD',
loginUserWatermarkOpen: 'LOGIN_USER_WATERMARK_OPEN',
footerCopyrightOpen: 'FOOTER_COPYRIGHT_OPEN',
roundedCornerStyleOpen: 'ROUNDED_CORNER_STYLE_OPEN',
moduleUnfoldOpen: 'MODULE_UNFOLD_OPEN' moduleUnfoldOpen: 'MODULE_UNFOLD_OPEN'
} }
const sideStyleList = ref([ const sideStyleList = ref([
{ {
tips: '暗色主题风格', tips: '暗色主题风格',
value: ThemeModeEnum.DARK, value: themeEnum.DARK,
style: 'snowy-setting-checkbox-item-dark' style: 'snowy-setting-checkbox-item-dark'
}, },
{ {
tips: '亮色主题风格', tips: '亮色主题风格',
value: ThemeModeEnum.LIGHT, value: themeEnum.LIGHT,
style: 'snowy-setting-checkbox-item-light' style: 'snowy-setting-checkbox-item-light'
}, },
{ {
tips: '暗黑模式', tips: '暗黑模式',
value: ThemeModeEnum.REAL_DARK, value: themeEnum.REAL_DARK,
style: 'snowy-setting-checkbox-item-realdark' style: 'snowy-setting-checkbox-item-realdark'
} }
]) ])
const layoutList = ref([ const layoutList = ref([
{ {
tips: '经典', tips: '经典',
value: 'classical', value: layoutEnum.CLASSICAL,
style: 'snowy-setting-layout-menu-classical' style: 'snowy-setting-layout-menu-classical'
}, },
{ {
tips: '双排菜单', tips: '双排菜单',
value: 'doublerow', value: layoutEnum.DOUBLEROW,
style: 'snowy-setting-layout-menu-doublerow' style: 'snowy-setting-layout-menu-doublerow'
},
{
tips: '顶部菜单',
value: layoutEnum.TOP,
style: 'snowy-setting-layout-menu-top'
} }
]) ])
const xnFormStyleOptions = ref([ const xnFormStyleOptions = ref([
{ {
label: '抽屉', label: '抽屉',
@ -142,7 +184,6 @@
value: 'modal' value: 'modal'
} }
]) ])
const theme = computed(() => { const theme = computed(() => {
return store.theme return store.theme
}) })
@ -158,12 +199,24 @@
const sideUniqueOpen = computed(() => { const sideUniqueOpen = computed(() => {
return store.sideUniqueOpen return store.sideUniqueOpen
}) })
const loginUserWatermarkOpen = computed(() => {
return store.loginUserWatermarkOpen
})
const footerCopyrightOpen = computed(() => {
return store.footerCopyrightOpen
})
const roundedCornerStyleOpen = computed(() => {
return store.roundedCornerStyleOpen
})
const layoutTagsOpen = computed(() => { const layoutTagsOpen = computed(() => {
return store.layoutTagsOpen return store.layoutTagsOpen
}) })
const breadcrumbOpen = computed(() => { const breadcrumbOpen = computed(() => {
return store.breadcrumbOpen return store.breadcrumbOpen
}) })
const fixedWidth = computed(() => {
return store.fixedWidth
})
const moduleUnfoldOpen = computed(() => { const moduleUnfoldOpen = computed(() => {
return store.moduleUnfoldOpen return store.moduleUnfoldOpen
}) })
@ -176,16 +229,14 @@
const formStyle = computed(() => { const formStyle = computed(() => {
return store.formStyle return store.formStyle
}) })
const changeTopHeaderThemeColorOpen = () => {
const changeTopHanderThemeColorOpen = () => {
toggleState('topHeaderThemeColorOpen') toggleState('topHeaderThemeColorOpen')
if (!topHeaderThemeColorOpen) { if (!topHeaderThemeColorOpen.value) {
store.topHeaderThemeColorSpread = false store.topHeaderThemeColorSpread = false
tool.data.set('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD', false) tool.data.set('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD', false)
} }
} }
const changeTopHeaderThemeColorSpread = () => {
const changeTopHanderThemeColorSpread = () => {
toggleState('topHeaderThemeColorSpread') toggleState('topHeaderThemeColorSpread')
} }
const toggleState = (stateName) => { const toggleState = (stateName) => {
@ -197,11 +248,13 @@
const setSideStyle = (value) => { const setSideStyle = (value) => {
store.setTheme(value) store.setTheme(value)
tool.data.set('SNOWY_THEME', value) tool.data.set('SNOWY_THEME', value)
layoutChange(layout.value)
} }
// //
const layoutStyle = (value) => { const layoutStyle = (value) => {
store.setLayout(value) store.setLayout(value)
tool.data.set('SNOWY_LAYOUT', value) tool.data.set('SNOWY_LAYOUT', value)
layoutChange(value)
} }
// //
const tagColor = (value) => { const tagColor = (value) => {
@ -213,6 +266,48 @@
tool.data.set('SNOWY_FORM_STYLE', value) tool.data.set('SNOWY_FORM_STYLE', value)
store.setFormStyle(value) store.setFormStyle(value)
} }
//
const layoutChange = (layout) => {
//
if (theme.value === themeEnum.REAL_DARK) {
topHeaderThemeColorOpenDisabled.value = true
topHeaderThemeColorSpreadDisabled.value = true
//
if (topHeaderThemeColorOpen.value) {
toggleState('topHeaderThemeColorOpen')
tool.data.set('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD', false)
}
} else {
if (layout !== layoutEnum.TOP) {
topHeaderThemeColorSpreadDisabled.value = false
topHeaderThemeColorOpenDisabled.value = false
} else {
topHeaderThemeColorOpenDisabled.value = false
}
}
//
if (layout === layoutEnum.TOP) {
//
moduleUnfoldDisabled.value = true
//
menuIsCollapseDisabled.value = true
//
if (sideUniqueOpen.value) {
toggleState('sideUniqueOpen')
}
sideUniqueOpenDisabled.value = true
topHeaderThemeColorSpreadDisabled.value = true
} else {
moduleUnfoldDisabled.value = false
menuIsCollapseDisabled.value = false
sideUniqueOpenDisabled.value = false
}
}
onMounted(() => {
const layout = tool.data.get('SNOWY_LAYOUT')
// dom
layoutChange(layout)
})
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@ -294,12 +389,11 @@
position: absolute; position: absolute;
right: 8px; right: 8px;
bottom: 8px; bottom: 8px;
color: #1890ff; color: #1677FF;
font-weight: 700; font-weight: 700;
font-size: 14px; font-size: 14px;
pointer-events: none; pointer-events: none;
} }
.snowy-setting-theme-color-colorBlock { .snowy-setting-theme-color-colorBlock {
margin-top: 8px; margin-top: 8px;
width: 20px; width: 20px;
@ -314,7 +408,6 @@
color: #fff; color: #fff;
font-weight: 700; font-weight: 700;
} }
.snowy-setting-layout-menu-doublerow { .snowy-setting-layout-menu-doublerow {
z-index: 1; z-index: 1;
background-color: #ebeef1; background-color: #ebeef1;
@ -364,8 +457,33 @@
background-color: #fff; background-color: #fff;
content: ''; content: '';
} }
.snowy-setting-layout-menu-top {
z-index: 1;
background-color: #ebeef1;
content: '';
}
.snowy-setting-layout-menu-top::before {
z-index: 1;
background-color: #ebeef1;
content: '';
}
.snowy-setting-layout-menu-top::after {
z-index: 2;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 25%;
background-color: #001529;
content: '';
}
.scrollbar { .scrollbar {
margin: 0 auto; margin: 0 auto;
} }
.setting-item-title {
color: var(--font-color);
}
:deep(.ant-form-item) {
margin-bottom: 12px !important;
}
</style> </style>

View File

@ -1,8 +1,8 @@
<template> <template>
<div v-drag class="mobile-nav-button" draggable="false" @click="showMobileNav($event)"> <div v-drag class="mobile-nav-button" draggable="false" @click="showMobileNav($event)">
<appstore-outlined style="font-size: 20px; color: white" /> <appstore-outlined class="xn-appout-line" />
</div> </div>
<a-drawer v-model:visible="visible" :width="210" :closable="false" placement="left"> <a-drawer v-model:open="visible" :width="210" :closable="false" placement="left">
<header class="snowy-header-logo mobile-nav"> <header class="snowy-header-logo mobile-nav">
<div class="snowy-header-left"> <div class="snowy-header-left">
<div class="logo-bar"> <div class="logo-bar">
@ -11,7 +11,7 @@
</div> </div>
</div> </div>
</header> </header>
<a-menu style="width: 208px; margin-left: -24px" mode="inline" @select="onSelect"> <a-menu class="xn-inline-line" mode="inline" @select="onSelect">
<NavMenu :nav-menus="menu"></NavMenu> <NavMenu :nav-menus="menu"></NavMenu>
</a-menu> </a-menu>
</a-drawer> </a-drawer>
@ -113,6 +113,14 @@
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.xn-appout-line {
font-size: 20px;
color: white;
}
.xn-inline-line {
width: 208px;
margin-left: -24px;
}
.mobile-nav { .mobile-nav {
margin-top: -24px; margin-top: -24px;
margin-left: -24px; margin-left: -24px;

View File

@ -9,32 +9,33 @@
> >
<div class="right-menu-item" @click="refreshTab"> <div class="right-menu-item" @click="refreshTab">
<reload-outlined class="snowy-header-tags-right" /> <reload-outlined class="snowy-header-tags-right" />
<div class="pl-3">刷新</div> <div class="pl-3 snowy-header-tags-right-font">刷新</div>
</div> </div>
<div class="right-menu-item" @click="closeTabs"> <div class="right-menu-item" @click="closeTabs">
<close-outlined class="snowy-header-tags-right" /> <close-outlined class="snowy-header-tags-right" />
<div class="pl-3">关闭</div> <div class="pl-3 snowy-header-tags-right-font">关闭</div>
</div> </div>
<div class="right-menu-item" @click="closeOtherTabs"> <div class="right-menu-item" @click="closeOtherTabs">
<close-outlined class="snowy-header-tags-right" /> <close-outlined class="snowy-header-tags-right" />
<div class="pl-3">关闭其他标签</div> <div class="pl-3 snowy-header-tags-right-font">关闭其他标签</div>
</div> </div>
<div class="right-menu-item" @click="maximize"> <div class="right-menu-item" @click="maximize">
<expand-outlined class="snowy-header-tags-right" /> <expand-outlined class="snowy-header-tags-right" />
<div class="pl-3">最大化</div> <div class="pl-3 snowy-header-tags-right-font">最大化</div>
</div> </div>
<div class="right-menu-item" @click="openWindow"> <div class="right-menu-item" @click="openWindow">
<select-outlined class="snowy-header-tags-right" /> <select-outlined class="snowy-header-tags-right" />
<div class="pl-3">新窗口打开</div> <div class="pl-3 snowy-header-tags-right-font">新窗口打开</div>
</div> </div>
</xn-context-menu> </xn-context-menu>
<a-tabs <a-tabs
v-model:activeKey="activeKey" v-model:activeKey="activeKey"
type="editable-card" type="editable-card"
class="snowy-admin-tabs" :class="[{ 'snowy-radius': roundedCornerStyleOpen }, 'snowy-admin-tabs']"
:animated="!roundedCornerStyleOpen"
hide-add hide-add
ref="tabs" ref="tabs"
@edit="onTabRemove" @edit="onTabRemove"
@ -85,11 +86,13 @@
const layoutTagsOpen = computed(() => { const layoutTagsOpen = computed(() => {
return store.layoutTagsOpen return store.layoutTagsOpen
}) })
const roundedCornerStyleOpen = computed(() => {
return store.roundedCornerStyleOpen
})
const tagList = computed(() => { const tagList = computed(() => {
return viewTags.value return viewTags.value
}) })
watch(route, (to) => { watch(route, (to) => {
addViewTags(to) addViewTags(to)
activeKey.value = to.fullPath activeKey.value = to.fullPath
@ -97,7 +100,6 @@
watch(layoutTagsOpen, () => { watch(layoutTagsOpen, () => {
// closeOtherCacheTabs() // closeOtherCacheTabs()
}) })
onMounted(() => { onMounted(() => {
const tabNavList = document.querySelector('.ant-tabs-nav-list') const tabNavList = document.querySelector('.ant-tabs-nav-list')
if (tabNavList) { if (tabNavList) {
@ -299,9 +301,8 @@
</script> </script>
<style lang="less"> <style lang="less">
.snowy-admin-tabs { .snowy-admin-tabs {
overflow: hidden; //
&.ant-tabs { &.ant-tabs {
background: var(--component-background);
box-shadow: var(--header-light-shadow);
z-index: 99; z-index: 99;
.ant-tabs-nav { .ant-tabs-nav {
margin-bottom: 0; margin-bottom: 0;
@ -336,7 +337,6 @@
} }
} }
} }
.snowy-admin-tabs-drop, .snowy-admin-tabs-drop,
.snowy-admin-tabs-arrow, .snowy-admin-tabs-arrow,
.ant-tabs-nav-operations .ant-tabs-nav-more { .ant-tabs-nav-operations .ant-tabs-nav-more {
@ -355,7 +355,7 @@
} }
.right-menu { .right-menu {
position: fixed; position: fixed;
background: #fff; background: var(--tag-background);
z-index: 999; z-index: 999;
border: 1px solid #eee; border: 1px solid #eee;
box-shadow: 0 0.5em 1em 0 rgb(0 0 0 / 10%); box-shadow: 0 0.5em 1em 0 rgb(0 0 0 / 10%);
@ -374,4 +374,101 @@
} }
} }
} }
.snowy-tags {
height: 40px;
background: var(--snowy-background-color);
}
.snowy-tags ul {
display: flex;
overflow: hidden;
padding-left: 0;
}
.snowy-tags li {
cursor: pointer;
display: inline-block;
float: left;
line-height: 39.5px;
position: relative;
flex-shrink: 0;
}
.snowy-tags li::after {
content: ' ';
width: 1px;
height: 100%;
position: absolute;
right: 0px;
background-image: linear-gradient(#fff, #e6e6e6);
}
.snowy-tags li a {
padding: 0 10px;
width: 100%;
height: 100%;
text-decoration: none;
display: flex;
align-items: center;
}
.snowy-tags li i {
margin-left: 10px;
border-radius: 3px;
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
}
.snowy-tags li i:hover {
background: rgba(0, 0, 0, 0.2);
color: @body-background;
}
.snowy-tags li:hover {
background: @body-background;
}
.snowy-tags li.active {
background: @primary-color;
}
.snowy-tags li.active a {
color: var(--font-color);
}
.snowy-tags li.sortable-ghost {
opacity: 0;
}
.snowy-header-tags-right {
margin-right: 10px;
color: var(--font-color);
}
.snowy-header-tags-right-font {
color: var(--font-color);
}
.snowy-radius .ant-tabs-tab-active {
position: relative;
z-index: 1;
border-radius: 10px 10px 0 0 !important;
box-shadow:
12px 15px 0 0 var(--primary-1),
-12px 15px 0 0 var(--primary-1);
}
.snowy-radius .ant-tabs-tab-active::before {
content: '';
position: absolute;
left: -13px;
bottom: 1px;
width: 13px;
height: 40px;
background: var(--primary-radius);
border-radius: 0 0 20px 0;
}
.snowy-radius .ant-tabs-tab-active::after {
content: '';
position: absolute;
right: -13px;
bottom: 1px;
width: 13px;
height: 40px;
background: var(--primary-radius);
border-radius: 0 0 0 20px;
}
.snowy-radius .ant-tabs-ink-bar {
visibility: hidden !important;
}
</style> </style>

View File

@ -8,22 +8,22 @@
<!-- <dev-user-message />--> <!-- <dev-user-message />-->
<a-dropdown class="user panel-item"> <a-dropdown class="user panel-item">
<div class="user-avatar"> <div class="user-avatar">
<a-avatar :src="userInfo.avatar" /> <a-avatar :src="userInfo ? userInfo.avatar : undefined" />
<label>{{ userName }}</label> <label>{{ userName }}</label>
</div> </div>
<template #overlay> <template #overlay>
<a-menu> <a-menu>
<a-menu-item key="uc" @click="handleUser('uc')"> <a-menu-item key="uc" @click="handleUser('uc')">
<UserOutlined style="margin-right: 8px" /> <UserOutlined class="xn-mr8" />
<span>个人中心</span> <span>个人中心</span>
</a-menu-item> </a-menu-item>
<a-menu-item key="clearCache" @click="handleUser('clearCache')"> <a-menu-item key="clearCache" @click="handleUser('clearCache')">
<loading3-quarters-outlined style="margin-right: 8px" /> <loading3-quarters-outlined class="xn-mr8" />
<span>清理缓存</span> <span>清理缓存</span>
</a-menu-item> </a-menu-item>
<a-menu-divider /> <a-menu-divider />
<a-menu-item key="outLogin" @click="handleUser('outLogin')"> <a-menu-item key="outLogin" @click="handleUser('outLogin')">
<export-outlined style="margin-right: 8px" /> <export-outlined class="xn-mr8" />
<span>退出登录</span> <span>退出登录</span>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
@ -48,7 +48,7 @@
</div> </div>
<!-- 整体风格设置抽屉 --> <!-- 整体风格设置抽屉 -->
<a-drawer v-model:visible="settingDialog" :closable="false" width="300"> <a-drawer v-model:open="settingDialog" :closable="false" width="300">
<setting /> <setting />
</a-drawer> </a-drawer>
</template> </template>
@ -128,6 +128,10 @@
tool.data.remove('MENU') tool.data.remove('MENU')
tool.data.remove('PERMISSIONS') tool.data.remove('PERMISSIONS')
router.replace({ path: '/login' }) router.replace({ path: '/login' })
nextTick(() => {
//
store.userInfo = undefined
})
}) })
.catch(() => { .catch(() => {
tool.data.clear() tool.data.clear()

View File

@ -0,0 +1,15 @@
/**
* Copyright [2022] [https://www.xiaonuo.vip]
* Snowy采用APACHE LICENSE 2.0开源协议您在使用过程中需要注意以下几点
* 1.请不要删除和修改根目录下的LICENSE文件
* 2.请不要删除和修改Snowy源码头部的版权声明
* 3.本项目代码可免费商业使用商业使用请保留源码和相关描述文件的项目出处作者声明等
* 4.分发源码时候请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
export const layoutEnum = {
CLASSICAL: 'classical',
DOUBLEROW: 'doublerow',
TOP: 'top'
}

View File

@ -0,0 +1,15 @@
/**
* Copyright [2022] [https://www.xiaonuo.vip]
* Snowy采用APACHE LICENSE 2.0开源协议您在使用过程中需要注意以下几点
* 1.请不要删除和修改根目录下的LICENSE文件
* 2.请不要删除和修改Snowy源码头部的版权声明
* 3.本项目代码可免费商业使用商业使用请保留源码和相关描述文件的项目出处作者声明等
* 4.分发源码时候请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
export const themeEnum = {
LIGHT: 'light',
DARK: 'dark',
REAL_DARK: 'realDark'
}

View File

@ -1,191 +1,86 @@
<template> <template>
<!-- 经典布局 --> <!-- 经典布局 -->
<a-layout v-if="layout === 'classical'"> <ClassicalMenu
<a-layout-sider v-if="layout === layoutEnum.CLASSICAL"
v-if="!isMobile" :layout="layout"
v-model:collapsed="menuIsCollapse" :isMobile="isMobile"
:trigger="null" :menuIsCollapse="menuIsCollapse"
collapsible :sideTheme="sideTheme"
:theme="sideTheme" :sysBaseConfig="sysBaseConfig"
width="210" :openKeys="openKeys"
> :selectedKeys="selectedKeys"
<header id="snowyHeaderLogo" class="snowy-header-logo"> :menu="menu"
<div class="snowy-header-left"> :breadcrumbOpen="breadcrumbOpen"
<div class="logo-bar"> :layoutTagsOpen="layoutTagsOpen"
<img class="logo" :src="sysBaseConfig.SNOWY_SYS_LOGO" /> :kStore="kStore"
<span>{{ sysBaseConfig.SNOWY_SYS_NAME }}</span> :footerCopyrightOpen="footerCopyrightOpen"
</div> :moduleMenuShow="moduleMenuShow"
</div> @onSelect="onSelect"
</header> @onOpenChange="onOpenChange"
<div :class="menuIsCollapse ? 'admin-ui-side isCollapse' : 'admin-ui-side'"> @switchModule="switchModule"
<div class="admin-ui-side-scroll"> @menuIsCollapseClick="menuIsCollapseClick"
<a-menu />
v-model:openKeys="openKeys"
v-model:selectedKeys="selectedKeys"
:theme="sideTheme"
mode="inline"
@select="onSelect"
@openChange="onOpenChange"
>
<NavMenu :nav-menus="menu" />
</a-menu>
</div>
</div>
</a-layout-sider>
<!-- 手机端情况下的左侧菜单 -->
<Side-m v-if="isMobile" />
<!-- 右侧布局 -->
<a-layout>
<div id="snowyHeader" class="snowy-header">
<div class="snowy-header-left" style="padding-left: 0px">
<div v-if="!isMobile" class="panel-item hidden-sm-and-down" @click="menuIsCollapseClick">
<MenuUnfoldOutlined v-if="menuIsCollapse" />
<MenuFoldOutlined v-else />
</div>
<moduleMenu v-if="moduleMenuShow" @switchModule="switchModule" />
<top-bar v-if="!isMobile && breadcrumbOpen" />
</div>
<div class="snowy-header-right">
<user-bar />
</div>
</div>
<!-- 多标签 -->
<Tags v-if="!isMobile && layoutTagsOpen" />
<a-layout-content class="main-content-wrapper">
<div id="admin-ui-main" class="admin-ui-main">
<router-view v-slot="{ Component }">
<keep-alive :include="kStore.keepLiveRoute">
<component :is="Component" v-if="kStore.routeShow" :key="route.name" />
</keep-alive>
</router-view>
<iframe-view />
<div class="main-bottom-wrapper">
<a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
sysBaseConfig.SNOWY_SYS_COPYRIGHT
}}</a>
</div>
</div>
</a-layout-content>
</a-layout>
</a-layout>
<!-- 双排菜单布局 --> <!-- 双排菜单布局 -->
<a-layout v-else-if="layout === 'doublerow'"> <DoubleRowMenu
<a-layout-sider v-if="!isMobile" width="80" :theme="sideTheme" :trigger="null" collapsible> v-else-if="layout === layoutEnum.DOUBLEROW"
<header id="snowyHeaderLogo" class="snowy-header-logo"> :layout="layout"
<div class="snowy-header-left"> :isMobile="isMobile"
<div class="logo-bar"> :sideTheme="sideTheme"
<router-link to="/"> :secondMenuSideTheme="secondMenuSideTheme"
<img class="logo" :title="sysBaseConfig.SNOWY_SYS_NAME" :src="sysBaseConfig.SNOWY_SYS_LOGO" /> :sysBaseConfig="sysBaseConfig"
</router-link> :openKeys="openKeys"
</div> :selectedKeys="selectedKeys"
</div> :menuIsCollapse="menuIsCollapse"
</header> :doublerowSelectedKey="doublerowSelectedKey"
<a-menu :menu="menu"
v-model:selectedKeys="doublerowSelectedKey" :nextMenu="nextMenu"
:theme="sideTheme" :breadcrumbOpen="breadcrumbOpen"
class="snowy-doublerow-layout-menu" :layoutTagsOpen="layoutTagsOpen"
v-for="item in menu" :layoutSiderDowbleMenu="layoutSiderDowbleMenu"
:key="item.path" :kStore="kStore"
> :footerCopyrightOpen="footerCopyrightOpen"
<a-menu-item :moduleMenuShow="moduleMenuShow"
:key="item.path" @onSelect="onSelect"
style=" @switchModule="switchModule"
text-align: center; @showMenu="showMenu"
border-radius: 2px; />
height: auto; <!-- 顶部菜单布局 -->
line-height: 20px; <TopMenu
flex: none; v-else-if="layout === layoutEnum.TOP"
display: block; :layout="layout"
padding: 12px 0 !important; :menuList="menuList"
" :menu="menu"
@click="showMenu(item)" :sysBaseConfig="sysBaseConfig"
v-if="!item.meta.hidden" :moduleMenuShow="moduleMenuShow"
> :openKeys="openKeys"
<a v-if="item.meta && item.meta.type === 'link'" :href="item.path" target="_blank" @click.stop="() => {}" /> :selectedKeys="selectedKeys"
<template #icon> :breadcrumbOpen="breadcrumbOpen"
<component :is="item.meta.icon" style="padding-left: 10px" /> :footerCopyrightOpen="footerCopyrightOpen"
</template> :sideTheme="sideTheme"
<div class="snowy-doublerow-layout-menu-item-fort-div"> :isMobile="isMobile"
<span class="snowy-doublerow-layout-menu-item-fort-div-span"> :kStore="kStore"
{{ item.meta.title }} :layoutTagsOpen="layoutTagsOpen"
</span> @switchModule="switchModule"
</div> @onOpenChange="onOpenChange"
</a-menu-item> @onSelect="onSelect"
</a-menu> />
</a-layout-sider>
<a-layout-sider
v-if="!isMobile"
v-show="layoutSiderDowbleMenu"
v-model:collapsed="menuIsCollapse"
:trigger="null"
width="170"
collapsible
:theme="secondMenuSideTheme"
>
<div v-if="!menuIsCollapse" id="snowyDoublerowSideTop" class="snowy-doublerow-side-top">
<h2 class="snowy-title">{{ pMenu.meta.title }}</h2>
</div>
<a-menu
v-model:collapsed="menuIsCollapse"
v-model:openKeys="openKeys"
v-model:selectedKeys="selectedKeys"
mode="inline"
:theme="secondMenuSideTheme"
@select="onSelect"
>
<NavMenu :nav-menus="nextMenu" />
</a-menu>
</a-layout-sider>
<!-- 手机端情况下的左侧菜单 -->
<Side-m v-if="isMobile" />
<a-layout>
<div id="snowyHeader" class="snowy-header">
<div class="snowy-header-left" style="padding-left: 0px">
<moduleMenu v-if="moduleMenuShow" @switchModule="switchModule" />
<top-bar v-if="!isMobile && breadcrumbOpen" />
</div>
<div class="snowy-header-right">
<user-bar />
</div>
</div>
<!-- 多标签 -->
<Tags v-if="!isMobile && layoutTagsOpen" />
<a-layout-content class="main-content-wrapper">
<div id="admin-ui-main" class="admin-ui-main">
<router-view v-slot="{ Component }">
<keep-alive :include="kStore.keepLiveRoute">
<component :is="Component" v-if="kStore.routeShow" :key="route.name" />
</keep-alive>
</router-view>
<iframe-view />
<div class="main-bottom-wrapper">
<a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
sysBaseConfig.SNOWY_SYS_COPYRIGHT
}}</a>
</div>
</div>
</a-layout-content>
</a-layout>
</a-layout>
<!-- 退出最大化 --> <!-- 退出最大化 -->
<div class="main-maximize-exit" @click="exitMaximize"> <div class="main-maximize-exit" @click="exitMaximize">
<fullscreen-exit-outlined style="color: #fff" /> <fullscreen-exit-outlined class="xn-color-fff" />
</div> </div>
</template> </template>
<script setup> <script setup>
import UserBar from '@/layout/components/userbar.vue'
import Tags from '@/layout/components/tags.vue'
import SideM from '@/layout/components/sideM.vue'
import NavMenu from '@/layout/components/NavMenu.vue'
import ModuleMenu from '@/layout/components/moduleMenu.vue'
import IframeView from '@/layout/components/iframeView.vue'
import TopBar from '@/layout/components/topbar.vue'
import { globalStore, keepAliveStore } from '@/store' import { globalStore, keepAliveStore } from '@/store'
import { ThemeModeEnum } from '@/utils/enum' import { themeEnum } from '@/layout/enum/themeEnum'
import { layoutEnum } from '@/layout/enum/layoutEnum'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import tool from '@/utils/tool' import tool from '@/utils/tool'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import ClassicalMenu from '@/layout/menu/classicalMenu.vue'
import DoubleRowMenu from '@/layout/menu/doubleRowMenu.vue'
import TopMenu from '@/layout/menu/topMenu.vue'
const store = globalStore() const store = globalStore()
const kStore = keepAliveStore() const kStore = keepAliveStore()
@ -197,10 +92,11 @@
const selectedKeys = ref([]) const selectedKeys = ref([])
const openKeys = ref([]) const openKeys = ref([])
const onSelectTag = ref(false) const onSelectTag = ref(false)
const moduleMenuData = ref([]) const moduleMenu = ref([])
const moduleMenuShow = ref(true) const moduleMenuShow = ref(true)
const doublerowSelectedKey = ref([]) const doublerowSelectedKey = ref([])
const layoutSiderDowbleMenu = ref(true) const layoutSiderDowbleMenu = ref(true)
const menuList = ref([])
// computed - start // computed - start
const layout = computed(() => { const layout = computed(() => {
return store.layout return store.layout
@ -214,6 +110,9 @@
const theme = computed(() => { const theme = computed(() => {
return store.theme return store.theme
}) })
const themeColor = computed(() => {
return store.themeColor
})
const layoutTagsOpen = computed(() => { const layoutTagsOpen = computed(() => {
// keepAlive // keepAlive
if (!store.layoutTagsOpen) { if (!store.layoutTagsOpen) {
@ -224,6 +123,9 @@
const breadcrumbOpen = computed(() => { const breadcrumbOpen = computed(() => {
return store.breadcrumbOpen return store.breadcrumbOpen
}) })
const fixedWidth = computed(() => {
return store.fixedWidth
})
const topHeaderThemeColorOpen = computed(() => { const topHeaderThemeColorOpen = computed(() => {
return store.topHeaderThemeColorOpen return store.topHeaderThemeColorOpen
}) })
@ -233,6 +135,9 @@
const sideUniqueOpen = computed(() => { const sideUniqueOpen = computed(() => {
return store.sideUniqueOpen return store.sideUniqueOpen
}) })
const footerCopyrightOpen = computed(() => {
return store.footerCopyrightOpen
})
const sysBaseConfig = computed(() => { const sysBaseConfig = computed(() => {
return store.sysBaseConfig return store.sysBaseConfig
}) })
@ -240,10 +145,13 @@
return store.module return store.module
}) })
const sideTheme = computed(() => { const sideTheme = computed(() => {
return theme.value === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : theme.value return theme.value === themeEnum.REAL_DARK ? themeEnum.DARK : theme.value
}) })
const secondMenuSideTheme = computed(() => { const secondMenuSideTheme = computed(() => {
return theme.value === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : ThemeModeEnum.LIGHT return theme.value === themeEnum.REAL_DARK ? themeEnum.DARK : themeEnum.LIGHT
})
const roundedCornerStyleOpen = computed(() => {
return store.roundedCornerStyleOpen
}) })
// //
const showThis = () => { const showThis = () => {
@ -266,14 +174,14 @@
} }
const nextTickMenu = pMenu.value.children const nextTickMenu = pMenu.value.children
if (pidKey) { if (pidKey) {
const modelPidKey = getParentKeys(moduleMenuData.value, route.path) const modelPidKey = getParentKeys(moduleMenu.value, route.path)
moduleMenuData.value.forEach((item) => { moduleMenu.value.forEach((item) => {
if (modelPidKey.includes(item.path)) { if (modelPidKey.includes(item.path)) {
tagSwitchModule(item.id) tagSwitchModule(item.id)
} }
}) })
const parentPath = pidKey[pidKey.length - 1] const parentPath = pidKey[pidKey.length - 1]
if (layout.value === 'doublerow') { if (layout.value === layoutEnum.DOUBLEROW) {
// //
const nextMenuTemp = nextTickMenu.filter((item) => item.path === parentPath)[0].children const nextMenuTemp = nextTickMenu.filter((item) => item.path === parentPath)[0].children
if (nextMenuTemp) { if (nextMenuTemp) {
@ -285,14 +193,14 @@
openKeys.value = pidKey openKeys.value = pidKey
} }
// //
if (layout.value === 'doublerow') { if (layout.value === layoutEnum.DOUBLEROW) {
setDoubleRowSelectedKey() setDoubleRowSelectedKey()
} }
}) })
} }
// -start // -start
moduleMenuData.value = router.getMenu() moduleMenu.value = router.getMenu()
// //
const menuModuleId = tool.data.get('SNOWY_MENU_MODULE_ID') const menuModuleId = tool.data.get('SNOWY_MENU_MODULE_ID')
if (menuModuleId) { if (menuModuleId) {
@ -307,13 +215,86 @@
menu.value = router.getMenu()[0].children menu.value = router.getMenu()[0].children
} }
showThis() showThis()
onMounted(() => { onMounted(() => {
onLayoutResize() onLayoutResize()
window.addEventListener('resize', onLayoutResize) window.addEventListener('resize', onLayoutResize)
window.addEventListener('resize', getNav)
switchoverTopHeaderThemeColor() switchoverTopHeaderThemeColor()
settingTopHeaderThemeOrColor(theme.value, layout.value)
settingFixedWidth()
nextTick(() => {
getNav(menu.value)
})
}) })
watch(route, (newValue) => { //
const getNav = (items) => {
const item = menu.value
//
if (layout.value !== 'top') return
const menuNavList = menu.value
menuList.value = menuNavList
nextTick(() => {
//
let liArr = document.querySelector('#topHeaderMenu').querySelectorAll('li')
let allWidth = document.querySelector('#xn-line-nav').offsetWidth //
//
let num = 0
let startIndex = 0
for (const [index, item] of liArr.entries()) {
num += item.offsetWidth
if (num > allWidth) {
startIndex = index - 1
break
}
}
//
if (num < allWidth) {
menuList.value = menuNavList
return
}
//
const showNav = menuNavList.slice(0, startIndex)
const hiddenNav = menuNavList.slice(startIndex, menuNavList.length)
menuList.value = showNav
menuList.value.push({
meta: {
icon: 'rightCircle-outlined',
title: '更多',
type: 'catalog'
},
children: hiddenNav
})
})
}
//
const handleMouseWheel = (event) => {
let element = document.querySelector('#xn-line-nav')
let element2 = document.querySelector('#topHeaderMenu')
//
let delta = event.deltaY
//
const num = 20
//
let leftMove = Number(element2.style.left.slice(0, -2))
//
let remove = element.offsetWidth - element2.scrollWidth
//
//
if (delta < 0 && leftMove > remove) {
element2.style.left = leftMove - num + 'px'
} else if (delta > 0 && leftMove < 0) {
//
// 0
element2.style.left = leftMove + num + 'px'
}
}
watch(route, () => {
// //
selectedKeys.value = [] selectedKeys.value = []
showThis() showThis()
@ -321,50 +302,128 @@
// //
watch(layout, (newValue) => { watch(layout, (newValue) => {
document.body.setAttribute('data-layout', newValue) document.body.setAttribute('data-layout', newValue)
if (newValue.includes('doublerow')) { if (newValue.includes(layoutEnum.DOUBLEROW)) {
showThis() showThis()
setDoubleRowSelectedKey() setDoubleRowSelectedKey()
} }
nextTick(() => { nextTick(() => {
// //
switchoverTopHeaderThemeColor() switchoverTopHeaderThemeColor()
// top
settingTopHeaderThemeOrColor(theme.value, newValue)
getNav(menu.value)
settingFixedWidth()
let element = document.querySelector('#xn-line-nav')
if (element) {
element.addEventListener('mousewheel', handleMouseWheel, false)
}
}) })
}) })
watch(topHeaderThemeColorOpen, () => {
switchoverTopHeaderThemeColor()
})
watch(fixedWidth, () => {
settingFixedWidth()
})
watch(layoutTagsOpen, () => {
settingFixedWidth()
})
watch(breadcrumbOpen, () => {
settingFixedWidth()
})
watch(topHeaderThemeColorSpread, () => {
switchoverTopHeaderThemeColor()
})
watch(theme, (newValue) => {
settingTopHeaderThemeOrColor(newValue, layout.value)
})
watch(themeColor, () => {
settingTopHeaderThemeOrColor(theme.value, layout.value)
})
watch(topHeaderThemeColorOpen, (newValue) => { watch(topHeaderThemeColorOpen, (newValue) => {
switchoverTopHeaderThemeColor() const header = document.getElementById('snowyHeader')
const topHeaderMenu = document.getElementById('topHeaderMenu')
if (layout.value === layoutEnum.TOP) {
if (newValue) {
header.classList.add('top-snowy-header-layout')
topHeaderMenu.classList.add('top-snowy-header-layout')
} else {
header.classList.remove('top-snowy-header-layout')
topHeaderMenu.classList.remove('top-snowy-header-layout')
}
}
}) })
watch(topHeaderThemeColorSpread, (newValue) => { watch(roundedCornerStyleOpen, () => {
switchoverTopHeaderThemeColor() settingTopHeaderThemeOrColor(theme.value, layout.value)
}) })
//
const settingFixedWidth = () => {
nextTick(() => {
const breadcrumbWidth = document.querySelector('.admin-ui-breadcrumb')
const showWidth = document.querySelector('.snowy-tags')
const mainWidth = document.querySelector('.ant-layout-content')
if (fixedWidth.value && layout.value === layoutEnum.TOP) {
breadcrumbWidth?.classList.add('xn-mg050')
showWidth?.classList.add('xn-mg050')
mainWidth?.classList.add('xn-pd1180')
} else {
breadcrumbWidth?.classList.remove('xn-mg050')
showWidth?.classList.remove('xn-mg050')
mainWidth?.classList.remove('xn-pd1180')
}
})
}
//
const settingTopHeaderThemeOrColor = (theme, layout) => {
const header = document.getElementById('snowyHeader')
const topHeaderMenu = document.getElementById('topHeaderMenu')
if (topHeaderThemeColorOpen.value && layout === layoutEnum.TOP) {
nextTick(() => {
topHeaderMenu.classList.add('top-snowy-header-layout')
header.classList.add('top-snowy-header-layout')
})
} else if (!topHeaderThemeColorOpen.value && layout === layoutEnum.TOP) {
nextTick(() => {
topHeaderMenu.classList.remove('top-snowy-header-layout')
header.classList.remove('top-snowy-header-layout')
})
}
if (theme === themeEnum.LIGHT && layout === layoutEnum.TOP) {
header.classList.remove('top-snowy-header')
header.classList.add('top-snowy-header-light')
} else {
header.classList.remove('top-snowy-header-light')
if (layout === layoutEnum.TOP) {
header.classList.add('top-snowy-header')
} else {
if (theme === themeEnum.REAL_DARK) {
header.classList.add('top-snowy-header')
} else {
header.classList.remove('top-snowy-header')
}
}
}
}
const menuIsCollapseClick = () => { const menuIsCollapseClick = () => {
store.toggleConfig('menuIsCollapse') store.toggleConfig('menuIsCollapse')
} }
// //
const switchoverTopHeaderThemeColor = () => { const switchoverTopHeaderThemeColor = () => {
//
const header = document.getElementById('snowyHeader')
topHeaderThemeColorOpen.value
? header.classList.add('snowy-header-primary-color')
: header.classList.remove('snowy-header-primary-color')
//
const headerLogin = document.getElementById('snowyHeaderLogo')
try { try {
//
const header = document.getElementById('snowyHeader')
topHeaderThemeColorOpen.value
? header.classList.add('snowy-header-primary-color')
: header.classList.remove('snowy-header-primary-color')
//
const headerLogin = document.getElementById('snowyHeaderLogo')
topHeaderThemeColorSpread.value topHeaderThemeColorSpread.value
? headerLogin.classList.add('snowy-header-logo-primary-color') ? headerLogin.classList.add('snowy-header-logo-primary-color')
: headerLogin.classList.remove('snowy-header-logo-primary-color') : headerLogin.classList.remove('snowy-header-logo-primary-color')
// eslint-disable-next-line no-empty // eslint-disable-next-line no-empty
} catch (e) {} } catch (e) {}
//
if (layout.value === 'doublerow') {
const snowyDoublerowSideTop = document.getElementById('snowyDoublerowSideTop')
try {
topHeaderThemeColorSpread.value
? snowyDoublerowSideTop.classList.add('snowy-doublerow-side-top-primary-color')
: snowyDoublerowSideTop.classList.remove('snowy-doublerow-side-top-primary-color')
// eslint-disable-next-line no-empty
} catch (e) {}
}
} }
// //
@ -447,7 +506,7 @@
layoutSiderDowbleMenu.value = false layoutSiderDowbleMenu.value = false
} }
} }
if (layout.value === 'doublerow') { if (layout.value === layoutEnum.DOUBLEROW) {
doublerowSelectedKey.value = [route.path] doublerowSelectedKey.value = [route.path]
} }
} }
@ -466,9 +525,9 @@
} }
// //
const switchModule = (id) => { const switchModule = (id) => {
if (moduleMenuData.value.length > 0) { if (moduleMenu.value.length > 0) {
showThis() showThis()
const menus = moduleMenuData.value.filter((item) => item.id === id)[0].children const menus = moduleMenu.value.filter((item) => item.id === id)[0].children
if (menus.length > 0) { if (menus.length > 0) {
// //
menu.value = menus menu.value = menus
@ -487,6 +546,7 @@
message.warning('该模块下无任何菜单') message.warning('该模块下无任何菜单')
} }
} }
getNav(menu.value)
} }
// //
const tagSwitchModule = (id) => { const tagSwitchModule = (id) => {
@ -494,7 +554,7 @@
tool.data.set('SNOWY_MENU_MODULE_ID', id) tool.data.set('SNOWY_MENU_MODULE_ID', id)
store.setModule(id) store.setModule(id)
// //
menu.value = moduleMenuData.value.filter((item) => item.id === id)[0].children menu.value = moduleMenu.value.filter((item) => item.id === id)[0].children
} }
// //
const traverseChild = (menu) => { const traverseChild = (menu) => {
@ -519,3 +579,46 @@
}) })
} }
</script> </script>
<style lang="less" scoped>
.xn-color-fff {
color: #fff;
}
.xn-pdl25 {
padding-left: 11px;
}
.xn-menu-line {
text-align: center;
height: auto;
line-height: 20px;
flex: none;
display: block;
padding: 12px 0 !important;
}
.xn-navmenu-line {
min-width: 0;
flex: 1 1 0%;
// padding: 0 20px;
overflow: hidden;
}
.xn-bb0 {
border-bottom: none;
position: relative;
}
.ant-layout-content {
display: flex;
flex-direction: column;
}
.xn-pd1180 {
padding: 10px 150px 0 150px;
}
.xn-pd050 {
padding: 0 50px;
}
.xn-pl10 {
padding-left: 10px;
}
.xn-mg050 {
margin: 0px 150px;
}
</style>

View File

@ -0,0 +1,154 @@
<template>
<a-layout>
<a-layout-sider
v-if="!isMobile"
:collapsed="menuIsCollapse"
:trigger="null"
collapsible
:theme="sideTheme"
width="210"
>
<header id="snowyHeaderLogo" class="snowy-header-logo">
<div class="snowy-header-left">
<div class="logo-bar">
<img class="logo" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
<span>{{ sysBaseConfig.SNOWY_SYS_NAME }}</span>
</div>
</div>
</header>
<div :class="menuIsCollapse ? 'admin-ui-side isCollapse' : 'admin-ui-side'">
<div class="admin-ui-side-scroll">
<a-menu
v-bind:openKeys="openKeys"
v-bind:selectedKeys="selectedKeys"
:theme="sideTheme"
mode="inline"
@select="onSelect"
@openChange="onOpenChange"
>
<NavMenu :nav-menus="menu" />
</a-menu>
</div>
</div>
</a-layout-sider>
<!-- 手机端情况下的左侧菜单 -->
<Side-m v-if="isMobile" />
<!-- 右侧布局 -->
<a-layout>
<div id="snowyHeader" class="snowy-header">
<div class="snowy-header-left xn-pl0">
<div v-if="!isMobile" class="panel-item hidden-sm-and-down" @click="menuIsCollapseClick">
<MenuUnfoldOutlined v-if="menuIsCollapse" />
<MenuFoldOutlined v-else />
</div>
<moduleMenu v-if="moduleMenuShow" @switchModule="switchModule" />
</div>
<div class="snowy-header-right">
<user-bar />
</div>
</div>
<Breadcrumb v-if="!isMobile && breadcrumbOpen" />
<!-- 多标签 -->
<Tags v-if="!isMobile && layoutTagsOpen" />
<a-layout-content class="main-content-wrapper">
<div id="admin-ui-main" class="admin-ui-main">
<router-view v-slot="{ Component }">
<keep-alive :include="kStore.keepLiveRoute">
<component :is="Component" v-if="kStore.routeShow" :key="route.name" />
</keep-alive>
</router-view>
<iframe-view />
<div v-if="footerCopyrightOpen" class="main-bottom-wrapper">
<a class="xn-color-a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
sysBaseConfig.SNOWY_SYS_COPYRIGHT
}}</a>
</div>
</div>
</a-layout-content>
</a-layout>
</a-layout>
</template>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
import UserBar from '@/layout/components/userbar.vue'
import Tags from '@/layout/components/tags.vue'
import SideM from '@/layout/components/sideM.vue'
import NavMenu from '@/layout/components/NavMenu.vue'
import ModuleMenu from '@/layout/components/moduleMenu.vue'
import IframeView from '@/layout/components/iframeView.vue'
import Breadcrumb from '@/layout/components/breadcrumb.vue'
const props = defineProps({
layout: { type: String }, //
isMobile: { type: Boolean }, //
menuIsCollapse: { type: Boolean }, //
sideTheme: { type: String },
sysBaseConfig: { type: Object },
openKeys: { type: Array },
selectedKeys: { type: Array },
menu: { type: Array }, //
breadcrumbOpen: { type: Boolean }, //
layoutTagsOpen: { type: Boolean },
kStore: { type: Object }, //
footerCopyrightOpen: { type: Boolean }, //
moduleMenuShow: { type: Boolean }
})
const emit = defineEmits(['onSelect', 'onOpenChange', 'switchModule', 'menuIsCollapseClick'])
const onSelect = (obj) => {
emit('onSelect', obj)
}
const onOpenChange = (keys) => {
emit('onOpenChange', keys)
}
const switchModule = (id) => {
emit('switchModule', id)
}
const menuIsCollapseClick = () => {
emit('menuIsCollapseClick')
}
</script>
<style lang="less" scoped>
.xn-color-fff {
color: #fff;
}
.xn-pdl25 {
padding-left: 11px;
}
.xn-menu-line {
text-align: center;
height: auto;
line-height: 20px;
flex: none;
display: block;
padding: 12px 0 !important;
}
.xn-navmenu-line {
min-width: 0;
flex: 1 1 0%;
overflow: hidden;
}
.xn-bb0 {
border-bottom: none;
position: relative;
}
.ant-layout-content {
display: flex;
flex-direction: column;
}
.xn-pd1180 {
padding: 10px 150px 0 150px;
}
.xn-pd050 {
padding: 0 50px;
}
.xn-pl10 {
padding-left: 10px;
}
.xn-mg050 {
margin: 0px 150px;
}
</style>

View File

@ -0,0 +1,185 @@
<template>
<a-layout>
<a-layout-sider v-if="!isMobile" width="80" :theme="sideTheme" :trigger="null" collapsible>
<header id="snowyHeaderLogo" class="snowy-header-logo">
<div class="snowy-header-left">
<div class="logo-bar">
<router-link to="/">
<img class="logo" :title="sysBaseConfig.SNOWY_SYS_NAME" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
</router-link>
</div>
</div>
</header>
<a-menu
:selectedKeys="doublerowSelectedKey"
:theme="sideTheme"
class="snowy-doublerow-layout-menu"
v-for="item in menu"
:key="item.path"
>
<a-menu-item
:key="item.path"
style="
text-align: center;
height: auto;
line-height: 20px;
flex: none;
display: block;
padding: 12px 0 !important;
"
@click="showMenu(item)"
v-if="!item.meta.hidden"
>
<a v-if="item.meta && item.meta.type === 'link'" :href="item.path" target="_blank" @click.stop="() => {}" />
<template #icon>
<component :is="item.meta.icon" class="xn-pl10" />
</template>
<div class="snowy-doublerow-layout-menu-item-fort-div">
<span class="snowy-doublerow-layout-menu-item-fort-div-span">
{{ item.meta.title }}
</span>
</div>
</a-menu-item>
</a-menu>
</a-layout-sider>
<!-- 手机端情况下的左侧菜单 -->
<Side-m v-if="isMobile" />
<a-layout>
<div id="snowyHeader" class="snowy-header">
<div class="snowy-header-left xn-pl0">
<moduleMenu v-if="moduleMenuShow" @switchModule="switchModule" />
</div>
<div class="snowy-header-right">
<user-bar />
</div>
</div>
<a-layout>
<a-layout-sider
v-if="!isMobile"
v-show="layoutSiderDowbleMenu"
:collapsed="menuIsCollapse"
:trigger="null"
width="170"
collapsible
:theme="secondMenuSideTheme"
>
<a-menu
:collapsed="menuIsCollapse"
:openKeys="openKeys"
:selectedKeys="selectedKeys"
mode="inline"
:theme="secondMenuSideTheme"
@select="onSelect"
>
<NavMenu :nav-menus="nextMenu" />
</a-menu>
</a-layout-sider>
<a-layout-content>
<breadcrumb v-if="!isMobile && breadcrumbOpen" />
<!-- 多标签 -->
<Tags v-if="!isMobile && layoutTagsOpen" />
<div class="main-content-wrapper">
<div id="admin-ui-main" class="admin-ui-main">
<router-view v-slot="{ Component }">
<keep-alive :include="kStore.keepLiveRoute">
<component :is="Component" v-if="kStore.routeShow" :key="route.name" />
</keep-alive>
</router-view>
<iframe-view />
<div v-if="footerCopyrightOpen" class="main-bottom-wrapper">
<a class="xn-color-a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
sysBaseConfig.SNOWY_SYS_COPYRIGHT
}}</a>
</div>
</div>
</div>
</a-layout-content>
</a-layout>
</a-layout>
</a-layout>
</template>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
import UserBar from '@/layout/components/userbar.vue'
import Tags from '@/layout/components/tags.vue'
import SideM from '@/layout/components/sideM.vue'
import NavMenu from '@/layout/components/NavMenu.vue'
import ModuleMenu from '@/layout/components/moduleMenu.vue'
import IframeView from '@/layout/components/iframeView.vue'
import Breadcrumb from '@/layout/components/breadcrumb.vue'
const props = defineProps({
layout: { type: String }, //
isMobile: { type: Boolean }, //
sideTheme: { type: String },
menuIsCollapse: {},
sysBaseConfig: { type: Object },
openKeys: { type: Array },
selectedKeys: { type: Array },
doublerowSelectedKey: { type: Array },
nextMenu: { type: Array },
menu: { type: Array }, //
breadcrumbOpen: { type: Boolean }, //
layoutTagsOpen: { type: Boolean },
layoutSiderDowbleMenu: { type: Boolean },
kStore: { type: Object }, //
footerCopyrightOpen: { type: Boolean }, //
moduleMenuShow: { type: Boolean },
secondMenuSideTheme: {}
})
const emit = defineEmits(['onSelect', 'switchModule', 'showMenu'])
const onSelect = (obj) => {
emit('onSelect', obj)
}
const switchModule = (id) => {
emit('switchModule', id)
}
const showMenu = (route) => {
emit('showMenu', route)
}
</script>
<style lang="less" scoped>
.xn-color-fff {
color: #fff;
}
.xn-pdl25 {
padding-left: 11px;
}
.xn-menu-line {
text-align: center;
height: auto;
line-height: 20px;
flex: none;
display: block;
padding: 12px 0 !important;
}
.xn-navmenu-line {
min-width: 0;
flex: 1 1 0%;
overflow: hidden;
}
.xn-bb0 {
border-bottom: none;
position: relative;
}
.ant-layout-content {
display: flex;
flex-direction: column;
}
.xn-pd1180 {
padding: 10px 150px 0 150px;
}
.xn-pd050 {
padding: 0 50px;
}
.xn-pl10 {
padding-left: 10px;
}
.xn-mg050 {
margin: 0px 150px;
}
</style>

View File

@ -0,0 +1,138 @@
<template>
<a-layout>
<a-layout class="layout">
<div id="snowyHeader" class="snowy-header top-snowy-header xn-pd050">
<div class="snowy-header-left xn-pl0">
<header id="snowyHeaderLogo" class="snowy-header-logo">
<div class="snowy-header-left">
<div class="logo-bar">
<img class="logo" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
<span>{{ sysBaseConfig.SNOWY_SYS_NAME }}</span>
</div>
</div>
</header>
</div>
<moduleMenu v-if="moduleMenuShow" @switchModule="switchModule" class="xn-pdl25" />
<div class="xn-navmenu-line" id="xn-line-nav">
<a-menu
class="xn-bb0"
id="topHeaderMenu"
:selectedKeys="selectedKeys"
:theme="sideTheme"
mode="horizontal"
@select="onSelect"
@openChange="onOpenChange"
collapsed="true"
>
<NavMenu :nav-menus="menuList" />
</a-menu>
</div>
<div class="snowy-header-right">
<user-bar />
</div>
</div>
<!-- 手机端情况下的左侧菜单 -->
<Side-m v-if="isMobile" />
<breadcrumb v-if="!isMobile && breadcrumbOpen" />
<!-- 多标签 -->
<Tags v-if="!isMobile && layoutTagsOpen" />
<a-layout-content class="main-content-wrapper">
<div id="admin-ui-main" class="admin-ui-main">
<router-view v-slot="{ Component }">
<keep-alive :include="kStore.keepLiveRoute">
<component :is="Component" v-if="kStore.routeShow" :key="route.name" />
</keep-alive>
</router-view>
<iframe-view />
<div v-if="footerCopyrightOpen" class="main-bottom-wrapper">
<a class="xn-color-a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
sysBaseConfig.SNOWY_SYS_COPYRIGHT
}}</a>
</div>
</div>
</a-layout-content>
</a-layout>
</a-layout>
</template>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
import UserBar from '@/layout/components/userbar.vue'
import Tags from '@/layout/components/tags.vue'
import SideM from '@/layout/components/sideM.vue'
import NavMenu from '@/layout/components/NavMenu.vue'
import ModuleMenu from '@/layout/components/moduleMenu.vue'
import IframeView from '@/layout/components/iframeView.vue'
import Breadcrumb from '@/layout/components/breadcrumb.vue'
const props = defineProps({
layout: {},
menu: { type: Array }, //
menuList: { type: Array }, //
sysBaseConfig: { type: Object },
moduleMenuShow: { type: Boolean },
selectedKeys: { type: Array },
openKeys: { type: Array },
sideTheme: { type: String },
isMobile: { type: Boolean }, //
breadcrumbOpen: { type: Boolean }, //
layoutTagsOpen: { type: Boolean },
layoutSiderDowbleMenu: { type: Boolean },
kStore: { type: Object }, //
footerCopyrightOpen: { type: Boolean } //
})
const emit = defineEmits(['onSelect', 'switchModule', 'onOpenChange'])
const onSelect = (obj) => {
emit('onSelect', obj)
}
const switchModule = (id) => {
emit('switchModule', id)
}
const onOpenChange = (keys) => {
emit('onOpenChange', keys)
}
</script>
<style lang="less" scoped>
.xn-color-fff {
color: #fff;
}
.xn-pdl25 {
padding-left: 11px;
}
.xn-menu-line {
text-align: center;
height: auto;
line-height: 20px;
flex: none;
display: block;
padding: 12px 0 !important;
}
.xn-navmenu-line {
min-width: 0;
flex: 1 1 0%;
overflow: hidden;
}
.xn-bb0 {
border-bottom: none;
position: relative;
}
.ant-layout-content {
display: flex;
flex-direction: column;
}
.xn-pd1180 {
padding: 10px 150px 0 150px;
}
.xn-pd050 {
padding: 0 50px;
}
.xn-pl10 {
padding-left: 10px;
}
.xn-mg050 {
margin: 0px 150px;
}
</style>

View File

@ -27,20 +27,12 @@ const getCacheConfig = (value) => {
return data return data
} }
/** // deprecated 请使用 useGlobalStore
* deprecated 请使用 useGlobalStore
*/
export const globalStore = defineStore('global', () => { export const globalStore = defineStore('global', () => {
// 利用Vue3组合式APIref()定义state的属性
// function() 定义actions
// computed 定义getters
// 定义state
// 移动端布局 // 移动端布局
const isMobile = ref(false) const isMobile = ref(false)
// 布局 // 布局
const layout = ref(getCacheConfig('SNOWY_LAYOUT')) const layout = ref(getCacheConfig('SNOWY_LAYOUT'))
// 菜单是否折叠 toggle // 菜单是否折叠 toggle
const menuIsCollapse = ref(getCacheConfig('SNOWY_MENU_COLLAPSE')) const menuIsCollapse = ref(getCacheConfig('SNOWY_MENU_COLLAPSE'))
// 侧边菜单是否排他展开 // 侧边菜单是否排他展开
@ -49,17 +41,24 @@ export const globalStore = defineStore('global', () => {
const layoutTagsOpen = ref(getCacheConfig('SNOWY_LAYOUT_TAGS_OPEN')) const layoutTagsOpen = ref(getCacheConfig('SNOWY_LAYOUT_TAGS_OPEN'))
// 是否展示面包屑 // 是否展示面包屑
const breadcrumbOpen = ref(getCacheConfig('SNOWY_BREADCRUMD_OPEN')) const breadcrumbOpen = ref(getCacheConfig('SNOWY_BREADCRUMD_OPEN'))
// 是否开启固定宽度(顶栏菜单)
const fixedWidth = ref(getCacheConfig('SNOWY_FIXEDWIDTH_OPEN'))
// 顶栏是否应用主题色 // 顶栏是否应用主题色
const topHeaderThemeColorOpen = ref(getCacheConfig('SNOWY_TOP_HEADER_THEME_COLOR_OPEN')) const topHeaderThemeColorOpen = ref(getCacheConfig('SNOWY_TOP_HEADER_THEME_COLOR_OPEN'))
// 顶栏主题色通栏 // 顶栏主题色通栏
const topHeaderThemeColorSpread = ref(getCacheConfig('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD')) const topHeaderThemeColorSpread = ref(getCacheConfig('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD'))
// 登录用户水印
const loginUserWatermarkOpen = ref(getCacheConfig('SNOWY_LOGIN_USER_WATERMARK_OPEN'))
// 页脚版权信息
const footerCopyrightOpen = ref(getCacheConfig('SNOWY_FOOTER_COPYRIGHT_OPEN'))
// 模块坞 // 模块坞
const moduleUnfoldOpen = ref(getCacheConfig('SNOWY_MODULE_UNFOLD_OPEN')) const moduleUnfoldOpen = ref(getCacheConfig('SNOWY_MODULE_UNFOLD_OPEN'))
// 主题 // 主题
const theme = ref(getCacheConfig('SNOWY_THEME')) const theme = ref(getCacheConfig('SNOWY_THEME'))
// 主题颜色 // 主题颜色
const themeColor = ref(toolDataGet('SNOWY_THEME_COLOR') || config.COLOR) const themeColor = ref(toolDataGet('SNOWY_THEME_COLOR') || config.COLOR)
// 圆角分格
const roundedCornerStyleOpen = ref(getCacheConfig('SNOWY_ROUNDED_CORNER_STYLE_OPEN'))
// 整体表单风格 // 整体表单风格
const formStyle = ref(getCacheConfig('SNOWY_FORM_STYLE')) const formStyle = ref(getCacheConfig('SNOWY_FORM_STYLE'))
// 用户信息 // 用户信息
@ -107,12 +106,24 @@ export const globalStore = defineStore('global', () => {
case 'breadcrumbOpen': case 'breadcrumbOpen':
breadcrumbOpen.value = !breadcrumbOpen.value breadcrumbOpen.value = !breadcrumbOpen.value
break break
case 'fixedWidth':
fixedWidth.value = !fixedWidth.value
break
case 'topHeaderThemeColorOpen': case 'topHeaderThemeColorOpen':
topHeaderThemeColorOpen.value = !topHeaderThemeColorOpen.value topHeaderThemeColorOpen.value = !topHeaderThemeColorOpen.value
topHeaderThemeColorSpread.value = topHeaderThemeColorOpen.value topHeaderThemeColorSpread.value = topHeaderThemeColorOpen.value
? topHeaderThemeColorSpread.value ? topHeaderThemeColorSpread.value
: topHeaderThemeColorOpen.value : topHeaderThemeColorOpen.value
break break
case 'loginUserWatermarkOpen':
loginUserWatermarkOpen.value = !loginUserWatermarkOpen.value
break
case 'footerCopyrightOpen':
footerCopyrightOpen.value = !footerCopyrightOpen.value
break
case 'roundedCornerStyleOpen':
roundedCornerStyleOpen.value = !roundedCornerStyleOpen.value
break
case 'moduleUnfoldOpen': case 'moduleUnfoldOpen':
moduleUnfoldOpen.value = !moduleUnfoldOpen.value moduleUnfoldOpen.value = !moduleUnfoldOpen.value
break break
@ -137,11 +148,15 @@ export const globalStore = defineStore('global', () => {
sideUniqueOpen, sideUniqueOpen,
layoutTagsOpen, layoutTagsOpen,
breadcrumbOpen, breadcrumbOpen,
fixedWidth,
topHeaderThemeColorOpen, topHeaderThemeColorOpen,
topHeaderThemeColorSpread, topHeaderThemeColorSpread,
loginUserWatermarkOpen,
footerCopyrightOpen,
moduleUnfoldOpen, moduleUnfoldOpen,
theme, theme,
themeColor, themeColor,
roundedCornerStyleOpen,
formStyle, formStyle,
userInfo, userInfo,
sysBaseConfig, sysBaseConfig,

View File

@ -1,398 +1,399 @@
@import 'ant-design-vue/es/style/themes/default.less';
:root { :root {
--blue-1: #e6f7ff; --blue-1: #e6f7ff;
--blue-2: #bae7ff; --blue-2: #bae7ff;
--blue-3: #91d5ff; --blue-3: #91d5ff;
--blue-4: #69c0ff; --blue-4: #69c0ff;
--blue-5: #40a9ff; --blue-5: #40a9ff;
--blue-6: #1890ff; --blue-6: #1677FF;
--blue-7: #096dd9; --blue-7: #096dd9;
--blue-8: #0050b3; --blue-8: #0050b3;
--blue-9: #003a8c; --blue-9: #003a8c;
--blue-10: #002766; --blue-10: #002766;
--green-1: #f6ffed; --green-1: #f6ffed;
--green-2: #d9f7be; --green-2: #d9f7be;
--green-3: #b7eb8f; --green-3: #b7eb8f;
--green-4: #95de64; --green-4: #95de64;
--green-5: #73d13d; --green-5: #73d13d;
--green-6: #52c41a; --green-6: #52c41a;
--green-7: #389e0d; --green-7: #389e0d;
--green-8: #237804; --green-8: #237804;
--green-9: #135200; --green-9: #135200;
--green-10: #092b00; --green-10: #092b00;
--red-1: #fff1f0; --red-1: #fff1f0;
--red-2: #ffccc7; --red-2: #ffccc7;
--red-3: #ffa39e; --red-3: #ffa39e;
--red-4: #ff7875; --red-4: #ff7875;
--red-5: #ff4d4f; --red-5: #ff4d4f;
--red-6: #f5222d; --red-6: #f5222d;
--red-7: #cf1322; --red-7: #cf1322;
--red-8: #a8071a; --red-8: #a8071a;
--red-9: #820014; --red-9: #820014;
--red-10: #5c0011; --red-10: #5c0011;
--gold-1: #fffbe6; --gold-1: #fffbe6;
--gold-2: #fff1b8; --gold-2: #fff1b8;
--gold-3: #ffe58f; --gold-3: #ffe58f;
--gold-4: #ffd666; --gold-4: #ffd666;
--gold-5: #ffc53d; --gold-5: #ffc53d;
--gold-6: #faad14; --gold-6: #faad14;
--gold-7: #d48806; --gold-7: #d48806;
--gold-8: #ad6800; --gold-8: #ad6800;
--gold-9: #874d00; --gold-9: #874d00;
--gold-10: #613400; --gold-10: #613400;
--purple-1: #f9f0ff; --purple-1: #f9f0ff;
--purple-2: #efdbff; --purple-2: #efdbff;
--purple-3: #d3adf7; --purple-3: #d3adf7;
--purple-4: #b37feb; --purple-4: #b37feb;
--purple-5: #9254de; --purple-5: #9254de;
--purple-6: #722ed1; --purple-6: #722ed1;
--purple-7: #531dab; --purple-7: #531dab;
--purple-8: #391085; --purple-8: #391085;
--purple-9: #22075e; --purple-9: #22075e;
--purple-10: #120338; --purple-10: #120338;
--cyan-1: #e6fffb; --cyan-1: #e6fffb;
--cyan-2: #b5f5ec; --cyan-2: #b5f5ec;
--cyan-3: #87e8de; --cyan-3: #87e8de;
--cyan-4: #5cdbd3; --cyan-4: #5cdbd3;
--cyan-5: #36cfc9; --cyan-5: #36cfc9;
--cyan-6: #13c2c2; --cyan-6: #13c2c2;
--cyan-7: #08979c; --cyan-7: #08979c;
--cyan-8: #006d75; --cyan-8: #006d75;
--cyan-9: #00474f; --cyan-9: #00474f;
--cyan-10: #002329; --cyan-10: #002329;
--pink-1: #fff0f6; --pink-1: #fff0f6;
--pink-2: #ffd6e7; --pink-2: #ffd6e7;
--pink-3: #ffadd2; --pink-3: #ffadd2;
--pink-4: #ff85c0; --pink-4: #ff85c0;
--pink-5: #f759ab; --pink-5: #f759ab;
--pink-6: #eb2f96; --pink-6: #eb2f96;
--pink-7: #c41d7f; --pink-7: #c41d7f;
--pink-8: #9e1068; --pink-8: #9e1068;
--pink-9: #780650; --pink-9: #780650;
--pink-10: #520339; --pink-10: #520339;
--orange-1: #fff7e6; --orange-1: #fff7e6;
--orange-2: #ffe7ba; --orange-2: #ffe7ba;
--orange-3: #ffd591; --orange-3: #ffd591;
--orange-4: #ffc069; --orange-4: #ffc069;
--orange-5: #ffa940; --orange-5: #ffa940;
--orange-6: #fa8c16; --orange-6: #fa8c16;
--orange-7: #d46b08; --orange-7: #d46b08;
--orange-8: #ad4e00; --orange-8: #ad4e00;
--orange-9: #873800; --orange-9: #873800;
--orange-10: #612500; --orange-10: #612500;
--primary-1: var(--blue-1); --primary-radius: #fff;
--primary-2: var(--blue-2); --primary-1: var(--blue-1);
--primary-3: var(--blue-3); --primary-2: var(--blue-2);
--primary-4: var(--blue-4); --primary-3: var(--blue-3);
--primary-5: var(--blue-5); --primary-4: var(--blue-4);
--primary-6: var(--blue-6); --primary-5: var(--blue-5);
--primary-7: var(--blue-7); --primary-6: var(--blue-6);
--primary-8: var(--blue-8); --primary-7: var(--blue-7);
--primary-9: var(--blue-9); --primary-8: var(--blue-8);
--primary-10: var(--blue-10); --primary-9: var(--blue-9);
--primary-10: var(--blue-10);
--primary-color: var(--primary-6);
--primary-color-hover: var(--primary-5); --primary-color: var(--primary-6);
--primary-color-active: var(--primary-7); --primary-color-hover: var(--primary-5);
--primary-color-outline: var(--primary-2); --primary-color-active: var(--primary-7);
--primary-color-outline: var(--primary-2);
--info-color: var(--primary-color);
--success-color: var(--green-6); --info-color: var(--primary-color);
--processing-color: var(--blue-6); --success-color: var(--green-6);
--highlight-color: var(--red-5); --processing-color: var(--blue-6);
--highlight-color: var(--red-5);
--warning-color: var(--gold-6);
--warning-color-hover: var(--gold-5); --warning-color: var(--gold-6);
--warning-color-active: var(--gold-7); --warning-color-hover: var(--gold-5);
--warning-color-outline: var(--gold-2); --warning-color-active: var(--gold-7);
--warning-color-outline: var(--gold-2);
--error-color: var(--red-5);
--error-color-hover: var(--red-4); --error-color: var(--red-5);
--error-color-active: var(--red-7); --error-color-hover: var(--red-4);
--error-color-outline: var(--red-2); --error-color-active: var(--red-7);
--error-color-outline: var(--red-2);
--body-background: #fff;
--component-background: #fff; --body-background: #fff;
--component-background: #fff;
--popover-background: @component-background;
--popover-customize-border-color: @border-color-split; --popover-background: @component-background;
--popover-customize-border-color: @border-color-split;
--text-color: fade(@black, 85%);
--text-color-secondary: fade(@black, 45%); --text-color: fade(@black, 85%);
--text-color-inverse: @white; --text-color-secondary: fade(@black, 45%);
--icon-color-hover: fade(@black, 75%); --text-color-inverse: @white;
--heading-color: fade(@black, 85%); --icon-color-hover: fade(@black, 75%);
--heading-color: fade(@black, 85%);
--item-hover-bg: #f5f5f5;
--item-hover-bg: #f5f5f5;
// Border color
--border-color-base: hsv(0, 0, 85%); // Border color
--border-color-split: hsv(0, 0, 94%); --border-color-base: hsv(0, 0, 85%);
//--border-color-inverse: @white; --border-color-split: hsv(0, 0, 94%);
//--border-color-inverse: @white;
//
--background-color-light: hsv(0, 0, 98%); //
--background-color-base: hsv(0, 0, 96%); --background-color-light: hsv(0, 0, 98%);
--background-color-base: hsv(0, 0, 96%);
// Disabled states
--disabled-color: fade(#000, 25%); // Disabled states
--disabled-bg: @background-color-base; --disabled-color: fade(#000, 25%);
--disabled-color-dark: fade(#fff, 35%); --disabled-bg: @background-color-base;
--disabled-color-dark: fade(#fff, 35%);
// Shadow
--shadow-color: rgba(0, 0, 0, 0.15); // Shadow
--shadow-color-inverse: @component-background; --shadow-color: rgba(195, 62, 62, 0.15);
--box-shadow-base: @shadow-1-down; --shadow-color-inverse: @component-background;
--shadow-1-up: 0 -2px 8px @shadow-color; --box-shadow-base: @shadow-1-down;
--shadow-1-down: 0 2px 8px @shadow-color; --shadow-1-up: 0 -2px 8px @shadow-color;
--shadow-1-left: -2px 0 8px @shadow-color; --shadow-1-down: 0 2px 8px @shadow-color;
--shadow-1-right: 2px 0 8px @shadow-color; --shadow-1-left: -2px 0 8px @shadow-color;
--shadow-2: 0 4px 12px @shadow-color; --shadow-1-right: 2px 0 8px @shadow-color;
--shadow-2: 0 4px 12px @shadow-color;
// Buttons
--btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); // Buttons
--btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); --btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
--btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12); --btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
--btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
--btn-default-bg: @component-background;
--btn-default-bg: @component-background;
--btn-default-ghost-color: @component-background;
--btn-default-ghost-border: @component-background; --btn-default-ghost-color: @component-background;
--btn-default-ghost-border: @component-background;
--btn-text-hover-bg: rgba(0, 0, 0, 0.018);
--btn-text-active-bg: rgba(0, 0, 0, 0.028); --btn-text-hover-bg: rgba(0, 0, 0, 0.018);
--btn-text-active-bg: rgba(0, 0, 0, 0.028);
// Checkbox
--checkbox-check-bg: @checkbox-check-color; // Checkbox
--checkbox-check-bg: @checkbox-check-color;
// Descriptions
--descriptions-bg: #fafafa; // Descriptions
--descriptions-bg: #fafafa;
// Divider
--divider-color: rgba(0, 0, 0, 6%); // Divider
--divider-color: rgba(0, 0, 0, 6%);
// Dropdown 有两个
--dropdown-menu-submenu-disabled-bg: @component-background; // Dropdown 有两个
--dropdown-menu-submenu-disabled-bg: @component-background;
// Radio
--radio-dot-disabled-color: fade(@black, 20%); // Radio
--radio-solid-checked-color: @component-background; --radio-dot-disabled-color: fade(@black, 20%);
--radio-solid-checked-color: @component-background;
// Radio buttons
--radio-disabled-button-checked-bg: coverTintMixin(@black, 90%); // Radio buttons
--radio-disabled-button-checked-color: @disabled-color; --radio-disabled-button-checked-bg: coverTintMixin(@black, 90%);
--radio-disabled-button-checked-color: @disabled-color;
// Layout
--layout-body-background: #f0f2f5; // Layout
--layout-header-background: #001529; --layout-body-background: #f0f2f5;
--layout-trigger-background: #002140; --layout-header-background: #001529;
//--layout-sider-background-1: coverTintMixin(#001529, 10%); --layout-trigger-background: #002140;
//--layout-sider-background-1: coverTintMixin(#001529, 10%);
// Dropdown 有两个
--dropdown-menu-bg: @component-background; // Dropdown 有两个
--dropdown-menu-bg: @component-background;
// Input
--input-placeholder-color: hsv(0, 0, 75%); // Input
--input-icon-color: @input-color; --input-placeholder-color: hsv(0, 0, 75%);
--input-bg: @component-background; --input-icon-color: @input-color;
--input-number-handler-active-bg: #f4f4f4; --input-bg: @component-background;
--input-icon-hover-color: fade(@black, 85%); --input-number-handler-active-bg: #f4f4f4;
--input-icon-hover-color: fade(@black, 85%);
// Mentions
--mentions-dropdown-bg: @component-background; // Mentions
--mentions-dropdown-bg: @component-background;
// Select
--select-dropdown-bg: @component-background; // Select
--select-background: @component-background; --select-dropdown-bg: @component-background;
--select-clear-background: @select-background; --select-background: @component-background;
--select-selection-item-bg: @background-color-base; --select-clear-background: @select-background;
--select-selection-item-border-color: @border-color-split; --select-selection-item-bg: @background-color-base;
--select-multiple-disabled-background: @input-disabled-bg; --select-selection-item-border-color: @border-color-split;
--select-multiple-item-disabled-color: #bfbfbf; --select-multiple-disabled-background: @input-disabled-bg;
--select-multiple-item-disabled-border-color: @select-border-color; --select-multiple-item-disabled-color: #bfbfbf;
--select-multiple-item-disabled-border-color: @select-border-color;
// Cascader
--cascader-bg: @component-background; // Cascader
--cascader-menu-bg: @component-background; --cascader-bg: @component-background;
--cascader-menu-border-color-split: @border-color-split; --cascader-menu-bg: @component-background;
--cascader-menu-border-color-split: @border-color-split;
// Tooltip
--tooltip-bg: rgba(0, 0, 0, 0.75); // Tooltip
--tooltip-bg: rgba(0, 0, 0, 0.75);
// Popover
--popover-bg: @component-background; // Popover
--popover-bg: @component-background;
// Modal
--modal-header-bg: @component-background; // Modal
--modal-header-border-color-split: @border-color-split; --modal-header-bg: @component-background;
--modal-content-bg: @component-background; --modal-header-border-color-split: @border-color-split;
--modal-footer-border-color-split: @border-color-split; --modal-content-bg: @component-background;
--modal-footer-border-color-split: @border-color-split;
// Progress
--progress-steps-item-bg: #f3f3f3; // Progress
--progress-steps-item-bg: #f3f3f3;
// Menu
--menu-popup-bg: @component-background; // Menu
--menu-dark-bg: @layout-header-background; --menu-popup-bg: @component-background;
--menu-dark-inline-submenu-bg: #000c17; --menu-dark-bg: @layout-header-background;
--menu-dark-inline-submenu-bg: #000c17;
// Table
--table-header-bg: @background-color-light; // Table
--table-header-sort-bg: @background-color-base; --table-header-bg: @background-color-light;
--table-body-sort-bg: #fafafa; --table-header-sort-bg: @background-color-base;
--table-row-hover-bg: @background-color-light; --table-body-sort-bg: #fafafa;
--table-expanded-row-bg: #fbfbfb; --table-row-hover-bg: @background-color-light;
--table-header-cell-split-color: rgba(0, 0, 0, 0.06); --table-expanded-row-bg: #fbfbfb;
--table-header-sort-active-bg: rgba(0, 0, 0, 0.04); --table-header-cell-split-color: rgba(0, 0, 0, 0.06);
--table-header-filter-active-bg: rgba(0, 0, 0, 0.04); --table-header-sort-active-bg: rgba(0, 0, 0, 0.04);
--table-filter-btns-bg: inherit; --table-header-filter-active-bg: rgba(0, 0, 0, 0.04);
--table-filter-dropdown-bg: @component-background; --table-filter-btns-bg: inherit;
--table-expand-icon-bg: @component-background; --table-filter-dropdown-bg: @component-background;
--table-expand-icon-bg: @component-background;
// TimePicker
--picker-bg: @component-background; // TimePicker
--picker-basic-cell-disabled-bg: @disabled-bg; --picker-bg: @component-background;
--picker-border-color: @border-color-split; --picker-basic-cell-disabled-bg: @disabled-bg;
--picker-border-color: @border-color-split;
// Calendar
--calendar-bg: @component-background; // Calendar
--calendar-input-bg: @input-bg; --calendar-bg: @component-background;
--calendar-border-color: @border-color-inverse; --calendar-input-bg: @input-bg;
--calendar-full-bg: @calendar-bg; --calendar-border-color: @border-color-inverse;
--calendar-full-bg: @calendar-bg;
// Badge
--badge-text-color: @component-background; // Badge
--badge-text-color: @component-background;
// Rate
--rate-star-bg: @border-color-split; // Rate
--rate-star-bg: @border-color-split;
// Card
--card-actions-background: @component-background; // Card
--card-skeleton-bg: #cfd8dc; --card-actions-background: @component-background;
--card-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16), --card-skeleton-bg: #cfd8dc;
0 3px 6px 0 rgba(0, 0, 0, 0.12), 0 5px 12px 4px rgba(0, 0, 0, 0.09); --card-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16),
0 3px 6px 0 rgba(0, 0, 0, 0.12), 0 5px 12px 4px rgba(0, 0, 0, 0.09);
// Comment
--comment-bg: inherit; // Comment
--comment-author-time-color: #ccc; --comment-bg: inherit;
--comment-action-hover-color: #595959; --comment-author-time-color: #ccc;
--comment-action-hover-color: #595959;
// BackTop
--back-top-bg: @text-color-secondary; // BackTop
--back-top-hover-bg: @text-color; --back-top-bg: @text-color-secondary;
--back-top-hover-bg: @text-color;
// Avatar
--avatar-bg: #ccc; // Avatar
--avatar-bg: #ccc;
// Switch
--switch-bg: @component-background; // Switch
--switch-bg: @component-background;
// Pagination
--pagination-item-bg: @component-background; // Pagination
--pagination-item-bg-active: @component-background; --pagination-item-bg: @component-background;
--pagination-item-link-bg: @component-background; --pagination-item-bg-active: @component-background;
--pagination-item-disabled-color-active: @white; --pagination-item-link-bg: @component-background;
--pagination-item-disabled-bg-active: darken(hsv(0, 0, 96%), 10%); --pagination-item-disabled-color-active: @white;
--pagination-item-input-bg: @component-background; --pagination-item-disabled-bg-active: darken(hsv(0, 0, 96%), 10%);
--pagination-item-input-bg: @component-background;
// PageHeader
--page-header-back-color: #000; // PageHeader
--page-header-ghost-bg: inherit; --page-header-back-color: #000;
--page-header-ghost-bg: inherit;
// Slider
--slider-rail-background-color: @background-color-base; // Slider
--slider-rail-background-color-hover: #e1e1e1; --slider-rail-background-color: @background-color-base;
--slider-dot-border-color: @border-color-split; --slider-rail-background-color-hover: #e1e1e1;
--slider-dot-border-color-active: @primary-4; --slider-dot-border-color: @border-color-split;
--slider-dot-border-color-active: @primary-4;
// Tree
--tree-bg: @component-background; // Tree
--tree-bg: @component-background;
// Skeleton
--skeleton-to-color: coverShadeMixin(@skeleton-color, 5%); // Skeleton
--skeleton-to-color: coverShadeMixin(@skeleton-color, 5%);
// Transfer
--transfer-item-hover-bg: @item-hover-bg; // Transfer
--transfer-item-hover-bg: @item-hover-bg;
// Message
--message-notice-content-bg: @component-background; // Message
--message-notice-content-bg: @component-background;
// List
--list-customize-card-bg: @component-background; // List
--list-customize-card-bg: @component-background;
// Drawer
--drawer-bg: @component-background; // Drawer
--drawer-bg: @component-background;
// Timeline
--timeline-color: @border-color-split; // Timeline
--timeline-dot-color: @primary-color; --timeline-color: @border-color-split;
--timeline-dot-color: @primary-color;
// Image
--image-preview-operation-disabled-color: rgba(255, 255, 255, 0.45); // Image
--image-preview-operation-disabled-color: rgba(255, 255, 255, 0.45);
// Steps
--steps-nav-arrow-color: fade(@black, 25%); // Steps
--steps-background: @component-background; --steps-nav-arrow-color: fade(@black, 25%);
--steps-background: @component-background;
// Notification
--notification-bg: @component-background; // Notification
--notification-bg: @component-background;
// 侧边栏
--sidebar-light-shadow: 1px 3px 3px rgba(0, 21, 41, 0.08); // 侧边栏
--sidebar-dark-shadow: 0 4px 4px rgba(0, 0, 0, 0.35); --sidebar-light-shadow: 1px 3px 3px rgba(0, 21, 41, 0.08);
--sidebar-dark-shadow: 0 4px 4px rgba(0, 0, 0, 0.35);
// 顶栏
--header-light-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); // 顶栏
--header-dark-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); --header-light-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
--header-tool-hover-bg: rgba(0, 0, 0, 0.025); --header-dark-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
--header-dark-tool-hover-bg: rgba(255, 255, 255, 0.05); --header-tool-hover-bg: rgba(0, 0, 0, 0.025);
--header-color-split: rgba(0, 0, 0, 0.08); --header-dark-tool-hover-bg: rgba(255, 255, 255, 0.05);
--header-color-split: rgba(0, 0, 0, 0.08);
// logo
--logo-light-shadow: 1px 2px 3px rgba(0, 21, 41, 0.08); // logo
--logo-dark-shadow: 0 3px 4px rgba(0, 0, 0, 0.35); --logo-light-shadow: 1px 2px 3px rgba(0, 21, 41, 0.08);
--logo-dark-shadow: 0 3px 4px rgba(0, 0, 0, 0.35);
//
--gradient-min: fade(#cfd8dc, 20%); //
--gradient-max: fade(#cfd8dc, 40%); --gradient-min: fade(#cfd8dc, 20%);
--gradient-max: fade(#cfd8dc, 40%);
//
--success-fade-20: fade(#52c41a, 20%); // font
--error-fade-20: fade(#ff4d4f, 20%); --font-color: rgba(0, 0, 0, 0.88);
--warning-fade-20: fade(#faad14, 20%); // header-bottom
--header-bottom: rgba(246, 246, 246, 0.85);
//--primary-fade-20: fade(#1890ff, 20%); // breadcrumb-background
--primary-fade-20: var(--primary-2); --breadcrumb-background: rgba(253, 253, 253, 0.85);
//--primary-fade-8: fade(#1890ff, 8%); // background-color
--snowy-background-color: #FFFFFF;
--white--fade--65: rgba(255,255,255,.65); // tag-background
--menu-dark-highlight-color: #fff; --tag-background: rgba(253, 253, 253);
--btn-primary-color: #fff; //
--tooltip-color: #fff; --success-fade-20: fade(#52c41a, 20%);
--error-fade-20: fade(#ff4d4f, 20%);
// workfolw design --warning-fade-20: fade(#faad14, 20%);
--node-wrap-box-color: rgb(255, 255, 255);
--node-wrap-box-before-color: #FFFFFF; //--primary-fade-20: fade(#1890ff, 20%);
--node-wrap-box-before-borde-color: rgb(202, 202, 202); --primary-fade-20: var(--primary-2);
--auto-judge-before-color: @component-background; //--primary-fade-8: fade(#1890ff, 8%);
}
--white--fade--65: rgba(255,255,255,.65);
--menu-dark-highlight-color: #fff;
#app .form-designer-container-9136076486841527{ --btn-primary-color: #fff;
--form-designer-primary-color: var(--primary-6); --tooltip-color: #fff;
--primary-background-color: @component-background; --card-above-color: #F0F0F0;
--layout-background-color: fade(#9867f7, 12%); --card-above-border-color: #CCCCCC;
--layout-hover-bg-color: fade(#9867f7, 24%);
// workfolw design
--title-text-color: fade(@white, 85%); --node-wrap-box-color: rgb(255, 255, 255);
--border-color: var(--border-color-split); --node-wrap-box-before-color: #FFFFFF;
--node-wrap-box-before-borde-color: rgb(202, 202, 202);
--auto-judge-before-color: #FFF;
--cover-line-before-color: #FFF;
} }

View File

@ -1,17 +1,6 @@
@import 'ant-design-vue/dist/antd';
@import 'ant-design-vue/es/style/themes/default.less';
@import './realdark'; @import './realdark';
@import './default'; @import './default';
/* 全局 */
/*
#app, body, html {
width: 100%;
height: 100%;
background-color: #f6f8f9;
}
*/
.body, html { .body, html {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -56,6 +45,7 @@ a, button, input, textarea {
padding: 11px 11px 0px; padding: 11px 11px 0px;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
flex: auto;
} }
.main-bottom-wrapper { .main-bottom-wrapper {
@ -71,7 +61,6 @@ a, button, input, textarea {
/* 双排菜单布局 */ /* 双排菜单布局 */
.snowy-doublerow-layout-menu { .snowy-doublerow-layout-menu {
padding-left: 5px;
padding-right: 5px; padding-right: 5px;
line-height: 0; line-height: 0;
align-items: center; align-items: center;
@ -86,26 +75,10 @@ a, button, input, textarea {
} }
.snowy-doublerow-layout-menu-item-fort-div-span { .snowy-doublerow-layout-menu-item-fort-div-span {
font-size: 12px; font-size: 13px;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.snowy-doublerow-side-top {
border-bottom: 1px solid var(--border-color-split);
height: 50px;
line-height: 50px;
padding-left: 20px;
font-size: 12px
}
// 应用主题色
.snowy-doublerow-side-top-primary-color {
background-color: var(--primary-color);
.snowy-title {
color: white;
}
}
.snowy-title{ .snowy-title{
color: var(--text-color); color: var(--text-color);
} }
@ -120,7 +93,6 @@ a, button, input, textarea {
} }
} }
/* 设置抽屉样式 */ /* 设置抽屉样式 */
.layout-setting { .layout-setting {
position: fixed; position: fixed;
@ -147,14 +119,13 @@ a, button, input, textarea {
height: 50px; height: 50px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
border-bottom: 1px solid var(--border-color-split); border-bottom: 1px solid var(--header-bottom);
box-shadow: 0 1px 4px rgba(0, 21, 41, .08); box-shadow: 0 0.4px 0.5px rgb(0 21 41 / 12%);
background-color: var(--body-background);
.ant-menu-item{ .ant-menu-item{
height: 48px; height: 48px;
line-height: 48px; line-height: 48px;
} }
background: var(--snowy-background-color);
} }
// 应用主题色 // 应用主题色
.snowy-header-primary-color { .snowy-header-primary-color {
@ -197,7 +168,7 @@ a, button, input, textarea {
} }
.snowy-header-logo { .snowy-header-logo {
height: 50px; height: 49px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
border-bottom: 1px solid rgba(255, 255, 255, 0.04); border-bottom: 1px solid rgba(255, 255, 255, 0.04);
@ -221,105 +192,29 @@ a, button, input, textarea {
height: 35px; height: 35px;
} }
/* 面包屑 */ .top-snowy-header {
.admin-ui-topbar { background: #001529;
padding-left: 15px color: white;
} }
.top-snowy-header-light {
.admin-ui-topbar .left-panel { background: #ffffff;
display: flex; color: #000000;
align-items: center;
} }
.top-snowy-header-layout {
.admin-ui-topbar .right-panel { background: var(--primary-color);
display: flex; color: #ffffff;
align-items: center;
} }
.panel-item { .panel-item {
padding: 0 10px; padding: 0 10px;
cursor: pointer; cursor: pointer;
height: 100%; height: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
/*color: var(--font-color);*/
} }
.panel-item:hover { .panel-item:hover {
background: var(--header-color-split); background: var(--header-color-split);
} }
/* 多标签 */
.snowy-tags {
height: 40px;
background: var(--component-background);
}
.snowy-tags ul {
display: flex;
overflow: hidden;
padding-left: 0;
}
.snowy-tags li {
cursor: pointer;
display: inline-block;
float: left;
line-height: 39.5px;
position: relative;
flex-shrink: 0;
}
.snowy-tags li::after {
content: " ";
width: 1px;
height: 100%;
position: absolute;
right: 0px;
background-image: linear-gradient(#fff, #e6e6e6);
}
.snowy-tags li a {
padding: 0 10px;
width: 100%;
height: 100%;
text-decoration: none;
display: flex;
align-items: center;
}
.snowy-tags li i {
margin-left: 10px;
border-radius: 3px;
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
}
.snowy-tags li i:hover {
background: rgba(0, 0, 0, .2);
color: @body-background;
}
.snowy-tags li:hover {
background: @body-background;
}
.snowy-tags li.active {
background: @primary-color;
}
.snowy-tags li.active a {
color: #fff;
}
.snowy-tags li.sortable-ghost {
opacity: 0;
}
.snowy-header-tags-right {
margin-right: 10px;
}
.contextmenu { .contextmenu {
position: fixed; position: fixed;
width: 200px; width: 200px;
@ -407,6 +302,10 @@ a, button, input, textarea {
.ant-card-extra { .ant-card-extra {
padding: 12px 0!important; padding: 12px 0!important;
} }
.ant-card-head {
border-bottom: 0px !important;
min-height: 50px !important;
}
/* 重写antdv的表格滚动条 */ /* 重写antdv的表格滚动条 */
.ant-table-body, .ant-table-content{ .ant-table-body, .ant-table-content{
@ -427,9 +326,9 @@ a, button, input, textarea {
} }
.left-span-label { .left-span-label {
border-left: 4px solid @primary-color; border-left: 4px solid var(--primary-color);
font-size: 15px; font-size: 15px;
color: #212121; color: var(--font-color);
font-weight: 600; font-weight: 600;
padding-left: 8px; padding-left: 8px;
} }
@ -464,8 +363,8 @@ body,
.admin-ui-main{ .admin-ui-main{
&::-webkit-scrollbar { &::-webkit-scrollbar {
/*滚动条整体样式*/ /*滚动条整体样式*/
width : 0px; /*高宽分别对应横竖滚动条的尺寸*/ width : 0; /*高宽分别对应横竖滚动条的尺寸*/
height: 0px; height: 0;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/ /*滚动条里面小方块*/
@ -498,3 +397,115 @@ body,
display: none!important; display: none!important;
} }
} }
.ant-modal-close-x .anticon {
padding: 2px !important;
}
.xn-mb10 {
margin-bottom: 10px;
}
.xn-mt4 {
margin-top: 4px;
}
.xn-mg08 {
margin: 0 8px;
}
.xn-fdr {
float: right;
}
.xn-wd {
width: 100%;
}
.xn-wd90 {
width: 90px;
}
.xn-wdcalc-70 {
width: calc(100% - 70px);
}
.xn-mr8 {
margin-right: 8px;
}
.xn-ht400 {
height: 400px;
}
.xn-wh25 {
height: 25px;
width: 25px;
}
.xn-ml10 {
margin-left: 10px;
}
.xn-pl0 {
padding-left: 0px;
}
.xn-pd8 {
padding: 8px;
}
.xn-pb10 {
padding-bottom: 10px;
}
.xn-color-a0a0a0 {
color: #a0a0a0;
}
.xn-color-d9d9d9 {
color: #d9d9d9;
}
.xn-color-ff4d4f {
color: #ff4d4f;
}
.xn-color-00025 {
color: rgba(0, 0, 0, 0.25);
}
.xn-jk-line {
width: 188px;
margin-bottom: 8px;
display: block;
}
.xn-findform-line {
border: 1px solid var(--border-color-split);
cursor: pointer;
width: 100%;
height: 40px;
}
.odd {
background-color: var(--table-row-hover-bg);
}
.snowy-theme-dark .odd {
background-color: #1d1d1d
}
// 以下是重写表单设计器的样式
.list-main {
background: var(--auto-judge-before-color) !important;
}
.drag-move-box:before {
background: var(--primary-color) !important;
}
.drag-move-box>.delete {
background: var(--primary-color) !important;
}
.drag-move-box>.copy {
background: var(--primary-color) !important;
}
.drag-move-box .show-key-box {
color: var(--primary-color) !important;
}
.left-ul-item:hover {
color: var(--primary-color) !important;
border: 1px solid var(--primary-color) !important;
-webkit-box-shadow: 0 2px 6px var(--primary-color) !important;
box-shadow: 0 2px 6px var(--primary-color) !important;
}
.list-main>.moving:before {
background: var(--primary-color) !important;
}
.operating-area a:hover {
color: var(--primary-color) !important;
}
.batch-box>.delete {
background: var(--primary-color) !important;
}
.batch-box>.copy {
background: var(--primary-color) !important;
}
.batch-box.active:before {
background: var(--primary-color) !important;
}

View File

@ -1,126 +0,0 @@
@media (max-width: 992px) {
// 移动端样式覆盖
.el-form-item {
display: block;
}
.el-form-item__label {
display: block;
text-align: left;
padding: 0 0 10px;
}
.el-dialog {
width: 90% !important;
}
.el-dialog.is-fullscreen {
width: 100% !important;
}
.el-drawer.rtl {
width: 90% !important;
}
.el-form-item__content {
margin-left: 0px !important;
}
.admin-ui-main {
> .el-container {
display: block;
height: auto;
}
> .el-container > .el-aside {
width: 100% !important;
border: 0
}
}
.scTable {
.el-table,
.el-table__body-wrapper {
display: block !important;
height: auto !important;
}
.scTable-page {
padding: 0 5px !important;
}
.el-pagination__total,
.el-pagination__jump,
.scTable-do {
display: none !important;
}
}
.headerPublic {
height: auto !important;
display: block;
.left-panel {
overflow: auto;
}
.left-panel::-webkit-scrollbar {
display: none;
}
.right-panel {
display: block;
margin-top: 15px;
}
.right-panel .right-panel-search {
display: block;
}
.right-panel .right-panel-search > * {
width: 100%;
margin: 0;
margin-top: 15px;
}
}
.admin-ui-main > .el-container > *:first-child:not(.el-aside):not(.el-header) {
border: 0;
margin-top: 0;
}
.admin-ui-main > .el-container > *:first-child:not(.el-aside):not(.el-header) + .el-aside {
margin-top: 0;
}
.admin-ui-main > .el-container > .el-aside {
border-bottom: 1px solid #ebeef5 !important;
}
.admin-ui-main > .el-container > .el-container {
border-top: 1px solid #ebeef5;
border-bottom: 1px solid #ebeef5;
margin-top: 15px;
}
.admin-ui-main > .el-container > .el-header {
@extend . headerPublic;
border-bottom: 1px solid #ebeef5;
}
.admin-ui-main > .el-container > .el-main {
border-top: 1px solid #ebeef5;
border-bottom: 1px solid #ebeef5;
margin-top: 15px;
}
.admin-ui-main > .el-container > .el-main + .el-aside {
border-left: 0 !important;
border-top: 1px solid #ebeef5;
margin-top: 15px;
}
.admin-ui-main > .el-container > .el-container > .el-header {
@extend . headerPublic
}
}

View File

@ -1,92 +0,0 @@
/* USERCENTER */
.user-info {
padding: 20px 40px;
}
.user-info-top {
text-align: center;
}
.user-info-top h2 {
margin-top: 10px;
font-size: 24px;
}
.user-info-top p {
color: #999;
margin-top: 5px;
}
.user-info-top button {
margin-top: 10px;
}
.user-info-main {
padding: 20px 0;
}
.user-info-main li {
list-style-type: none;
line-height: 2;
font-size: 14px;
}
.user-info-main li i {
margin-right: 10px;
}
.user-info-bottom {
border-top: 1px solid #e6e6e6;
}
.user-info-bottom h2 {
font-size: 14px;
margin: 15px 0;
}
/*static-table*/
.static-table {
border-collapse: collapse;
width: 100%;
font-size: 14px;
margin-bottom: 45px;
line-height: 1.5em;
}
.static-table th {
text-align: left;
white-space: nowrap;
color: #909399;
font-weight: 400;
border-bottom: 1px solid #dcdfe6;
padding: 15px;
max-width: 250px;
}
.static-table td {
border-bottom: 1px solid #dcdfe6;
padding: 15px;
max-width: 250px;
color: #606266;
}
/*header-tabs*/
.header-tabs {
padding: 0;
display: block;
border: 0 !important;
height: auto;
}
.header-tabs .el-tabs {
border: 0;
box-shadow: none;
}
.header-tabs .el-tabs__content {
display: none;
}
.header-tabs .el-tabs__item {
font-size: 12px;
}

View File

@ -3,5 +3,5 @@
直接 var(--primary-color) 直接 var(--primary-color)
例如:新建个变量,黑的白的在不同的less中设定好这个时候就会跟着颜色的主题变化 例如:新建个变量,在default.less跟realdark.less中设定好这个时候就会跟着颜色的主题变化

View File

@ -11,16 +11,10 @@
@functions: ~`(function() { @functions: ~`(function() {
this.fade = function(color, amount) { this.fade = function(color, amount) {
if (String(color).indexOf('var(') === 0) { if (String(color).indexOf('var(') === 0) {
/*
(var(--primary-color), 7) -> var(--primary-7)
*/
if (color.indexOf('--primary-color') !== -1 ) { if (color.indexOf('--primary-color') !== -1 ) {
var m = amount > 10 ? amount/10 :amount var m = amount > 10 ? amount/10 :amount
return color.replace('-color)', '-' + m + ')') return color.replace('-color)', '-' + m + ')')
} }
/*
(var(--error-color), 70%) ===> var(--error-color--fade-7)
*/
return color.replace(')', '--fade--' + parseInt(amount) + ')') return color.replace(')', '--fade--' + parseInt(amount) + ')')
} }
return color return color
@ -29,403 +23,395 @@
} }
.fade(); .fade();
@import 'ant-design-vue/es/style/themes/default.less'; @import 'ant-design-vue/dist/reset.css';
//@import '../themes/default.less';
.snowy-theme-dark { .snowy-theme-dark {
--blue-1: #111d2c; --blue-1: #111d2c;
--blue-2: #112a45; --blue-2: #112a45;
--blue-3: #15395b; --blue-3: #15395b;
--blue-4: #164c7e; --blue-4: #164c7e;
--blue-5: #1765ad; --blue-5: #1765ad;
--blue-6: #177ddc; --blue-6: #177ddc;
--blue-7: #3c9ae8; --blue-7: #3c9ae8;
--blue-8: #65b7f3; --blue-8: #65b7f3;
--blue-9: #8dcff8; --blue-9: #8dcff8;
--blue-10: #b7e3fa; --blue-10: #b7e3fa;
--green-1: #162312; --green-1: #162312;
--green-2: #1d3712; --green-2: #1d3712;
--green-3: #274916; --green-3: #274916;
--green-4: #306317; --green-4: #306317;
--green-5: #3c8618; --green-5: #3c8618;
--green-6: #49aa19; --green-6: #49aa19;
--green-7: #6abe39; --green-7: #6abe39;
--green-8: #8fd460; --green-8: #8fd460;
--green-9: #b2e58b; --green-9: #b2e58b;
--green-10: #d5f2bb; --green-10: #d5f2bb;
--red-1: #2a1215; --red-1: #2a1215;
--red-2: #431418; --red-2: #431418;
--red-3: #58181c; --red-3: #58181c;
--red-4: #791a1f; --red-4: #791a1f;
--red-5: #a61d24; --red-5: #a61d24;
--red-6: #f5222d; --red-6: #f5222d;
--red-7: #e84749; --red-7: #e84749;
--red-8: #f37370; --red-8: #f37370;
--red-9: #f89f9a; --red-9: #f89f9a;
--red-10: #fac8c3; --red-10: #fac8c3;
--gold-1: #2b2111; --gold-1: #2b2111;
--gold-2: #443111; --gold-2: #443111;
--gold-3: #594214; --gold-3: #594214;
--gold-4: #7c5914; --gold-4: #7c5914;
--gold-5: #aa7714; --gold-5: #aa7714;
--gold-6: #d89614; --gold-6: #d89614;
--gold-7: #e8b339; --gold-7: #e8b339;
--gold-8: #f3cc62; --gold-8: #f3cc62;
--gold-9: #f8df8b; --gold-9: #f8df8b;
--gold-10: #faedb5; --gold-10: #faedb5;
--purple-1: #1a1325; --purple-1: #1a1325;
--purple-2: #24163a; --purple-2: #24163a;
--purple-3: #301c4d; --purple-3: #301c4d;
--purple-4: #3e2069; --purple-4: #3e2069;
--purple-5: #51258f; --purple-5: #51258f;
--purple-6: #642ab5; --purple-6: #642ab5;
--purple-7: #854eca; --purple-7: #854eca;
--purple-8: #ab7ae0; --purple-8: #ab7ae0;
--purple-9: #cda8f0; --purple-9: #cda8f0;
--purple-10: #ebd7fa; --purple-10: #ebd7fa;
--cyan-1: #112123; --cyan-1: #112123;
--cyan-2: #113536; --cyan-2: #113536;
--cyan-3: #144848; --cyan-3: #144848;
--cyan-4: #146262; --cyan-4: #146262;
--cyan-5: #138585; --cyan-5: #138585;
--cyan-6: #13a8a8; --cyan-6: #13a8a8;
--cyan-7: #33bcb7; --cyan-7: #33bcb7;
--cyan-8: #58d1c9; --cyan-8: #58d1c9;
--cyan-9: #84e2d8; --cyan-9: #84e2d8;
--cyan-10: #b2f1e8; --cyan-10: #b2f1e8;
--pink-1: #291321; --pink-1: #291321;
--pink-2: #40162f; --pink-2: #40162f;
--pink-3: #551c3b; --pink-3: #551c3b;
--pink-4: #75204f; --pink-4: #75204f;
--pink-5: #a02669; --pink-5: #a02669;
--pink-6: #cb2b83; --pink-6: #cb2b83;
--pink-7: #e0529c; --pink-7: #e0529c;
--pink-8: #f37fb7; --pink-8: #f37fb7;
--pink-9: #f8a8cc; --pink-9: #f8a8cc;
--pink-10: #fad2e3; --pink-10: #fad2e3;
--orange-1: #2b1d11; --orange-1: #2b1d11;
--orange-2: #442a11; --orange-2: #442a11;
--orange-3: #593815; --orange-3: #593815;
--orange-4: #7c4a15; --orange-4: #7c4a15;
--orange-5: #aa6215; --orange-5: #aa6215;
--orange-6: #d87a16; --orange-6: #d87a16;
--orange-7: #e89a3c; --orange-7: #e89a3c;
--orange-8: #f3b765; --orange-8: #f3b765;
--orange-9: #f8cf8d; --orange-9: #f8cf8d;
--orange-10: #fae3b7; --orange-10: #fae3b7;
--primary-1: var(--blue-1); --primary-radius: #141414;
--primary-2: var(--blue-2); --primary-1: var(--blue-1);
--primary-3: var(--blue-3); --primary-2: var(--blue-2);
--primary-4: var(--blue-4); --primary-3: var(--blue-3);
--primary-5: var(--blue-5); --primary-4: var(--blue-4);
--primary-6: var(--blue-6); --primary-5: var(--blue-5);
--primary-7: var(--blue-7); --primary-6: var(--blue-6);
--primary-8: var(--blue-8); --primary-7: var(--blue-7);
--primary-9: var(--blue-9); --primary-8: var(--blue-8);
--primary-10: var(--blue-10); --primary-9: var(--blue-9);
--primary-10: var(--blue-10);
--primary-color: var(--primary-6);
--primary-color-hover: var(--primary-5); --primary-color: var(--primary-6);
--primary-color-active: var(--primary-7); --primary-color-hover: var(--primary-5);
--primary-color-outline: var(--primary-2); --primary-color-active: var(--primary-7);
--primary-color-outline: var(--primary-2);
--info-color: var(--primary-color);
--success-color: var(--green-6); --info-color: var(--primary-color);
--processing-color: var(--blue-6); --success-color: var(--green-6);
--highlight-color: var(--red-5); --processing-color: var(--blue-6);
--highlight-color: var(--red-5);
--warning-color: var(--gold-6);
--warning-color-hover: var(--gold-5); --warning-color: var(--gold-6);
--warning-color-active: var(--gold-7); --warning-color-hover: var(--gold-5);
--warning-color-outline: var(--gold-2); --warning-color-active: var(--gold-7);
--warning-color-outline: var(--gold-2);
--error-color: var(--red-5);
--error-color-hover: var(--red-4); --error-color: var(--red-5);
--error-color-active: var(--red-7); --error-color-hover: var(--red-4);
--error-color-outline: var(--red-2); --error-color-active: var(--red-7);
--error-color-outline: var(--red-2);
--body-background: @black;
--component-background: #141414; --body-background: @black;
--component-background: #141414;
--popover-background: #1f1f1f; --popover-background: #1f1f1f;
--popover-customize-border-color: #3a3a3a; --popover-customize-border-color: #3a3a3a;
--text-color: fade(@white, 85%); --text-color: fade(@white, 85%);
--text-color-secondary: fade(@white, 45%); --text-color-secondary: fade(@white, 45%);
--text-color-inverse: @white; --text-color-inverse: @white;
--icon-color-hover: fade(@white, 75%); --icon-color-hover: fade(@white, 75%);
--heading-color: fade(@white, 85%); --heading-color: fade(@white, 85%);
--item-hover-bg: fade(@white, 8%); --item-hover-bg: fade(@white, 8%);
// Border color // Border color
--border-color-base: #434343; --border-color-base: #434343;
--border-color-split: #303030; --border-color-split: #303030;
//--border-color-inverse: @black; //--border-color-inverse: @black;
// //
--background-color-light: fade(@white, 4%); --background-color-light: fade(@white, 4%);
--background-color-base: fade(@white, 8%); --background-color-base: fade(@white, 8%);
// Disabled states // Disabled states
--disabled-color: fade(@white, 30%); --disabled-color: fade(@white, 30%);
--disabled-bg: @background-color-base; --disabled-bg: @background-color-base;
--disabled-color-dark: fade(@white, 30%); --disabled-color-dark: fade(@white, 30%);
// Shadow // Shadow
--shadow-color: rgba(0, 0, 0, 0.45); --shadow-color: rgba(0, 0, 0, 0.45);
--shadow-color-inverse: @component-background; --shadow-color-inverse: @component-background;
--box-shadow-base: @shadow-2; --box-shadow-base: @shadow-2;
--shadow-1-up: 0 -6px 16px -8px rgba(0, 0, 0, 0.32), --shadow-1-up: 0 -6px 16px -8px rgba(0, 0, 0, 0.32),
0 -9px 28px 0 rgba(0, 0, 0, 0.2), 0 -12px 48px 16px rgba(0, 0, 0, 0.12); 0 -9px 28px 0 rgba(0, 0, 0, 0.2), 0 -12px 48px 16px rgba(0, 0, 0, 0.12);
--shadow-1-down: 0 6px 16px -8px rgba(0, 0, 0, 0.32), --shadow-1-down: 0 6px 16px -8px rgba(0, 0, 0, 0.32),
0 9px 28px 0 rgba(0, 0, 0, 0.2), 0 12px 48px 16px rgba(0, 0, 0, 0.12); 0 9px 28px 0 rgba(0, 0, 0, 0.2), 0 12px 48px 16px rgba(0, 0, 0, 0.12);
--shadow-1-right: 6px 0 16px -8px rgba(0, 0, 0, 0.32), --shadow-1-right: 6px 0 16px -8px rgba(0, 0, 0, 0.32),
9px 0 28px 0 rgba(0, 0, 0, 0.2), 12px 0 48px 16px rgba(0, 0, 0, 0.12); 9px 0 28px 0 rgba(0, 0, 0, 0.2), 12px 0 48px 16px rgba(0, 0, 0, 0.12);
--shadow-2: 0 3px 6px -4px rgba(0, 0, 0, 0.48), --shadow-2: 0 3px 6px -4px rgba(0, 0, 0, 0.48),
0 6px 16px 0 rgba(0, 0, 0, 0.32), 0 9px 28px 8px rgba(0, 0, 0, 0.2); 0 6px 16px 0 rgba(0, 0, 0, 0.32), 0 9px 28px 8px rgba(0, 0, 0, 0.2);
// Buttons // Buttons
--btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); --btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
--btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); --btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
--btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12); --btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
--btn-default-bg: transparent; --btn-default-bg: transparent;
--btn-default-ghost-color: @text-color; --btn-default-ghost-color: @text-color;
--btn-default-ghost-border: fade(@white, 25%); --btn-default-ghost-border: fade(@white, 25%);
--btn-text-hover-bg: rgba(255, 255, 255, 0.03); --btn-text-hover-bg: rgba(255, 255, 255, 0.03);
--btn-text-active-bg: rgba(255, 255, 255, 0.04); --btn-text-active-bg: rgba(255, 255, 255, 0.04);
// Checkbox // Checkbox
--checkbox-check-bg: transparent; --checkbox-check-bg: transparent;
// Descriptions // Descriptions
--descriptions-bg: @background-color-light; --descriptions-bg: @background-color-light;
// Divider // Divider
--divider-color: rgba(255, 255, 255, 12%); --divider-color: rgba(255, 255, 255, 12%);
// Dropdown 有两个 // Dropdown 有两个
--dropdown-menu-submenu-disabled-bg: transparent; --dropdown-menu-submenu-disabled-bg: transparent;
// Radio // Radio
--radio-dot-disabled-color: fade(@white, 20%); --radio-dot-disabled-color: fade(@white, 20%);
--radio-solid-checked-color: @white; --radio-solid-checked-color: @white;
// Radio buttons // Radio buttons
--radio-disabled-button-checked-bg: fade(@white, 20%); --radio-disabled-button-checked-bg: fade(@white, 20%);
--radio-disabled-button-checked-color: @disabled-color; --radio-disabled-button-checked-color: @disabled-color;
// Layout // Layout
--layout-body-background: @body-background; --layout-body-background: @body-background;
--layout-header-background: @popover-background; --layout-header-background: @popover-background;
--layout-trigger-background: #262626; --layout-trigger-background: #262626;
//--layout-sider-background-1: tint(#1f1f1f, 10%); //--layout-sider-background-1: tint(#1f1f1f, 10%);
// Dropdown 有两个 // Dropdown 有两个
--dropdown-menu-bg: @popover-background; --dropdown-menu-bg: @popover-background;
// Input // Input
--input-placeholder-color: fade(@white, 30%); --input-placeholder-color: fade(@white, 30%);
--input-icon-color: fade(@white, 30%); --input-icon-color: fade(@white, 30%);
--input-bg: transparent; --input-bg: transparent;
--input-number-handler-active-bg: @item-hover-bg; --input-number-handler-active-bg: @item-hover-bg;
--input-icon-hover-color: fade(@white, 85%); --input-icon-hover-color: fade(@white, 85%);
// Mentions // Mentions
--mentions-dropdown-bg: @popover-background; --mentions-dropdown-bg: @popover-background;
// Select // Select
--select-dropdown-bg: @popover-background; --select-dropdown-bg: @popover-background;
--select-background: transparent; --select-background: transparent;
--select-clear-background: @component-background; --select-clear-background: @component-background;
--select-selection-item-bg: fade(@white, 8); --select-selection-item-bg: fade(@white, 8);
--select-selection-item-border-color: @border-color-split; --select-selection-item-border-color: @border-color-split;
--select-multiple-disabled-background: @component-background; --select-multiple-disabled-background: @component-background;
--select-multiple-item-disabled-color: #595959; --select-multiple-item-disabled-color: #595959;
--select-multiple-item-disabled-border-color: @popover-background; --select-multiple-item-disabled-border-color: @popover-background;
// Cascader // Cascader
--cascader-bg: transparent; --cascader-bg: transparent;
--cascader-menu-bg: @popover-background; --cascader-menu-bg: @popover-background;
--cascader-menu-border-color-split: @border-color-split; --cascader-menu-border-color-split: @border-color-split;
// Tooltip // Tooltip
--tooltip-bg: #434343; --tooltip-bg: #434343;
// Popover // Popover
--popover-bg: @popover-background; --popover-bg: @popover-background;
// Modal // Modal
--modal-header-bg: @popover-background; --modal-header-bg: @popover-background;
--modal-header-border-color-split: @border-color-split; --modal-header-border-color-split: @border-color-split;
--modal-content-bg: @popover-background; --modal-content-bg: @popover-background;
--modal-footer-border-color-split: @border-color-split; --modal-footer-border-color-split: @border-color-split;
// Progress // Progress
--progress-steps-item-bg: fade(@white, 8%); --progress-steps-item-bg: fade(@white, 8%);
// Menu // Menu
--menu-popup-bg: @popover-background; --menu-popup-bg: @popover-background;
--menu-dark-bg: @popover-background; --menu-dark-bg: @popover-background;
--menu-dark-inline-submenu-bg: @component-background; --menu-dark-inline-submenu-bg: @component-background;
// Table // Table
--table-header-bg: #1d1d1d; --table-header-bg: #1d1d1d;
--table-header-sort-bg: #262626; --table-header-sort-bg: #262626;
--table-body-sort-bg: fade(@white, 1%); --table-body-sort-bg: fade(@white, 1%);
--table-row-hover-bg: #262626; --table-row-hover-bg: #262626;
--table-expanded-row-bg: @table-header-bg; --table-expanded-row-bg: @table-header-bg;
--table-header-cell-split-color: fade(@white, 8%); --table-header-cell-split-color: fade(@white, 8%);
--table-header-sort-active-bg: #303030; --table-header-sort-active-bg: #303030;
--table-header-filter-active-bg: #434343; --table-header-filter-active-bg: #434343;
--table-filter-btns-bg: @popover-background; --table-filter-btns-bg: @popover-background;
--table-filter-dropdown-bg: @popover-background; --table-filter-dropdown-bg: @popover-background;
--table-expand-icon-bg: transparent; --table-expand-icon-bg: transparent;
// TimePicker // TimePicker
--picker-bg: transparent; --picker-bg: transparent;
--picker-basic-cell-disabled-bg: #303030; --picker-basic-cell-disabled-bg: #303030;
--picker-border-color: @border-color-split; --picker-border-color: @border-color-split;
// Calendar // Calendar
--calendar-bg: @popover-background; --calendar-bg: @popover-background;
--calendar-input-bg: @calendar-bg; --calendar-input-bg: @calendar-bg;
--calendar-border-color: transparent; --calendar-border-color: transparent;
--calendar-full-bg: @component-background; --calendar-full-bg: @component-background;
// Badge // Badge
--badge-text-color: @white; --badge-text-color: @white;
// Rate // Rate
--rate-star-bg: fade(@white, 12%); --rate-star-bg: fade(@white, 12%);
// Card // Card
--card-actions-background: @component-background; --card-actions-background: @component-background;
--card-skeleton-bg: #303030; --card-skeleton-bg: #303030;
--card-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.64), --card-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.64),
0 3px 6px 0 rgba(0, 0, 0, 0.48), 0 5px 12px 4px rgba(0, 0, 0, 0.36); 0 3px 6px 0 rgba(0, 0, 0, 0.48), 0 5px 12px 4px rgba(0, 0, 0, 0.36);
// Comment // Comment
--comment-bg: transparent; --comment-bg: transparent;
--comment-author-time-color: fade(@white, 30%); --comment-author-time-color: fade(@white, 30%);
--comment-action-hover-color: fade(@white, 65%); --comment-action-hover-color: fade(@white, 65%);
// BackTop // BackTop
--back-top-bg: var(--tooltip-bg); --back-top-bg: var(--tooltip-bg);
--back-top-hover-bg: var(--border-color-split); --back-top-hover-bg: var(--border-color-split);
// Avatar // Avatar
--avatar-bg: fade(@white, 30%); --avatar-bg: fade(@white, 30%);
// Switch // Switch
--switch-bg: @white; --switch-bg: @white;
// Pagination // Pagination
--pagination-item-bg: transparent; --pagination-item-bg: transparent;
--pagination-item-bg-active: transparent; --pagination-item-bg-active: transparent;
--pagination-item-link-bg: transparent; --pagination-item-link-bg: transparent;
--pagination-item-disabled-color-active: @black; --pagination-item-disabled-color-active: @black;
--pagination-item-disabled-bg-active: fade(@white, 25%); --pagination-item-disabled-bg-active: fade(@white, 25%);
--pagination-item-input-bg: @pagination-item-bg; --pagination-item-input-bg: @pagination-item-bg;
// PageHeader // PageHeader
--page-header-back-color: @icon-color; --page-header-back-color: @icon-color;
--page-header-ghost-bg: transparent; --page-header-ghost-bg: transparent;
// Slider // Slider
--slider-rail-background-color: #262626; --slider-rail-background-color: #262626;
--slider-rail-background-color-hover: @border-color-base; --slider-rail-background-color-hover: @border-color-base;
--slider-dot-border-color: @border-color-split; --slider-dot-border-color: @border-color-split;
--slider-dot-border-color-active: @primary-4; --slider-dot-border-color-active: @primary-4;
// Tree // Tree
--tree-bg: transparent; --tree-bg: transparent;
// Skeleton // Skeleton
--skeleton-to-color: fade(@white, 16%); --skeleton-to-color: fade(@white, 16%);
// Transfer // Transfer
--transfer-item-hover-bg: #262626; --transfer-item-hover-bg: #262626;
// Message // Message
--message-notice-content-bg: @popover-background; --message-notice-content-bg: @popover-background;
// List // List
--list-customize-card-bg: transparent; --list-customize-card-bg: transparent;
// Drawer // Drawer
--drawer-bg: @popover-background; --drawer-bg: @popover-background;
// Timeline // Timeline
--timeline-color: @border-color-split; --timeline-color: @border-color-split;
--timeline-dot-color: @primary-color; --timeline-dot-color: @primary-color;
// Steps // Steps
--steps-nav-arrow-color: fade(@white, 20%); --steps-nav-arrow-color: fade(@white, 20%);
--steps-background: transparent; --steps-background: transparent;
// Notification // Notification
--notification-bg: @popover-background; --notification-bg: @popover-background;
// 侧边栏 // 侧边栏
--sidebar-light-shadow: 0 4px 4px rgba(0, 0, 0, 0.6); --sidebar-light-shadow: 0 4px 4px rgba(0, 0, 0, 0.6);
--sidebar-dark-shadow: 0 4px 4px rgba(0, 0, 0, 0.6); --sidebar-dark-shadow: 0 4px 4px rgba(0, 0, 0, 0.6);
// 顶栏 // 顶栏
--header-light-shadow: 0 1px 4px rgba(0, 0, 0, 0.6); --header-light-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
--header-dark-shadow: 0 1px 4px rgba(0, 0, 0, 0.6); --header-dark-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
--header-tool-hover-bg: rgba(255, 255, 255, 0.05); --header-tool-hover-bg: rgba(255, 255, 255, 0.05);
--header-dark-tool-hover-bg: rgba(255, 255, 255, 0.05); --header-dark-tool-hover-bg: rgba(255, 255, 255, 0.05);
--header-color-split: rgba(255, 255, 255, 0.15); --header-color-split: rgba(255, 255, 255, 0.15);
// logo // logo
--logo-light-shadow: 0 3px 4px rgba(0, 0, 0, 0.6); --logo-light-shadow: 0 3px 4px rgba(0, 0, 0, 0.6);
--logo-dark-shadow: 0 3px 4px rgba(0, 0, 0, 0.6); --logo-dark-shadow: 0 3px 4px rgba(0, 0, 0, 0.6);
// //
--gradient-min: fade(#303030, 20%); --gradient-min: fade(#303030, 20%);
--gradient-max: fade(#303030, 40%); --gradient-max: fade(#303030, 40%);
// // font
--primary-fade-20: var(--primary-2); --font-color: #FFFFFF;
// header-bottom
--black--fade--85: rgba(255, 255, 255, 0.85); --header-bottom: rgba(54, 54, 54, 0.6);
--switch-shadow-color: 0 2px 4px rgb(0 35 11 / 20%); // breadcrumb-background
--breadcrumb-background: rgba(54, 54, 54, 0.6);
// workfolw design // background-color
--node-wrap-box-color: #303030; --snowy-background-color: #141414;
--node-wrap-box-before-color: rgba(255, 255, 255, 0.09); // 箭头旁边 // tag-background
--node-wrap-box-before-borde-color: rgba(255, 255, 255, 0.09); // 箭头 --tag-background: rgba(56, 56, 56);
--auto-judge-before-color: @component-background; // 箭头背景 //
} --primary-fade-20: var(--primary-2);
// 表单设计器主题覆盖 --black--fade--85: rgba(255, 255, 255, 0.85);
.snowy-theme-dark{ --switch-shadow-color: 0 2px 4px rgb(0 35 11 / 20%);
--hint-color: #888; --card-above-color: #303030;
--card-above-border-color: #484848;
.form-designer-container-9136076486841527{
--form-designer-primary-color: var(--primary-6); // workfolw design
--primary-background-color: @component-background; --node-wrap-box-color: #303030;
--layout-background-color: fade(#9867f7, 12%); --node-wrap-box-before-color: rgba(255, 255, 255, 0.09); // 箭头旁边
--layout-hover-bg-color: fade(#9867f7, 24%); --node-wrap-box-before-borde-color: rgba(255, 255, 255, 0.09); // 箭头
--auto-judge-before-color: #141414; // 箭头背景
--title-text-color: fade(@black, 85%); --cover-line-before-color: #141414;
--border-color: var(--border-color-split);
--component-background: #141414;
}
} }

View File

@ -11,7 +11,7 @@
import { generate } from '@ant-design/colors' import { generate } from '@ant-design/colors'
import tool from '../utils/tool' import tool from '../utils/tool'
import config from '../config' import config from '../config'
import { ThemeModeEnum } from './enum' import { themeEnum } from '@/layout/enum/themeEnum'
const changeColor = (newPrimaryColor, theme, darkClass = 'snowy-theme-dark') => { const changeColor = (newPrimaryColor, theme, darkClass = 'snowy-theme-dark') => {
return new Promise((resolve) => { return new Promise((resolve) => {
@ -20,7 +20,7 @@ const changeColor = (newPrimaryColor, theme, darkClass = 'snowy-theme-dark') =>
if (themeEle && themeEle.parentNode) { if (themeEle && themeEle.parentNode) {
themeEle.parentNode.removeChild(themeEle) themeEle.parentNode.removeChild(themeEle)
} }
const isRealDark = theme === ThemeModeEnum.REAL_DARK const isRealDark = theme === themeEnum.REAL_DARK
if (newPrimaryColor) { if (newPrimaryColor) {
const colors = generate(newPrimaryColor, isRealDark ? { theme: 'dark' } : {}) const colors = generate(newPrimaryColor, isRealDark ? { theme: 'dark' } : {})
const rootClass = isRealDark ? `.${darkClass}` : ':root' const rootClass = isRealDark ? `.${darkClass}` : ':root'

View File

@ -8,7 +8,7 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作 * 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip * 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/ */
/* /**
* @Descripttion: 工具集 * @Descripttion: 工具集
* @version: 1.1 * @version: 1.1
* @LastEditors: yubaoshan * @LastEditors: yubaoshan
@ -20,10 +20,18 @@ const tool = {}
tool.data = { tool.data = {
set(table, settings) { set(table, settings) {
const _set = JSON.stringify(settings) const _set = JSON.stringify(settings)
return localStorage.setItem(table, _set) const SNOWYSTRING = table.slice(0, 6) === 'SNOWY_' && table !== 'SNOWY_SYS_BASE_CONFIG'
if (SNOWYSTRING) {
let localSetting = JSON.parse(localStorage.getItem('SNOWY_SETTING')) || {}
let newSetting = {}
newSetting[table] = _set
return localStorage.setItem('SNOWY_SETTING', JSON.stringify(Object.assign(localSetting, newSetting)))
} else return localStorage.setItem(table, _set)
}, },
get(table) { get(table) {
let data = localStorage.getItem(table) const SNOWYSTRING = table.slice(0, 6) === 'SNOWY_' && table !== 'SNOWY_SYS_BASE_CONFIG'
const SNOWY_SETTING = JSON.parse(localStorage.getItem('SNOWY_SETTING')) || {}
let data = SNOWYSTRING ? SNOWY_SETTING[table] : localStorage.getItem(table)
try { try {
data = JSON.parse(data) data = JSON.parse(data)
} catch (err) { } catch (err) {

View File

@ -3,7 +3,7 @@
<a-form-item name="email"> <a-form-item name="email">
<a-input v-model:value="emailFormData.email" :placeholder="$t('login.emailPlaceholder')" size="large"> <a-input v-model:value="emailFormData.email" :placeholder="$t('login.emailPlaceholder')" size="large">
<template #prefix> <template #prefix>
<mail-outlined style="color: rgba(0, 0, 0, 0.25)" /> <mail-outlined class="xn-color-00025" />
</template> </template>
</a-input> </a-input>
</a-form-item> </a-form-item>
@ -16,12 +16,12 @@
size="large" size="large"
> >
<template #prefix> <template #prefix>
<mail-outlined style="color: rgba(0, 0, 0, 0.25)" /> <mail-outlined class="xn-color-00025" />
</template> </template>
</a-input> </a-input>
</a-col> </a-col>
<a-col :span="7"> <a-col :span="7">
<a-button size="large" style="width: 100%" @click="getEmailValidCode" :disabled="state.smsSendBtn">{{ <a-button size="large" class="xn-wd" @click="getEmailValidCode" :disabled="state.smsSendBtn">{{
(!state.smsSendBtn && $t('login.getSmsCode')) || state.time + ' s' (!state.smsSendBtn && $t('login.getSmsCode')) || state.time + ' s'
}}</a-button> }}</a-button>
</a-col> </a-col>
@ -35,7 +35,7 @@
size="large" size="large"
> >
<template #prefix> <template #prefix>
<LockOutlined style="color: rgba(0, 0, 0, 0.25)" /> <LockOutlined class="xn-color-00025" />
</template> </template>
</a-input-password> </a-input-password>
</a-form-item> </a-form-item>
@ -43,10 +43,10 @@
<a-form-item> <a-form-item>
<a-row :gutter="8"> <a-row :gutter="8">
<a-col :span="7"> <a-col :span="7">
<a-button style="width: 100%" round size="large" href="/login">{{ $t('login.backLogin') }}</a-button> <a-button class="xn-wd" round size="large" href="/login">{{ $t('login.backLogin') }}</a-button>
</a-col> </a-col>
<a-col :span="17"> <a-col :span="17">
<a-button type="primary" style="width: 100%" :loading="islogin" round size="large" @click="submitReset">{{ <a-button type="primary" class="xn-wd" :loading="islogin" round size="large" @click="submitReset">{{
$t('login.restPassword') $t('login.restPassword')
}}</a-button> }}</a-button>
</a-col> </a-col>
@ -54,7 +54,7 @@
</a-form-item> </a-form-item>
</a-form> </a-form>
<a-modal <a-modal
v-model:visible="visible" v-model:open="visible"
:width="400" :width="400"
:title="$t('login.machineValidation')" :title="$t('login.machineValidation')"
@cancel="handleCancel" @cancel="handleCancel"
@ -70,16 +70,12 @@
size="large" size="large"
> >
<template #prefix> <template #prefix>
<verified-outlined style="color: rgba(0, 0, 0, 0.25)" /> <verified-outlined class="xn-color-00025" />
</template> </template>
</a-input> </a-input>
</a-col> </a-col>
<a-col :span="7"> <a-col :span="7">
<img <img :src="validCodeBase64" class="xn-findform-line" @click="getPhonePicCaptcha" />
:src="validCodeBase64"
style="border: 1px solid var(--border-color-split); cursor: pointer; width: 100%; height: 40px"
@click="getPhonePicCaptcha"
/>
</a-col> </a-col>
</a-row> </a-row>
</a-form-item> </a-form-item>
@ -121,23 +117,26 @@
formRules.value.emailValidCode = [required(), rules.number] formRules.value.emailValidCode = [required(), rules.number]
formRules.value.newPassword = [required()] formRules.value.newPassword = [required()]
emailResetFormRef.value.validate().then(() => { emailResetFormRef.value
emailFormData.value.validCode = emailFormData.value.emailValidCode .validate()
emailFormData.value.validCodeReqNo = emailValidCodeReqNo.value .then(() => {
emailFormData.value.newPassword = smCrypto.doSm2Encrypt(emailFormData.value.newPassword) emailFormData.value.validCode = emailFormData.value.emailValidCode
islogin.value = true emailFormData.value.validCodeReqNo = emailValidCodeReqNo.value
userCenterApi emailFormData.value.newPassword = smCrypto.doSm2Encrypt(emailFormData.value.newPassword)
.userFindPasswordByEmail(emailFormData.value) islogin.value = true
.then(() => { userCenterApi
router.replace({ .userFindPasswordByEmail(emailFormData.value)
path: '/' .then(() => {
router.replace({
path: '/'
})
message.success('找回成功')
}) })
message.success('找回成功') .finally(() => {
}) islogin.value = false
.finally(() => { })
islogin.value = false })
}) .catch(() => {})
})
} }
// //

View File

@ -3,7 +3,7 @@
<a-form-item name="phone"> <a-form-item name="phone">
<a-input v-model:value="phoneFormData.phone" :placeholder="$t('login.phonePlaceholder')" size="large"> <a-input v-model:value="phoneFormData.phone" :placeholder="$t('login.phonePlaceholder')" size="large">
<template #prefix> <template #prefix>
<mobile-outlined style="color: rgba(0, 0, 0, 0.25)" /> <mobile-outlined class="xn-color-00025" />
</template> </template>
</a-input> </a-input>
</a-form-item> </a-form-item>
@ -16,12 +16,12 @@
size="large" size="large"
> >
<template #prefix> <template #prefix>
<mail-outlined style="color: rgba(0, 0, 0, 0.25)" /> <mail-outlined class="xn-color-00025" />
</template> </template>
</a-input> </a-input>
</a-col> </a-col>
<a-col :span="7"> <a-col :span="7">
<a-button size="large" style="width: 100%" @click="getPhoneValidCode" :disabled="state.smsSendBtn">{{ <a-button size="large" class="xn-wd" @click="getPhoneValidCode" :disabled="state.smsSendBtn">{{
(!state.smsSendBtn && $t('login.getSmsCode')) || state.time + ' s' (!state.smsSendBtn && $t('login.getSmsCode')) || state.time + ' s'
}}</a-button> }}</a-button>
</a-col> </a-col>
@ -35,7 +35,7 @@
size="large" size="large"
> >
<template #prefix> <template #prefix>
<LockOutlined style="color: rgba(0, 0, 0, 0.25)" /> <LockOutlined class="xn-color-00025" />
</template> </template>
</a-input-password> </a-input-password>
</a-form-item> </a-form-item>
@ -43,10 +43,10 @@
<a-form-item> <a-form-item>
<a-row :gutter="8"> <a-row :gutter="8">
<a-col :span="7"> <a-col :span="7">
<a-button style="width: 100%" round size="large" href="/login">{{ $t('login.backLogin') }}</a-button> <a-button class="xn-wd" round size="large" href="/login">{{ $t('login.backLogin') }}</a-button>
</a-col> </a-col>
<a-col :span="17"> <a-col :span="17">
<a-button type="primary" style="width: 100%" :loading="islogin" round size="large" @click="submitReset">{{ <a-button type="primary" class="xn-wd" :loading="islogin" round size="large" @click="submitReset">{{
$t('login.restPassword') $t('login.restPassword')
}}</a-button> }}</a-button>
</a-col> </a-col>
@ -54,7 +54,7 @@
</a-form-item> </a-form-item>
</a-form> </a-form>
<a-modal <a-modal
v-model:visible="visible" v-model:open="visible"
:width="400" :width="400"
:title="$t('login.machineValidation')" :title="$t('login.machineValidation')"
@cancel="handleCancel" @cancel="handleCancel"
@ -70,16 +70,12 @@
size="large" size="large"
> >
<template #prefix> <template #prefix>
<verified-outlined style="color: rgba(0, 0, 0, 0.25)" /> <verified-outlined class="xn-color-00025" />
</template> </template>
</a-input> </a-input>
</a-col> </a-col>
<a-col :span="7"> <a-col :span="7">
<img <img :src="validCodeBase64" class="xn-findform-line" @click="getPhonePicCaptcha" />
:src="validCodeBase64"
style="border: 1px solid var(--border-color-split); cursor: pointer; width: 100%; height: 40px"
@click="getPhonePicCaptcha"
/>
</a-col> </a-col>
</a-row> </a-row>
</a-form-item> </a-form-item>
@ -122,23 +118,26 @@
formRules.value.phoneValidCode = [required(), rules.number] formRules.value.phoneValidCode = [required(), rules.number]
formRules.value.newPassword = [required()] formRules.value.newPassword = [required()]
phoneLoginFormRef.value.validate().then(() => { phoneLoginFormRef.value
phoneFormData.value.validCode = phoneFormData.value.phoneValidCode .validate()
phoneFormData.value.validCodeReqNo = phoneValidCodeReqNo.value .then(() => {
phoneFormData.value.newPassword = smCrypto.doSm2Encrypt(phoneFormData.value.newPassword) phoneFormData.value.validCode = phoneFormData.value.phoneValidCode
islogin.value = true phoneFormData.value.validCodeReqNo = phoneValidCodeReqNo.value
userCenterApi phoneFormData.value.newPassword = smCrypto.doSm2Encrypt(phoneFormData.value.newPassword)
.userFindPasswordByPhone(phoneFormData.value) islogin.value = true
.then(() => { userCenterApi
router.replace({ .userFindPasswordByPhone(phoneFormData.value)
path: '/' .then(() => {
router.replace({
path: '/'
})
message.success('找回成功')
}) })
message.success('找回成功') .finally(() => {
}) islogin.value = false
.finally(() => { })
islogin.value = false })
}) .catch(() => {})
})
} }
// //

View File

@ -78,7 +78,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a href="/findpwd" style="color: #0d84ff">{{ $t('login.forgetPassword') }}</a> <a href="/findpwd" class="xn-color-0d84ff">{{ $t('login.forgetPassword') }}</a>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" class="w-full" :loading="loading" round size="large" @click="login" <a-button type="primary" class="w-full" :loading="loading" round size="large" @click="login"
@ -213,24 +213,36 @@
// //
const loginForm = ref() const loginForm = ref()
const login = async () => { const login = async () => {
loginForm.value.validate().then(async () => { loginForm.value
loading.value = true .validate()
const loginData = { .then(async () => {
account: ruleForm.account, loading.value = true
// SM2使hash const loginData = {
password: smCrypto.doSm2Encrypt(ruleForm.password), account: ruleForm.account,
validCode: ruleForm.validCode, // SM2使hash
validCodeReqNo: ruleForm.validCodeReqNo password: smCrypto.doSm2Encrypt(ruleForm.password),
} validCode: ruleForm.validCode,
// token validCodeReqNo: ruleForm.validCodeReqNo
try { }
const loginToken = await loginApi.login(loginData)
afterLogin(loginToken) // token
} catch (err) { // loginApi.login(loginData).then((loginToken) => {
loading.value = false // afterLogin(loginToken)
loginCaptcha() // }).catch(() => {
} // loading.value = false
}) // loginCaptcha()
// })
// token
try {
const loginToken = await loginApi.login(loginData)
const loginAfter = afterLogin(loginToken)
} catch (err) {
loading.value = false
loginCaptcha()
}
})
.catch(() => {})
} }
const configLang = (key) => { const configLang = (key) => {
config.value.lang = key config.value.lang = key
@ -238,4 +250,7 @@
</script> </script>
<style lang="less"> <style lang="less">
@import 'login'; @import 'login';
.xn-color-0d84ff {
color: #0d84ff;
}
</style> </style>

View File

@ -21,20 +21,20 @@
</a-input> </a-input>
</a-col> </a-col>
<a-col :span="7"> <a-col :span="7">
<a-button size="large" style="width: 100%" @click="getPhoneValidCode" :disabled="state.smsSendBtn"> <a-button size="large" class="xn-wd" @click="getPhoneValidCode" :disabled="state.smsSendBtn">
{{ (!state.smsSendBtn && $t('login.getSmsCode')) || state.time + ' s' }} {{ (!state.smsSendBtn && $t('login.getSmsCode')) || state.time + ' s' }}
</a-button> </a-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" style="width: 100%" :loading="loading" round size="large" @click="submitLogin"> <a-button type="primary" class="xn-wd" :loading="loading" round size="large" @click="submitLogin">
{{ $t('login.signIn') }} {{ $t('login.signIn') }}
</a-button> </a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
<a-modal <a-modal
v-model:visible="visible" v-model:open="visible"
:width="400" :width="400"
:title="$t('login.machineValidation')" :title="$t('login.machineValidation')"
@cancel="handleCancel" @cancel="handleCancel"
@ -57,7 +57,7 @@
<a-col :span="7"> <a-col :span="7">
<img <img
:src="validCodeBase64" :src="validCodeBase64"
style="border: 1px solid var(--border-color-split); cursor: pointer; width: 100%; height: 40px" class="xn-findform-line"
@click="getPhonePicCaptcha" @click="getPhonePicCaptcha"
/> />
</a-col> </a-col>
@ -94,6 +94,7 @@
getPhonePicCaptcha() getPhonePicCaptcha()
}) })
} }
// //
const submitLogin = async () => { const submitLogin = async () => {
formRules.value.phone = [required('请输入11位手机号'), rules.phone] formRules.value.phone = [required('请输入11位手机号'), rules.phone]
@ -105,14 +106,12 @@
phoneFormData.value.validCode = phoneFormData.value.phoneValidCode phoneFormData.value.validCode = phoneFormData.value.phoneValidCode
// delete phoneFormData.value.phoneValidCode // delete phoneFormData.value.phoneValidCode
phoneFormData.value.validCodeReqNo = phoneValidCodeReqNo.value phoneFormData.value.validCodeReqNo = phoneValidCodeReqNo.value
loading.value = true loading.value = true
try { loginApi.loginByPhone(phoneFormData.value).then((token) => {
const token = await loginApi.loginByPhone(phoneFormData.value)
afterLogin(token) afterLogin(token)
} catch (err) { }).catch((err) => {
loading.value = false loading.value = false
} })
} }
// //

View File

@ -1,5 +1,5 @@
<template> <template>
<div style="padding-bottom: 10px"> <div class="xn-pb10">
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :span="6"> <a-col :span="6">
<a-card class="snowy-monitor-card" :bordered="false"> <a-card class="snowy-monitor-card" :bordered="false">
@ -15,7 +15,7 @@
<a-col :span="6"> <a-col :span="6">
<a-card class="snowy-monitor-card" :bordered="false"> <a-card class="snowy-monitor-card" :bordered="false">
<template #cover> <template #cover>
<verified-outlined style="color: rgb(255, 156, 110)" class="snowy-monitor-card-icon" /> <verified-outlined class="snowy-monitor-card-icon xn-color-ff9c6e" />
<div class="snowy-monitor-card-div"> <div class="snowy-monitor-card-div">
<span class="snowy-monitor-card-span">最大签发令牌</span <span class="snowy-monitor-card-span">最大签发令牌</span
><span class="snowy-monitor-card-span">{{ analysisObj.maxTokenCount }}</span> ><span class="snowy-monitor-card-span">{{ analysisObj.maxTokenCount }}</span>
@ -26,7 +26,7 @@
<a-col :span="6"> <a-col :span="6">
<a-card class="snowy-monitor-card" :bordered="false"> <a-card class="snowy-monitor-card" :bordered="false">
<template #cover> <template #cover>
<rise-outlined style="color: rgb(255, 133, 192)" class="snowy-monitor-card-icon" /> <rise-outlined class="snowy-monitor-card-icon xn-color-ff85c0" />
<div class="snowy-monitor-card-div"> <div class="snowy-monitor-card-div">
<span class="snowy-monitor-card-span">1小时内新增</span <span class="snowy-monitor-card-span">1小时内新增</span
><span class="snowy-monitor-card-span">{{ analysisObj.oneHourNewlyAdded }}</span> ><span class="snowy-monitor-card-span">{{ analysisObj.oneHourNewlyAdded }}</span>
@ -37,7 +37,7 @@
<a-col :span="6"> <a-col :span="6">
<a-card class="snowy-monitor-card" :bordered="false"> <a-card class="snowy-monitor-card" :bordered="false">
<template #cover> <template #cover>
<pie-chart-outlined style="color: rgb(92, 219, 211)" class="snowy-monitor-card-icon" /> <pie-chart-outlined class="snowy-monitor-card-icon xn-color-5cdbd3" />
<div class="snowy-monitor-card-div"> <div class="snowy-monitor-card-div">
<span class="snowy-monitor-card-span">B/C端占比</span <span class="snowy-monitor-card-span">B/C端占比</span
><span class="snowy-monitor-card-span">{{ analysisObj.proportionOfBAndC }}</span> ><span class="snowy-monitor-card-span">{{ analysisObj.proportionOfBAndC }}</span>
@ -80,4 +80,13 @@
.snowy-monitor-card-span { .snowy-monitor-card-span {
font-size: 16px; font-size: 16px;
} }
.xn-color-ff9c6e {
color: #ff9c6e;
}
.xn-color-ff85c0 {
color: #ff85c0;
}
.xn-color-5cdbd3 {
color: #5cdbd3;
}
</style> </style>

View File

@ -2,7 +2,7 @@
<s-table ref="tableRef" :columns="columns" :data="loadDataB" :alert="false" bordered :row-key="(record) => record.id"> <s-table ref="tableRef" :columns="columns" :data="loadDataB" :alert="false" bordered :row-key="(record) => record.id">
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'avatar'"> <template v-if="column.dataIndex === 'avatar'">
<a-avatar :src="record.avatar" style="width: 25px; height: 25px" /> <a-avatar :src="record.avatar" class="xn-wh25" />
</template> </template>
<template v-if="column.dataIndex === 'tokenNumber'"> <template v-if="column.dataIndex === 'tokenNumber'">
{{ record.tokenSignList.length }} {{ record.tokenSignList.length }}

View File

@ -2,7 +2,7 @@
<s-table ref="tableRef" :columns="columns" :data="loadDataC" :alert="false" bordered :row-key="(record) => record.id"> <s-table ref="tableRef" :columns="columns" :data="loadDataC" :alert="false" bordered :row-key="(record) => record.id">
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'avatar'"> <template v-if="column.dataIndex === 'avatar'">
<a-avatar :src="record.avatar" style="width: 25px; height: 25px" /> <a-avatar :src="record.avatar" class="xn-wh25" />
</template> </template>
<template v-if="column.dataIndex === 'tokenNumber'"> <template v-if="column.dataIndex === 'tokenNumber'">
{{ record.tokenSignList.length }} {{ record.tokenSignList.length }}

View File

@ -2,7 +2,7 @@
<xn-form-container title="令牌列表" :width="650" :visible="visible" :destroy-on-close="true" @close="onClose"> <xn-form-container title="令牌列表" :width="650" :visible="visible" :destroy-on-close="true" @close="onClose">
<a-button <a-button
danger danger
style="margin-bottom: 10px" class="xn-mb10"
:disabled="selectedRowKeys.length === 0" :disabled="selectedRowKeys.length === 0"
:loading="beatchExitLoading" :loading="beatchExitLoading"
@click="beachExitTokenValue" @click="beachExitTokenValue"
@ -14,6 +14,7 @@
:row-selection="rowSelection" :row-selection="rowSelection"
bordered bordered
:row-key="(record) => record.tokenValue" :row-key="(record) => record.tokenValue"
size="small"
> >
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'tokenDevice'"> <template v-if="column.dataIndex === 'tokenDevice'">

View File

@ -3,7 +3,7 @@
<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form"> <a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="8"> <a-col :span="8">
<a-form-item label="关键" name="searchKey"> <a-form-item label="关键" name="searchKey">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入用户名或昵称关键词"></a-input> <a-input v-model:value="searchFormState.searchKey" placeholder="请输入用户名或昵称关键词"></a-input>
</a-form-item> </a-form-item>
</a-col> </a-col>
@ -15,7 +15,7 @@
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6">
<a-button type="primary" @click="tableRef.refresh(true)"></a-button> <a-button type="primary" @click="tableRef.refresh(true)"></a-button>
<a-button style="margin: 0 8px" @click="reset"></a-button> <a-button class="xn-mg08" @click="reset"></a-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>

View File

@ -6,7 +6,7 @@
:disabled="true" :disabled="true"
v-model:value="formData.parentId" v-model:value="formData.parentId"
v-model:treeExpandedKeys="defaultExpandedKeys" v-model:treeExpandedKeys="defaultExpandedKeys"
style="width: 100%" class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级字典" placeholder="请选择上级字典"
allow-clear allow-clear
@ -27,11 +27,11 @@
<a-input v-model:value="formData.dictValue" placeholder="请输入字典值" allow-clear :disabled="true" /> <a-input v-model:value="formData.dictValue" placeholder="请输入字典值" allow-clear :disabled="true" />
</a-form-item> </a-form-item>
<a-form-item label="排序:" name="sortCode"> <a-form-item label="排序:" name="sortCode">
<a-input-number style="width: 100%" v-model:value="formData.sortCode" :max="1000" /> <a-input-number class="xn-wd" v-model:value="formData.sortCode" :max="1000" />
</a-form-item> </a-form-item>
</a-form> </a-form>
<template #footer> <template #footer>
<a-button style="margin-right: 8px" @click="onClose"></a-button> <a-button class="xn-mr8" @click="onClose"></a-button>
<a-button type="primary" @click="onSubmit"></a-button> <a-button type="primary" @click="onSubmit"></a-button>
</template> </template>
</xn-form-container> </xn-form-container>
@ -94,12 +94,15 @@
}) })
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
bizDictApi.submitForm(formData.value).then(() => { .validate()
visible.value = false .then(() => {
emit('successful') bizDictApi.submitForm(formData.value).then(() => {
visible.value = false
emit('successful')
})
}) })
}) .catch(() => {})
} }
// //
defineExpose({ defineExpose({

View File

@ -13,7 +13,7 @@
</a-card> </a-card>
</a-col> </a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="19" :xl="19"> <a-col :xs="24" :sm="24" :md="24" :lg="19" :xl="19">
<a-card :bordered="false" style="margin-bottom: 10px"> <a-card :bordered="false" class="xn-mb10">
<a-form <a-form
ref="searchFormRef" ref="searchFormRef"
name="advanced_search" name="advanced_search"
@ -39,7 +39,7 @@
</a-row> </a-row>
</a-form> </a-form>
</a-card> </a-card>
<a-card :bordered="false" style="margin-bottom: 10px"> <a-card :bordered="false" class="xn-mb10">
<s-table <s-table
ref="tableRef" ref="tableRef"
:columns="columns" :columns="columns"

View File

@ -10,7 +10,7 @@
<a-form-item label="上级机构:" name="parentId"> <a-form-item label="上级机构:" name="parentId">
<a-tree-select <a-tree-select
v-model:value="formData.parentId" v-model:value="formData.parentId"
style="width: 100%" class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级机构" placeholder="请选择上级机构"
allow-clear allow-clear
@ -32,33 +32,27 @@
<a-select <a-select
v-model:value="formData.category" v-model:value="formData.category"
:options="orgCategoryOptions" :options="orgCategoryOptions"
style="width: 100%" class="xn-wd"
placeholder="请选择机构分类" placeholder="请选择机构分类"
/> />
</a-form-item> </a-form-item>
<a-form-item label="排序:" name="sortCode"> <a-form-item label="排序:" name="sortCode">
<a-input-number style="width: 100%" v-model:value="formData.sortCode" :max="100" /> <a-input-number class="xn-wd" v-model:value="formData.sortCode" :max="100" />
</a-form-item> </a-form-item>
<a-form-item label="指定主管:" name="directorId"> <a-form-item label="指定主管:" name="directorId">
<a-button type="link" style="padding-left: 0px" @click="openSelector(formData.directorId)"></a-button> <xn-user-selector
<a-tag v-if="formData.directorId && formData.directorName" color="orange" closable @close="closeUserTag">{{ :org-tree-api="selectorApiFunction.orgTreeApi"
formData.directorName :user-page-api="selectorApiFunction.userPageApi"
}}</a-tag> :user-list-by-id-list-api="selectorApiFunction.checkedUserListApi"
<a-input v-show="false" v-model:value="formData.directorId" /> :radio-model="true"
v-model:value="formData.directorId"
/>
</a-form-item> </a-form-item>
</a-form> </a-form>
<template #footer> <template #footer>
<a-button style="margin-right: 8px" @click="onClose"></a-button> <a-button class="xn-mr8" @click="onClose"></a-button>
<a-button type="primary" :loading="submitLoading" @click="onSubmit"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit"></a-button>
</template> </template>
<user-selector-plus
ref="UserSelectorPlus"
:org-tree-api="selectorApiFunction.orgTreeApi"
:user-page-api="selectorApiFunction.userPageApi"
:checked-user-list-api="selectorApiFunction.checkedUserListApi"
:radio-model="true"
@onBack="userBack"
/>
</xn-form-container> </xn-form-container>
</template> </template>
@ -66,14 +60,12 @@
import { required } from '@/utils/formRules' import { required } from '@/utils/formRules'
import bizOrgApi from '@/api/biz/bizOrgApi' import bizOrgApi from '@/api/biz/bizOrgApi'
import userCenterApi from '@/api/sys/userCenterApi' import userCenterApi from '@/api/sys/userCenterApi'
import userSelectorPlus from '@/components/Selector/userSelectorPlus.vue'
import tool from '@/utils/tool' import tool from '@/utils/tool'
// emit // emit
const emit = defineEmits({ successful: null }) const emit = defineEmits({ successful: null })
// //
const visible = ref(false) const visible = ref(false)
let UserSelectorPlus = ref()
const formRef = ref() const formRef = ref()
// //
const formData = ref({}) const formData = ref({})
@ -116,33 +108,13 @@
} }
// //
const formRules = { const formRules = {
parentId: [required('请选择上级机构')],
name: [required('请输入机构名称')], name: [required('请输入机构名称')],
category: [required('请选择机构分类')], category: [required('请选择机构分类')],
sortCode: [required('请选择排序')] sortCode: [required('请选择排序')]
} }
// //
const orgCategoryOptions = tool.dictList('ORG_CATEGORY') const orgCategoryOptions = tool.dictList('ORG_CATEGORY')
//
const openSelector = (id) => {
let checkedUserIds = []
checkedUserIds.push(id)
UserSelectorPlus.value.showUserPlusModal(checkedUserIds)
}
//
const userBack = (value) => {
if (value.length > 0) {
formData.value.directorId = value[0].id
formData.value.directorName = value[0].name
} else {
formData.value.directorId = ''
formData.value.directorName = ''
}
}
//
const closeUserTag = () => {
formData.value.directorId = ''
formData.value.directorName = ''
}
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value formRef.value

View File

@ -14,7 +14,7 @@
</a-card> </a-card>
</a-col> </a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="19" :xl="19"> <a-col :xs="24" :sm="24" :md="24" :lg="19" :xl="19">
<a-card :bordered="false" style="margin-bottom: 10px"> <a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState"> <a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="8"> <a-col :span="8">
@ -27,7 +27,7 @@
<template #icon><SearchOutlined /></template> <template #icon><SearchOutlined /></template>
查询 查询
</a-button> </a-button>
<a-button class="snowy-buttom-left" @click="reset"> <a-button class="snowy-button-left" @click="reset">
<template #icon><redo-outlined /></template> <template #icon><redo-outlined /></template>
重置 重置
</a-button> </a-button>
@ -213,10 +213,7 @@
.ant-form-item { .ant-form-item {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
.primaryAdd { .snowy-button-left {
margin-right: 10px;
}
.snowy-buttom-left {
margin-left: 8px; margin-left: 8px;
} }
</style> </style>

View File

@ -10,7 +10,7 @@
<a-form-item label="所属组织:" name="orgId"> <a-form-item label="所属组织:" name="orgId">
<a-tree-select <a-tree-select
v-model:value="formData.orgId" v-model:value="formData.orgId"
style="width: 100%" class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择组织" placeholder="请选择组织"
allow-clear allow-clear
@ -32,17 +32,17 @@
<a-select <a-select
v-model:value="formData.category" v-model:value="formData.category"
:options="positionCategoryOptions" :options="positionCategoryOptions"
style="width: 100%" class="xn-wd"
placeholder="请选择岗位分类" placeholder="请选择岗位分类"
> >
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item label="排序:" name="sortCode"> <a-form-item label="排序:" name="sortCode">
<a-input-number style="width: 100%" v-model:value="formData.sortCode" :max="100" /> <a-input-number class="xn-wd" v-model:value="formData.sortCode" :max="100" />
</a-form-item> </a-form-item>
</a-form> </a-form>
<template #footer> <template #footer>
<a-button style="margin-right: 8px" @click="onClose"></a-button> <a-button class="xn-mr8" @click="onClose"></a-button>
<a-button type="primary" :loading="submitLoading" @click="onSubmit"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit"></a-button>
</template> </template>
</xn-form-container> </xn-form-container>

View File

@ -14,7 +14,7 @@
</a-card> </a-card>
</a-col> </a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="19" :xl="19"> <a-col :xs="24" :sm="24" :md="24" :lg="19" :xl="19">
<a-card :bordered="false" style="margin-bottom: 10px"> <a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState"> <a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="8"> <a-col :span="8">
@ -27,7 +27,7 @@
<template #icon><SearchOutlined /></template> <template #icon><SearchOutlined /></template>
查询 查询
</a-button> </a-button>
<a-button class="snowy-buttom-left" @click="reset"> <a-button class="snowy-button-left" @click="reset">
<template #icon><redo-outlined /></template> <template #icon><redo-outlined /></template>
重置 重置
</a-button> </a-button>
@ -210,10 +210,7 @@
.ant-form-item { .ant-form-item {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
.primaryAdd { .snowy-button-left {
margin-right: 10px;
}
.snowy-buttom-left {
margin-left: 8px; margin-left: 8px;
} }
</style> </style>

View File

@ -49,7 +49,7 @@
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :span="12"> <a-col :span="12">
<a-form-item label="出生日期:" name="birthday"> <a-form-item label="出生日期:" name="birthday">
<a-date-picker v-model:value="formData.birthday" value-format="YYYY-MM-DD" style="width: 100%" /> <a-date-picker v-model:value="formData.birthday" value-format="YYYY-MM-DD" class="xn-wd" />
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@ -58,7 +58,7 @@
<a-form-item label="选择组织:" name="orgId"> <a-form-item label="选择组织:" name="orgId">
<a-tree-select <a-tree-select
v-model:value="formData.orgId" v-model:value="formData.orgId"
style="width: 100%" class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择组织" placeholder="请选择组织"
allow-clear allow-clear
@ -112,7 +112,7 @@
</a-col> </a-col>
<a-col :span="8"> <a-col :span="8">
<a-form-item label="入职日期:" name="entryDate"> <a-form-item label="入职日期:" name="entryDate">
<a-date-picker v-model:value="formData.entryDate" value-format="YYYY-MM-DD" style="width: 100%" /> <a-date-picker v-model:value="formData.entryDate" value-format="YYYY-MM-DD" class="xn-wd" />
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@ -137,7 +137,7 @@
> >
<a-tree-select <a-tree-select
v-model:value="positionInfo.orgId" v-model:value="positionInfo.orgId"
style="width: 100%" class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择机构" placeholder="请选择机构"
allow-clear allow-clear
@ -176,7 +176,7 @@
/> />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="3" style="margin-top: 4px"> <a-col :span="3" class="xn-mt4">
<a-button size="small" type="primary" danger ghost @click="delDomains(index)"></a-button> <a-button size="small" type="primary" danger ghost @click="delDomains(index)"></a-button>
</a-col> </a-col>
</a-row> </a-row>
@ -316,13 +316,13 @@
</a-tabs> </a-tabs>
</a-form> </a-form>
<template #footer> <template #footer>
<a-button style="margin-right: 8px" @click="onClose"></a-button> <a-button class="xn-mr8" @click="onClose"></a-button>
<a-button type="primary" :loading="formLoading" @click="onSubmit"></a-button> <a-button type="primary" :loading="formLoading" @click="onSubmit"></a-button>
</template> </template>
</xn-form-container> </xn-form-container>
</template> </template>
<script setup> <script setup name="bizUser">
import bizUserApi from '@/api/biz/bizUserApi' import bizUserApi from '@/api/biz/bizUserApi'
import { required } from '@/utils/formRules' import { required } from '@/utils/formRules'
import tool from '@/utils/tool' import tool from '@/utils/tool'
@ -507,25 +507,28 @@
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
// .validate()
let formDatas = JSON.parse(JSON.stringify(formData.value)) .then(() => {
if (formDatas.positionJson && formDatas.positionJson.length > 0) { //
formDatas.positionJson = JSON.stringify(formDatas.positionJson) let formDatas = JSON.parse(JSON.stringify(formData.value))
} else { if (formDatas.positionJson && formDatas.positionJson.length > 0) {
delete formDatas.positionJson formDatas.positionJson = JSON.stringify(formDatas.positionJson)
} } else {
formLoading.value = true delete formDatas.positionJson
bizUserApi }
.submitForm(formDatas, formDatas.id) formLoading.value = true
.then(() => { bizUserApi
onClose() .submitForm(formDatas, formDatas.id)
emit('successful') .then(() => {
}) onClose()
.finally(() => { emit('successful')
formLoading.value = false })
}) .finally(() => {
}) formLoading.value = false
})
})
.catch(() => {})
} }
// //
const genderOptions = tool.dictList('GENDER') const genderOptions = tool.dictList('GENDER')

View File

@ -14,7 +14,7 @@
</a-card> </a-card>
</a-col> </a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="19" :xl="19"> <a-col :xs="24" :sm="24" :md="24" :lg="19" :xl="19">
<a-card :bordered="false" style="margin-bottom: 10px"> <a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState"> <a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="8"> <a-col :span="8">
@ -39,7 +39,7 @@
<template #icon><SearchOutlined /></template> <template #icon><SearchOutlined /></template>
{{ $t('common.searchButton') }} {{ $t('common.searchButton') }}
</a-button> </a-button>
<a-button class="snowy-buttom-left" @click="reset"> <a-button class="snowy-button-left" @click="reset">
<template #icon><redo-outlined /></template> <template #icon><redo-outlined /></template>
{{ $t('common.resetButton') }} {{ $t('common.resetButton') }}
</a-button> </a-button>
@ -418,14 +418,11 @@
.ant-form-item { .ant-form-item {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
.primaryAdd {
margin-right: 10px;
}
.snowy-table-avatar { .snowy-table-avatar {
margin-top: -10px; margin-top: -10px;
margin-bottom: -10px; margin-bottom: -10px;
} }
.snowy-buttom-left { .snowy-button-left {
margin-left: 8px; margin-left: 8px;
} }
</style> </style>

View File

@ -19,7 +19,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="() => formRef.resetFields()">重置</a-button> <a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>
@ -59,22 +59,25 @@
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
submitLoading.value = true .validate()
let submitParam = cloneDeep(formData.value) .then(() => {
const param = Object.entries(submitParam).map((item) => { submitLoading.value = true
return { let submitParam = cloneDeep(formData.value)
configKey: item[0], const param = Object.entries(submitParam).map((item) => {
configValue: item[1] return {
} configKey: item[0],
}) configValue: item[1]
configApi }
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
}) })
}) configApi
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
} }
const layout = { const layout = {
labelCol: { labelCol: {

View File

@ -16,7 +16,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="() => formRef.resetFields()">重置</a-button> <a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>
@ -55,22 +55,25 @@
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
submitLoading.value = true .validate()
let submitParam = cloneDeep(formData.value) .then(() => {
const param = Object.entries(submitParam).map((item) => { submitLoading.value = true
return { let submitParam = cloneDeep(formData.value)
configKey: item[0], const param = Object.entries(submitParam).map((item) => {
configValue: item[1] return {
} configKey: item[0],
}) configValue: item[1]
configApi }
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
}) })
}) configApi
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
} }
const layout = { const layout = {
labelCol: { labelCol: {

View File

@ -19,7 +19,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="() => formRef.resetFields()">重置</a-button> <a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>

View File

@ -22,7 +22,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="() => formRef.resetFields()">重置</a-button> <a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>
@ -63,22 +63,25 @@
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
submitLoading.value = true .validate()
let submitParam = cloneDeep(formData.value) .then(() => {
const param = Object.entries(submitParam).map((item) => { submitLoading.value = true
return { let submitParam = cloneDeep(formData.value)
configKey: item[0], const param = Object.entries(submitParam).map((item) => {
configValue: item[1] return {
} configKey: item[0],
}) configValue: item[1]
configApi }
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
}) })
}) configApi
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
} }
const layout = { const layout = {
labelCol: { labelCol: {

View File

@ -16,7 +16,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="() => formRef.resetFields()">重置</a-button> <a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>
@ -55,22 +55,25 @@
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
submitLoading.value = true .validate()
let submitParam = cloneDeep(formData.value) .then(() => {
const param = Object.entries(submitParam).map((item) => { submitLoading.value = true
return { let submitParam = cloneDeep(formData.value)
configKey: item[0], const param = Object.entries(submitParam).map((item) => {
configValue: item[1] return {
} configKey: item[0],
}) configValue: item[1]
configApi }
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
}) })
}) configApi
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
} }
const layout = { const layout = {
labelCol: { labelCol: {

View File

@ -22,7 +22,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="() => formRef.resetFields()">重置</a-button> <a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>
@ -63,22 +63,25 @@
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
submitLoading.value = true .validate()
let submitParam = cloneDeep(formData.value) .then(() => {
const param = Object.entries(submitParam).map((item) => { submitLoading.value = true
return { let submitParam = cloneDeep(formData.value)
configKey: item[0], const param = Object.entries(submitParam).map((item) => {
configValue: item[1] return {
} configKey: item[0],
}) configValue: item[1]
configApi }
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
}) })
}) configApi
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
} }
const layout = { const layout = {
labelCol: { labelCol: {

View File

@ -22,7 +22,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="() => formRef.resetFields()">重置</a-button> <a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>
@ -63,22 +63,25 @@
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
submitLoading.value = true .validate()
let submitParam = cloneDeep(formData.value) .then(() => {
const param = Object.entries(submitParam).map((item) => { submitLoading.value = true
return { let submitParam = cloneDeep(formData.value)
configKey: item[0], const param = Object.entries(submitParam).map((item) => {
configValue: item[1] return {
} configKey: item[0],
}) configValue: item[1]
configApi }
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
}) })
}) configApi
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
} }
const layout = { const layout = {
labelCol: { labelCol: {

View File

@ -1,6 +1,6 @@
<template> <template>
<a-card <a-card
style="width: 100%" class="xn-wd"
:bordered="false" :bordered="false"
:tab-list="tabListNoTitle" :tab-list="tabListNoTitle"
:active-tab-key="noTitleKey" :active-tab-key="noTitleKey"

View File

@ -21,11 +21,11 @@
<a-input v-model:value="formData.remark" placeholder="请输入备注" allow-clear /> <a-input v-model:value="formData.remark" placeholder="请输入备注" allow-clear />
</a-form-item> </a-form-item>
<a-form-item label="排序:" name="sortCode"> <a-form-item label="排序:" name="sortCode">
<a-input-number style="width: 100%" v-model:value="formData.sortCode" :max="1000" /> <a-input-number class="xn-wd" v-model:value="formData.sortCode" :max="1000" />
</a-form-item> </a-form-item>
</a-form> </a-form>
<template #footer> <template #footer>
<a-button style="margin-right: 8px" @click="onClose"></a-button> <a-button class="xn-mr8" @click="onClose"></a-button>
<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button> <a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
</template> </template>
</xn-form-container> </xn-form-container>
@ -66,18 +66,21 @@
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
submitLoading.value = true .validate()
configApi .then(() => {
.submitForm(formData.value, formData.value.id) submitLoading.value = true
.then(() => { configApi
onClose() .submitForm(formData.value, formData.value.id)
emit('successful') .then(() => {
}) onClose()
.finally(() => { emit('successful')
submitLoading.value = false })
}) .finally(() => {
}) submitLoading.value = false
})
})
.catch(() => {})
} }
// //

View File

@ -18,7 +18,7 @@
</a-button> </a-button>
<a-input-search <a-input-search
v-model:value="searchFormState.searchKey" v-model:value="searchFormState.searchKey"
placeholder="请输入关键" placeholder="请输入关键"
enter-button enter-button
allowClear allowClear
@search="tableRef.refresh(true)" @search="tableRef.refresh(true)"

View File

@ -22,7 +22,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="() => formRef.resetFields()">重置</a-button> <a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>
@ -63,22 +63,25 @@
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
submitLoading.value = true .validate()
let submitParam = cloneDeep(formData.value) .then(() => {
const param = Object.entries(submitParam).map((item) => { submitLoading.value = true
return { let submitParam = cloneDeep(formData.value)
configKey: item[0], const param = Object.entries(submitParam).map((item) => {
configValue: item[1] return {
} configKey: item[0],
}) configValue: item[1]
configApi }
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
}) })
}) configApi
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
} }
const layout = { const layout = {
labelCol: { labelCol: {

View File

@ -1,16 +1,20 @@
<template> <template>
<a-tabs v-model:activeKey="activeKey" tab-position="left"> <a-tabs v-model:activeKey="activeKey" tab-position="left">
<a-tab-pane key="xiaonuoSms" tab="小诺短信">
<xiaonuo-sms-form />
</a-tab-pane>
<a-tab-pane key="aliyunSms" tab="阿里短信"> <a-tab-pane key="aliyunSms" tab="阿里短信">
<aliyunSmsForm /> <aliyun-sms-form />
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="tencentSms" tab="腾讯短信"> <a-tab-pane key="tencentSms" tab="腾讯短信">
<tencentSmsForm /> <tencent-sms-form />
</a-tab-pane> </a-tab-pane>
</a-tabs> </a-tabs>
</template> </template>
<script setup name="smsConfig"> <script setup name="smsConfig">
import XiaonuoSmsForm from './xiaonuoSmsForm.vue'
import AliyunSmsForm from './aliyunSmsForm.vue' import AliyunSmsForm from './aliyunSmsForm.vue'
import TencentSmsForm from './tencentSmsForm.vue' import TencentSmsForm from './tencentSmsForm.vue'
const activeKey = ref('aliyunSms') const activeKey = ref('xiaonuoSms')
</script> </script>

View File

@ -25,7 +25,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="() => formRef.resetFields()">重置</a-button> <a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>
@ -67,22 +67,25 @@
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
submitLoading.value = true .validate()
let submitParam = cloneDeep(formData.value) .then(() => {
const param = Object.entries(submitParam).map((item) => { submitLoading.value = true
return { let submitParam = cloneDeep(formData.value)
configKey: item[0], const param = Object.entries(submitParam).map((item) => {
configValue: item[1] return {
} configKey: item[0],
}) configValue: item[1]
configApi }
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
}) })
}) configApi
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
} }
const layout = { const layout = {
labelCol: { labelCol: {

View File

@ -0,0 +1,108 @@
<template>
<a-spin :spinning="loadSpinning">
<a-form
ref="formRef"
:model="formData"
:rules="formRules"
layout="vertical"
:label-col="{ ...layout.labelCol, offset: 0 }"
:wrapper-col="{ ...layout.wrapperCol, offset: 0 }"
>
<a-form-item name="SNOWY_SMS_XIAONUO_ACCESS_KEY_ID">
<template #label>
<a-tooltip>
<template #title> 通过官网申请短信或联系站长 </template>
<question-circle-outlined />
</a-tooltip>
&nbsp 小诺短信账号
</template>
<a-input v-model:value="formData.SNOWY_SMS_XIAONUO_ACCESS_KEY_ID" placeholder="请输入小诺短信账号" />
</a-form-item>
<a-form-item label="小诺短信秘钥:" name="SNOWY_SMS_XIAONUO_ACCESS_KEY_SECRET">
<a-input v-model:value="formData.SNOWY_SMS_XIAONUO_ACCESS_KEY_SECRET" placeholder="请输入小诺短信秘钥" />
</a-form-item>
<a-form-item label="发送短信URL" name="SNOWY_SMS_XIAONUO_REQUEST_URL">
<a-input v-model:value="formData.SNOWY_SMS_XIAONUO_REQUEST_URL" placeholder="请输入发送短信URL" />
</a-form-item>
<a-form-item name="SNOWY_SMS_XIAONUO_DEFAULT_SIGN_NAME">
<template #label>
<a-tooltip>
<template #title> 若账号跟密钥已绑定签名则此处配置签名后无效 </template>
<question-circle-outlined />
</a-tooltip>
&nbsp 短信签名
</template>
<a-input v-model:value="formData.SNOWY_SMS_XIAONUO_DEFAULT_SIGN_NAME" placeholder="请输入短信签名" />
</a-form-item>
<a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item>
</a-form>
</a-spin>
</template>
<script setup name="xiaonuoSmsForm">
import { cloneDeep } from 'lodash-es'
import { required } from '@/utils/formRules'
import { message } from 'ant-design-vue'
import configApi from '@/api/dev/configApi'
const formRef = ref()
const formData = ref({})
const submitLoading = ref(false)
const loadSpinning = ref(true)
// ,
const param = {
category: 'SMS_XIAONUO'
}
configApi.configList(param).then((data) => {
loadSpinning.value = false
if (data) {
data.forEach((item) => {
formData.value[item.configKey] = item.configValue
})
} else {
message.warning('表单项不存在,请初始化数据库')
}
})
//
const formRules = {
SNOWY_SMS_XIAONUO_ACCESS_KEY_ID: [required('请输入小诺短信账号')],
SNOWY_SMS_XIAONUO_ACCESS_KEY_SECRET: [required('请输入小诺短信秘钥')],
SNOWY_SMS_XIAONUO_REQUEST_URL: [required('请输入发送短信URL')],
SNOWY_SMS_XIAONUO_DEFAULT_SIGN_NAME: [required('请输入短信签名')]
}
//
const onSubmit = () => {
formRef.value
.validate()
.then(() => {
submitLoading.value = true
let submitParam = cloneDeep(formData.value)
const param = Object.entries(submitParam).map((item) => {
return {
configKey: item[0],
configValue: item[1]
}
})
configApi
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
}
const layout = {
labelCol: {
span: 4
},
wrapperCol: {
span: 12
}
}
</script>

View File

@ -88,7 +88,7 @@
<a-col :span="24"> <a-col :span="24">
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="resetForm"></a-button> <a-button class="xn-ml10" @click="resetForm"></a-button>
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
@ -100,6 +100,7 @@
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { required } from '@/utils/formRules' import { required } from '@/utils/formRules'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { globalStore } from '@/store'
import configApi from '@/api/dev/configApi' import configApi from '@/api/dev/configApi'
import tool from '@/utils/tool' import tool from '@/utils/tool'
import MenuTreeSelect from '@/components/TreeSelect/menuTreeSelect.vue' import MenuTreeSelect from '@/components/TreeSelect/menuTreeSelect.vue'
@ -113,6 +114,7 @@
const imageUrl = ref('') const imageUrl = ref('')
const menuTreeSelectRef = ref() const menuTreeSelectRef = ref()
const loadSpinning = ref(true) const loadSpinning = ref(true)
const store = globalStore()
// , // ,
const param = { const param = {
category: 'SYS_BASE' category: 'SYS_BASE'
@ -191,6 +193,11 @@
.then(() => { .then(() => {
submitLoading.value = true submitLoading.value = true
let submitParam = cloneDeep(formData.value) let submitParam = cloneDeep(formData.value)
//
const shortcut = {
shortcut: menuTreeSelectRef.value.getSelectData()
}
submitParam.SNOWY_SYS_DEFAULT_WORKBENCH_DATA = JSON.stringify(shortcut)
submitParam.SNOWY_SYS_LOGO = submitParam.SNOWY_SYS_LOGO[0] submitParam.SNOWY_SYS_LOGO = submitParam.SNOWY_SYS_LOGO[0]
const param = Object.entries(submitParam).map((item) => { const param = Object.entries(submitParam).map((item) => {
return { return {
@ -198,17 +205,13 @@
configValue: item[1] configValue: item[1]
} }
}) })
//
const shortcut = {
shortcut: menuTreeSelectRef.value.getSelectData()
}
param.push({
configKey: 'SNOWY_SYS_DEFAULT_WORKBENCH_DATA',
configValue: JSON.stringify(shortcut)
})
configApi configApi
.configEditForm(param) .configEditForm(param)
.then(() => {}) .then(() => {
// 使
tool.data.set('SNOWY_SYS_BASE_CONFIG', submitParam)
store.setSysBaseConfig(submitParam)
})
.finally(() => { .finally(() => {
submitLoading.value = false submitLoading.value = false
}) })

View File

@ -19,7 +19,7 @@
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button> <a-button type="primary" :loading="submitLoading" @click="onSubmit()"></a-button>
<a-button style="margin-left: 10px" @click="() => formRef.resetFields()">重置</a-button> <a-button class="xn-ml10" @click="() => formRef.resetFields()">重置</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>
@ -59,22 +59,25 @@
} }
// //
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate().then(() => { formRef.value
submitLoading.value = true .validate()
let submitParam = cloneDeep(formData.value) .then(() => {
const param = Object.entries(submitParam).map((item) => { submitLoading.value = true
return { let submitParam = cloneDeep(formData.value)
configKey: item[0], const param = Object.entries(submitParam).map((item) => {
configValue: item[1] return {
} configKey: item[0],
}) configValue: item[1]
configApi }
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
}) })
}) configApi
.configEditForm(param)
.then(() => {})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
} }
const layout = { const layout = {
labelCol: { labelCol: {

Some files were not shown because too many files have changed in this diff Show More