Compare commits

...

376 Commits

Author SHA1 Message Date
小诺
39d745536c 【新增】新增前端批量处理按钮(可配置类型、图标、名称),新增正数金额校验规则 2023-04-19 21:55:15 +08:00
小诺
2335f1f34b 【更新】去掉前端加密工具类中的私钥以及基本无用的方法 2023-04-19 21:40:04 +08:00
xiaonuobase
aa8cbb847d 【升级】退出后路由回到登陆前使用的页面,感谢码云 冬天 建议 2023-04-19 17:54:43 +08:00
小诺
3e28c838ee 【更新】字典功能被选中后列表包含自己,且自动区分上下级 2023-04-14 00:25:35 +08:00
xuyuxiang
18ee9d4ec8 【修复】修复过滤器sa-token校验规则bug 2023-04-13 15:06:01 +08:00
jiwangyu
1943c3985f 【修复】修复TinyMCE6段落样式、字体、列表编号控件不显示问题 2023-04-10 05:58:38 +00:00
woyuno
4155d160cb 【优化】过滤器sa-token校验规则优化 2023-04-10 05:08:32 +00:00
guaiwu
95c86975ac 提交postgresql数据库最新的初始化脚本 2023-04-10 04:14:29 +00:00
xiaonuobase
85a96962e0 【更新】操作日志详情高亮组件增加滚动条 2023-04-07 11:44:41 +08:00
xuyuxiang
308d08b81f 【优化】优化角色和用户授权逻辑判断 2023-04-07 11:13:02 +08:00
xiaonuobase
5a46563a47 【更新】授权菜单资源加入提示更改 2023-04-07 11:02:45 +08:00
xiaonuobase
e5d7a8aef4 【更新】授权菜单资源加入提示 2023-04-07 10:51:16 +08:00
小诺
a050e25025 Merge branch 'master' of gitee.com:xiaonuobase/snowy into dev
Signed-off-by: 小诺 <1253070437@qq.com>
2023-04-06 02:27:17 +00:00
xuyuxiang
5b64dd0a07 【修复】修复邮箱校验错误的提示语 2023-04-06 09:23:50 +08:00
xiaonuobase
1521fcc529 【新增】新增左上角折叠菜单功能 2023-04-03 15:01:01 +08:00
小诺
a4cfc69126 【更新】顶部模块坞样式闪动改动 2023-03-29 21:16:11 +08:00
小诺
f24bb37e96 【更新】一个影响其他布局的css调整 2023-03-28 22:27:39 +08:00
徐玉祥
f5f84b1469 【更新】更新sql说明 2023-03-28 19:40:30 +08:00
dongxiayu
ffeb363126 【修复】修复 #I6FSBE 菜单树搜索 bug 2023-03-28 00:23:25 +08:00
小诺
8d43c83eef 【更新】表格{ x: 1200, y: 300 }不生效问题修复 2023-03-27 16:07:50 +00:00
xlzy
21decad50c 【更新】修复清除缓存之后,头像没有更新的问题 2023-03-27 16:07:50 +00:00
小诺
0dc2d9dcf6 【更新】关闭多标签功能后,移除其他被缓存的标签 2023-03-27 16:07:50 +00:00
小诺
89ae5eff78 【优化】调整顶部模块坞间距 2023-03-27 16:07:50 +00:00
xlzy
b845a0c253 【更新】删除无用配置,默认值就是这些 2023-03-27 16:07:50 +00:00
xlzy
9195f0ea36 【更新】显示面包屑时,间距过大 2023-03-27 16:07:50 +00:00
小诺
40d10734a2 【优化】优化css代码格式 2023-03-27 16:07:50 +00:00
xlzy
ac59260a49 【更新】顶部栏应用主题色时修正样式 2023-03-27 16:07:50 +00:00
xlzy
9b5f2502f8 【更新】首页打开控制台的显示优化 2023-03-27 16:07:50 +00:00
小诺
cc06c12f8c 【修复】修复首页两个日志模块超管不显示更多按钮的问题 2023-03-27 16:07:50 +00:00
小诺
183ea32be6 【优化】字典界面样式调整,更协调 2023-03-27 16:07:50 +00:00
xlzy
a2b7d7b713 【更新】修复最大化标签之后,模块坞不显示的问题 2023-03-27 16:07:50 +00:00
xlzy
991fba682f 【更新】超时时间设置1分钟 2023-03-27 16:07:50 +00:00
xlzy
99d66df3dc 【更新】修复修改分页之后,刷新表格时传递的pageSize参数不正确的问题 2023-03-27 16:07:50 +00:00
xlzy
8e8e59ae47 【更新】安装qs库 2023-03-27 16:07:50 +00:00
xlzy
fa6a10e7cd 【更新】解决tailwindcss控制台警告 2023-03-27 16:07:50 +00:00
xlzy
c2041c2782 【更新】兼容更多的请求method,增加moduleRequest,更方便添加前缀 2023-03-27 16:07:50 +00:00
xlzy
65fe9fce81 【更新】修复tailwindcss部分颜色不生效 2023-03-27 16:07:50 +00:00
xlzy
c4df5d65e2 【更新】移除style 2023-03-27 16:07:50 +00:00
小诺
283e42f0d2 【更新】设置抽屉内的一些bug修复,以及少数功能代码优化 2023-03-27 16:07:50 +00:00
xlzy
c016c136ae 【更新】升级vite以及其他依赖并锁定版本 2023-03-27 16:07:50 +00:00
xlzy
fa91de42b9 【更新】忽略lock文件 2023-03-27 16:07:50 +00:00
xlzy
7384ed0ce3 【更新】调整XnFormContainer 2023-03-27 16:07:50 +00:00
xuyuxiang
23d0791e4e 【修复】修复 #I6PK10 登录菜单取并集bug 2023-03-27 16:07:50 +00:00
xlzy
0ba4a8c4d0 【更新】升级vite版本 2023-03-27 16:07:50 +00:00
xlzy
e5c7326a38 【更新】替换旧的$store 2023-03-27 16:07:50 +00:00
xlzy
96fa681a91 【更新】兼容formStyle 2023-03-27 16:07:50 +00:00
xlzy
48736f6519 【更新】使用Pinia代替Vuex 2023-03-27 16:07:50 +00:00
xuyuxiang
1cdd40be28 【修复】修复 #I6NVHY 手机验证码登录验证bug 2023-03-27 16:07:50 +00:00
xuyuxiang
9f66eb52a3 【优化】优化异常打印,不使用e.printStackTrace方式 2023-03-27 16:07:50 +00:00
xuyuxiang
60049933ae 【优化】优化异常打印,不使用e.printStackTrace方式 2023-03-27 16:07:50 +00:00
小诺
50ff1b8f9f 【更新】表格{ x: 1200, y: 300 }不生效问题修复 2023-03-27 23:44:49 +08:00
xlzy
ae73f1bb14 【更新】修复清除缓存之后,头像没有更新的问题 2023-03-27 23:14:26 +08:00
小诺
cc8c7b1e07 【更新】关闭多标签功能后,移除其他被缓存的标签 2023-03-27 00:10:11 +08:00
小诺
6a74374f71 【优化】调整顶部模块坞间距 2023-03-26 23:08:20 +08:00
xlzy
3aefc5fd8b 【更新】删除无用配置,默认值就是这些 2023-03-26 23:01:31 +08:00
xlzy
1a4ec87b69 【更新】显示面包屑时,间距过大 2023-03-26 22:54:13 +08:00
小诺
3cc44e4ec1 【优化】优化css代码格式 2023-03-26 22:13:28 +08:00
xlzy
a29da7fac0 【更新】顶部栏应用主题色时修正样式 2023-03-26 20:48:58 +08:00
xlzy
9884e6bb1e 【更新】首页打开控制台的显示优化 2023-03-26 20:36:47 +08:00
小诺
a085116ae9 【修复】修复首页两个日志模块超管不显示更多按钮的问题 2023-03-26 16:06:20 +08:00
小诺
516e5f9566 【优化】字典界面样式调整,更协调 2023-03-26 15:32:40 +08:00
xlzy
4c1a31661e 【更新】修复最大化标签之后,模块坞不显示的问题 2023-03-26 14:58:00 +08:00
xlzy
3005f8e7a5 【更新】超时时间设置1分钟 2023-03-26 14:39:19 +08:00
xlzy
2c4c321590 【更新】修复修改分页之后,刷新表格时传递的pageSize参数不正确的问题 2023-03-26 13:57:34 +08:00
xlzy
d67f24ef5c 【更新】安装qs库 2023-03-26 13:07:54 +08:00
xlzy
5c43c869aa 【更新】解决tailwindcss控制台警告 2023-03-26 13:07:11 +08:00
xlzy
9db45c2297 【更新】兼容更多的请求method,增加moduleRequest,更方便添加前缀 2023-03-26 12:49:14 +08:00
xlzy
363c9b7b2b 【更新】修复tailwindcss部分颜色不生效 2023-03-26 12:09:52 +08:00
xlzy
7daf8b05de 【更新】移除style 2023-03-26 12:02:29 +08:00
小诺
9d0c481f85 【更新】设置抽屉内的一些bug修复,以及少数功能代码优化 2023-03-26 01:57:08 +08:00
xlzy
ea0ffa53ef 【更新】升级vite以及其他依赖并锁定版本 2023-03-25 17:44:35 +08:00
xlzy
2b80d75327 【更新】忽略lock文件 2023-03-25 17:42:41 +08:00
xlzy
51fe3e9a2d 【更新】调整XnFormContainer 2023-03-25 17:41:16 +08:00
xuyuxiang
da4f5f1dd3 【修复】修复 #I6PK10 登录菜单取并集bug 2023-03-24 09:18:59 +08:00
xlzy
40a0dafb4e 【更新】升级vite版本 2023-03-23 23:14:12 +08:00
xlzy
6913945e1b 【更新】替换旧的$store 2023-03-23 23:11:14 +08:00
xlzy
1ea621bf5a 【更新】兼容formStyle 2023-03-23 17:00:47 +08:00
xlzy
2c6ec39122 【更新】使用Pinia代替Vuex 2023-03-23 17:00:47 +08:00
xuyuxiang
df11702b38 【修复】修复 #I6NVHY 手机验证码登录验证bug 2023-03-23 16:57:19 +08:00
xuyuxiang
2e87918730 【优化】优化异常打印,不使用e.printStackTrace方式 2023-03-23 14:16:32 +08:00
xuyuxiang
8f2fa66647 【优化】优化异常打印,不使用e.printStackTrace方式 2023-03-23 14:13:00 +08:00
小诺
3febc21536
!96 【修复】修复登录界面刷新后无缓冲情况下报错问题
Merge pull request !96 from 小诺/dev
2023-03-23 04:11:52 +00:00
xuyuxiang
d1e8ca972f 【修复】修复登录界面刷新后无缓冲情况下报错问题 2023-03-23 12:09:22 +08:00
徐玉祥
6f702b6e55 【更新】升级SpringFrameWork至5.3.26,紧急修复漏洞 2023-03-23 00:56:39 +08:00
小诺
2b33da9e9c 【更新】锁定前端依赖版本,避免某依赖升级摧毁原有可用性 2023-03-23 00:47:22 +08:00
小诺
7387f4d1d3 【修复】修复登录界面验证码输入错误后不重置以及配置完成不立马生效问题 2023-03-22 23:34:04 +08:00
小诺
360f1bb233 【升级】前端整体升级所有抽屉采用统一组件,可根据喜好情况在抽屉跟对话框随意切换 2023-03-22 21:44:43 +08:00
小诺
e97ea6b731 【更新】修复一个前端模块坞闪烁问题,优化css样式 2023-03-21 00:47:15 +08:00
xlzy
09c4fb24b5 【更新】调整多页签交互,增加右键操作 2023-03-20 21:48:42 +08:00
xlzy
e42c4ddc3a 【更新】新增XnFormContainer组件和使用demo 2023-03-20 21:48:42 +08:00
xiaonuobase
df8482e4a7 【更新】增加QQ新群号 685395081 2023-03-20 15:26:04 +08:00
徐玉祥
f1e4e44d7e 【优化】优化导包 2023-03-18 19:44:56 +08:00
小诺
5352269b09 【优化】优化一个前端字典函数 2023-03-17 02:01:05 +08:00
小诺
65e48f847f 【修复】修复代码生成批量删除组件引用方法取不到参数问题 2023-03-16 21:45:04 +08:00
xuyuxiang
5345501700 【修复】修复 #I6N98C GenConfig Entity SortCode字段与数据库对应字段数据类型不符 2023-03-15 14:39:37 +08:00
xuyuxiang
b81d122b95 【修复】修复 #I6MY3S CommonCacheOperator缓存bug 2023-03-15 09:07:57 +08:00
小诺
747b6973be 【更新】统一下载blob功能加入判断 2023-03-14 23:54:57 +08:00
xuyuxiang
d18eb01292 【修复】修复C端用户Mapper.xml对应的Mapper接口错误 2023-03-14 16:35:36 +08:00
小诺
f8d7ced955 【更新】调整导出功能的参数格式 2023-03-14 01:45:43 +08:00
徐玉祥
bba662ed6c 【更新】回滚错误异常处理 2023-03-13 23:56:20 +08:00
徐玉祥
bbb634e9f4 【更新】优化流下载接口在权限校验时的异常处理 2023-03-13 22:48:52 +08:00
徐玉祥
4181fd0aca 【更新】biz模块删除导入模板 2023-03-13 22:18:55 +08:00
徐玉祥
e33c566eaa 【更新】下载模板接口使用Void 2023-03-13 22:16:18 +08:00
徐玉祥
a5f94ec488 【更新】easypoi排除冲突依赖 2023-03-13 22:07:22 +08:00
徐玉祥
282019598e 【更新】恢复空Test 2023-03-13 21:37:21 +08:00
小诺
41a9ce41a6 【更新】调整一点业务前端代码格式 2023-03-13 21:14:26 +08:00
徐玉祥
bdce56a803 【更新】前端操作栏权限判断 2023-03-13 20:48:16 +08:00
徐玉祥
16b2263ae5 【更新】完善业务模块的导入导出,导出新SQL 2023-03-13 20:44:06 +08:00
xuyuxiang
b47192516a 【更新】业务模块前端增加导出方法 2023-03-13 17:22:22 +08:00
xuyuxiang
25e3b339c1 【更新】业务模块增加导入导出等功能代码 2023-03-13 17:12:49 +08:00
xuyuxiang
4f71fd1006 【更新】业务模块增加导入导出等功能代码 2023-03-13 16:10:41 +08:00
xiaonuobase
5fe157b672 【更新】业务功能列表增加操作头 2023-03-13 11:31:58 +08:00
xiaonuobase
f395391f4c 【修改】更新sql文件,增加导入导出的按钮权限 2023-03-13 11:18:31 +08:00
小诺
c7e615c7b4 【更新】代码生成增加对应的批量删除跟代码调优,解决了iss中提出的生成后代码不能重置等一系列问题,其次优化后端实体类导包 2023-03-12 23:43:44 +08:00
小诺
98d3c87bac 【修复】sTable修复alert的用法 2023-03-12 23:42:37 +08:00
小诺
dece5567ba 【修复】修复刷新浏览器路由警告问题 2023-03-12 21:14:31 +08:00
小诺
cd3b44e6ba 【更新】前端界面验证码配置后刷新模式更改,登录界面回车监听增加 2023-03-12 19:20:21 +08:00
小诺
b546184f3f 【更新】所有列表上面重置按钮重置后刷新列表 2023-03-12 14:55:37 +08:00
小诺
3ed834204b 【更新】更改因头像被清理后无法导出的问题 2023-03-12 14:30:42 +08:00
小诺
1613273835 【升级】所有带有批量删除的功能统一封装为插件共用,实现批量删除确认 2023-03-12 11:02:15 +08:00
小诺
cb4f0a4680 【升级】用户、角色、字典、机构、岗位这些左树右表得到增强,新增时选择树后对应新增的表单跟着选中 2023-03-12 02:39:59 +08:00
小诺
41d8a234a3 【更新】前端界面数字滑动条统一更换为数字输入框 2023-03-12 01:55:07 +08:00
小诺
aea1fac10b 【更新】前端代码进行大量的优化、缩减 2023-03-12 01:42:38 +08:00
小诺
46890f08c8 【修复】个人中心清理掉头像后阴影效果错乱问题以及签名图片左右不饱满问题 2023-03-12 00:59:38 +08:00
小诺
47ff13c198 【更新】优化代码,业务下人员管理导入功能同步加入导入文件类型限制 2023-03-12 00:23:51 +08:00
D哥
e34944a950 优化:限制和验证用户导入上传的文件类型和扩展名为xls、xlsx
Signed-off-by: D哥 <12271764+darrenteng@user.noreply.gitee.com>
2023-03-11 16:02:06 +00:00
小诺
d13dfb0043 【更新】完成定时任务前端立即运行功能 2023-03-11 23:55:43 +08:00
小诺
0b0d7e7cfd 【优化】优化前端菜单管理界面查询 2023-03-11 23:46:20 +08:00
小诺
b51180bfbf 【更新】人员管理模块下增加导入导出以及该模块对应的国际化配置调整 2023-03-11 23:43:28 +08:00
小诺
87f43b5f17 【更新】针对前端下载blob提出重复代码 2023-03-11 22:34:22 +08:00
小诺
d552d86dd2 【更新】完善前端用户管理导出用户功能 2023-03-11 22:29:33 +08:00
小诺
b87a7f5d65 【新增】新增用户管理的授权角色与授权资源,新增前端导入功能,新增导出某用户的模板信息,优化部分代码 2023-03-10 01:52:06 +08:00
xuyuxiang
e4a6b7aad0 【修复】修复getUserByIdWithoutException的逻辑判断错误 2023-03-09 16:05:54 +08:00
xuyuxiang
700232952f 【更新】SaToken注解拦截器更新替换过时的写法 2023-03-09 15:24:35 +08:00
xuyuxiang
0c1e0952f1 【修复】修复 #I6JN8G PostgreSQL表名大小写及引发的代码生成问题 2023-03-09 15:02:55 +08:00
xuyuxiang
77098b3173 【更新】更新README 2023-03-08 14:50:19 +08:00
xuyuxiang
11f6938623 【更新】注释没有使用的数据库驱动依赖,更新README 2023-03-08 14:48:34 +08:00
xuyuxiang
b98663ab7c 【更新】优化用户导入代码 2023-03-08 10:39:02 +08:00
xuyuxiang
33bbcd810a 【更新】优化用户选择器 2023-03-08 10:30:07 +08:00
xuyuxiang
c71badd0d5 【更新】完善导入功能 2023-03-08 10:17:07 +08:00
徐玉祥
41f9e174c7 【更新】用户导入,待完善 2023-03-07 23:48:47 +08:00
徐玉祥
55a02c6053 【更新】用户导入,待完善 2023-03-07 23:48:26 +08:00
xuyuxiang
2056089ed9 【更新】完善导入功能 2023-03-07 17:08:06 +08:00
xuyuxiang
20c238f9cd 【更新】完善导出年龄计算 2023-03-07 13:20:31 +08:00
xuyuxiang
78ae075519 【更新】更新导出模板 2023-03-07 11:30:34 +08:00
徐玉祥
c49c7b5e3a 【更新】导入模板改为GET下载 2023-03-06 22:51:31 +08:00
徐玉祥
a49fb8a807 【更新】用户导入功能(待完善) 2023-03-06 22:49:42 +08:00
徐玉祥
db9393b182 【更新】完善导出word的图片显示问题 2023-03-06 22:47:13 +08:00
xuyuxiang
0ccaf15f40 【更新】完成用户导出功能 2023-03-06 17:01:29 +08:00
xuyuxiang
2f566b2d1a 【更新】完成用户导出功能 2023-03-06 14:24:33 +08:00
徐玉祥
eb7b68e2e5 【更新】新增一个导入模板 2023-03-05 17:44:30 +08:00
徐玉祥
de22c060cb 【更新】完善一个注释 2023-03-05 16:48:42 +08:00
徐玉祥
445c7b1a5e 【更新】完善一个注释 2023-03-05 16:47:31 +08:00
徐玉祥
515c072e59 【更新】优化授权逻辑,用户导入(待完善) 2023-03-05 16:33:11 +08:00
徐玉祥
567127f2b2 【更新】优化登录逻辑,减少查询次数 2023-03-05 15:11:48 +08:00
徐玉祥
755e70e2c5 【更新】登陆部分待优化 2023-03-05 03:49:22 +08:00
徐玉祥
fcc65450fc 【更新】完善用户、机构选择器,启用缓存机制优化 2023-03-05 03:48:41 +08:00
徐玉祥
1cf1e1765e 【更新】导出功能(待完善) 2023-03-05 00:58:39 +08:00
徐玉祥
029c4cfba8 【更新】完善用户独立授权资源和权限,完善获取用户菜单的接口 2023-03-04 23:59:02 +08:00
xuyuxiang
e4b4c782e3 【更新】用户单独授权(待完善) 2023-03-03 17:04:35 +08:00
xuyuxiang
2801b730c5 【更新】系统默认密码脱敏返回 2023-03-03 16:16:52 +08:00
xuyuxiang
b04c7510e5 【更新】定时任务新增立即运行接口 2023-03-03 15:54:51 +08:00
xuyuxiang
16ff5dcb3c 【更新】更新数据变动事件机制,可对系统数据变动监听做额外处理,降低耦合 2023-03-03 14:43:07 +08:00
徐玉祥
11c9145eaf 【更新】更新README墨菲安全认证徽章 2023-03-02 23:39:23 +08:00
徐玉祥
ed32848708 【更新】更新README墨菲安全认证徽章 2023-03-02 23:34:09 +08:00
徐玉祥
635ecb60d6 【更新】完成根目录pom.xml锁定版本号,排除依赖冲突 2023-03-02 23:33:37 +08:00
徐玉祥
f06b637e47 【更新】mybatisplus升级后removeBatchByIds改为removeByIds 2023-03-02 23:32:53 +08:00
徐玉祥
ce403d8528 【更新】根目录pom.xml锁定版本号,其他xml无需填写版本,由父项目统一管理 2023-03-02 21:36:52 +08:00
徐玉祥
08eada130b 【更新】先恢复pom.xml,不做依赖排除 2023-03-02 21:01:58 +08:00
xuyuxiang
042c678328 【修复】修复yml的一个漏洞 2023-03-02 17:05:35 +08:00
xuyuxiang
c7e5c4472f 【修复】忽略不需要提交的一个文件 2023-03-02 16:55:51 +08:00
xuyuxiang
f7e4c82b2e 【修复】修复一部分漏洞 2023-03-02 16:54:09 +08:00
xuyuxiang
3f3b4a6023 【修复】升级hutool版本,修复漏洞 2023-03-02 16:20:22 +08:00
xuyuxiang
620369c4da 【修复】完善MINIO工具类 2023-03-02 15:23:32 +08:00
xuyuxiang
e680edf65d 【修复】升级MINIO版本,解决项目中的jar包依赖冲突 2023-03-02 15:20:36 +08:00
小诺
ad0f7a8811 【修复】修复iss提出问题:系统设置,点击重置按钮报错 2023-03-01 23:51:31 +08:00
小诺
6ce2afadf7 【更新】端口误提交更新 2023-03-01 23:37:31 +08:00
xuyuxiang
286e5add86 【修复】修复 #I663US 代码生成主键驼峰命名错误 2023-03-01 13:26:10 +08:00
xuyuxiang
5ac312af12 【修复】修复 #I66L8X 代码生成逻辑删除字段枚举有问题 2023-03-01 11:23:00 +08:00
xuyuxiang
308243b16b 【修复】修复 #I65QRH 个人中心保存个人信息的修改手机号未验证重复,而且没有传签名确修改了签名的bug 2023-03-01 11:13:42 +08:00
xuyuxiang
a1e78d1d1e 【更新】代码生产接口仅超管可用 2023-03-01 11:09:32 +08:00
xuyuxiang
437b0b069d 【更新】去掉误提交 2023-03-01 09:53:16 +08:00
xuyuxiang
8de2c3a838 【修复】修复 #I6IB27 CommonJoinPointUtil类中getArgsJsonString在某些情况下出现bug 2023-03-01 09:52:11 +08:00
小诺
d823d3aa1a 【修复】修复iss列表查询参数parameter的size默认是undefined,感谢qq群 seven 小伙 2023-02-28 23:40:12 +08:00
D哥
a7890763fe
修复操作日志-异常日志-详情【返回结果】栏语法高亮不能自动判别开发语言着色问题
Signed-off-by: D哥 <12271764+darrenteng@user.noreply.gitee.com>
2023-02-23 09:05:16 +00:00
小诺
e11abd1f9a 【更新】代码生成增强,生成到插件与模块可配置,新增及编辑加入事务注解 2023-02-23 00:55:02 +08:00
小诺
08e70171bc 【更新】更新文件上传组件,返回名称跟下载url 2023-02-19 17:12:02 +08:00
小诺
6cf3425f13 【优化】优化一个iss提出的前端文字错误 2023-02-16 23:50:25 +08:00
小诺
d36efcb3d9 【更新】为移动端功能更新SQL表结构及数据 2023-02-09 23:38:10 +08:00
小诺
3aee08136b 【优化】优化一些移动端相关的代码 2023-02-06 22:56:12 +08:00
D哥
4926efe662 修复业管身份登录添加岗位时报错【不支持的岗位分类:XXX】
Signed-off-by: D哥 <12271764+darrenteng@user.noreply.gitee.com>
2023-02-05 15:54:42 +00:00
小诺
8d17ec38ba 【优化】去掉一个多余的导包 2023-02-05 13:57:35 +08:00
每天一点
6fee6f09de 【修复】修复获取个人信息不返回移动端按钮码问题 2023-02-05 13:30:11 +08:00
小诺
f577bae164 【优化】优化一个移动端授权时查询代码 2023-02-05 03:15:38 +08:00
小诺
a901e2a4ff 【更新】修复授权移动端无按钮错误,优化前端移动端菜单模块等管理界面 2023-02-05 03:12:07 +08:00
每天一点
b34c427a5d 去掉方形和原型图标 2023-02-05 02:49:42 +08:00
每天一点
bb0a54c5d8 移动端菜单使用移动端图标选择器 2023-02-05 02:02:32 +08:00
每天一点
45e2f2528f 图标移动端选择器 2023-02-05 01:56:32 +08:00
每天一点
fdd7d4e29e 移动端图标库 2023-02-05 01:54:38 +08:00
每天一点
ccd951ee61 移动端菜单bug 2023-02-04 13:40:41 +08:00
小诺
0c67454008 【更新】移动端授权错误修改,按钮未显示问题待修复 2023-02-04 01:33:28 +08:00
小诺
ba0ed7978f 【更新】移动端按钮授权基本完成 2023-02-03 01:21:30 +08:00
xuyuxiang
e288a19078 【更新】完善移动端菜单模块,增加按钮模块,与PC一致 2023-02-01 10:11:18 +08:00
小诺
fed5dc8bbf 【更新】完善前端给角色授权移动端菜单功能 2023-02-01 01:34:22 +08:00
小诺
a2ac82a1e8 【更新】完善移动端菜的跟模块的管理 2023-02-01 01:10:30 +08:00
小诺
b5f005613b 【更新】少导入一个LambdaQueryWrapper的包 2023-02-01 00:27:09 +08:00
xuyuxiang
660b1e91a9 【更新】完善移动端菜单,menu的pages改为path,增加了menuType字段,与后端一致,前端记得修改 2023-01-31 11:05:08 +08:00
xuyuxiang
b61371b722 【更新】修复查询使用lamdaUpdateWrapper的错误 2023-01-31 09:10:54 +08:00
小诺
61b969b2f1 【更新】更新移动端菜单管理(待完善) 2023-01-31 01:47:08 +08:00
xuyuxiang
647e7de72b 【更新】移动端功能(待完善) 2023-01-30 17:04:24 +08:00
小诺
07b5481aea 【更新】补充一个sql文件 2023-01-28 23:42:55 +08:00
小诺
fb27a50192 【新增】新增移动端菜单管理功能(待完善) 2023-01-28 23:40:12 +08:00
xiaonuobase
03bf8a1b2e 【修改】调整postgres数据库文件PR的内容 2023-01-28 14:46:14 +08:00
andrewgreat
0ed84ae1d2 修改导入postgres数据sql格式 2023-01-28 04:53:11 +00:00
andrewgreat
fdd5d9285e 使master分支数据库数据 2023-01-28 04:53:11 +00:00
andrewgreat
539cec483f 【更新】新增postgres的配置,适配postgres 2023-01-28 04:53:11 +00:00
小诺
668b3851c5 【优化】生成代码后加入权限控制接口、修复代码生成点击配置部分内容被重置问题、生成的表单数字输入框值改为10000,滑动输入改为1000 2023-01-27 13:12:24 +08:00
小诺
99182cd929 【优化】优化字典前端语法-小改动 2023-01-17 23:46:05 +08:00
小诺
879b3fa74f 【修复】修复代码生成选择压缩包下包名输入框不显示问题 2023-01-13 01:32:46 +08:00
小诺
4dd22edc8d 【新增】stable组件新增默认的每页条数(defaultPageSize)跟指定每页可以显示多少条(pageSizeOptions)配置 2023-01-12 22:41:07 +08:00
小诺
9e480b08e3 【更新】面包屑错乱问题修复 2023-01-06 22:36:11 +08:00
xuyuxiang
6cb9de9a56 【更新】完善注释 2023-01-03 14:26:21 +08:00
小诺
ed6419d2d9
!78 【bugfix】修复无法删除【系统配置】-->【其他配置】记录问题
Merge pull request !78 from xiaomaiyun/master
2022-12-31 15:28:02 +00:00
xiaomaiyun
311b8f7f38
[bugfix]修复无法删除【系统配置】-->【其他配置】记录问题
Signed-off-by: xiaomaiyun <923782299@qq.com>
2022-12-28 08:29:46 +00:00
小诺
f00a8786c4
!77 【bugfux】修复代码高亮显示build打包发布后样式消失问题
Merge pull request !77 from xiaomaiyun/master
2022-12-20 02:03:06 +00:00
xiaomaiyun
d053263f4b
[bugfix]解决Vue使用highlight.js build打包发布后样式消失问题
Signed-off-by: xiaomaiyun <923782299@qq.com>
2022-12-17 19:10:03 +00:00
xiaomaiyun
426ae0eb03
首页轮播图实现
Signed-off-by: xiaomaiyun <923782299@qq.com>
2022-12-17 15:07:44 +00:00
xiaomaiyun
937a9d306b
!1 修复删除按钮无法自动刷新列表
Merge pull request !1 from xiaomaiyun/N/A
2022-12-15 15:26:16 +00:00
xiaomaiyun
8291fd8293
[bugfix]菜单管理-->按钮权限-->删除,无法自动刷新按钮列表
Signed-off-by: xiaomaiyun <923782299@qq.com>
2022-12-15 15:25:15 +00:00
小诺
e533167710
!70 v2.1.4
Merge pull request !70 from 小诺/dev
2022-12-08 09:36:54 +00:00
xiaonuobase
2696a626c3 【修复】修复两个问题,关联的issues为(少林寺驻北固山办事处大神父王喇嘛)创建 #I6546J、(可达鸭给我冲鸭)创建 #I631O1,提出贡献感谢! 2022-12-08 17:28:18 +08:00
xiaonuobase
dc2cdd6488 【修复】修复一个内存溢出的bug,感谢群内(꧁༺佲牌舞仔༻꧂)的钻研并提供 2022-12-08 17:11:23 +08:00
小诺
f7610dad14 【更新】readme更新最新视频教程总览图 2022-12-06 23:37:43 +08:00
小诺
682e9a96fb 【更新】更改一些遗漏的请求加载去除 2022-12-05 23:09:14 +08:00
小诺
bfae72401d 【更新】代码生成删除方法主键错误修复 2022-12-05 22:39:07 +08:00
小诺
10ffbe6be1 【新增】readme新增pr方式 2022-12-04 01:40:16 +08:00
小诺
db2ef88c5f 【更新】BC端认证权限例子更明确 https://gitee.com/xiaonuobase/snowy/issues/I63AJ2 2022-12-04 01:29:24 +08:00
小诺
405bf92794 【更新】代码生成主键更新为非写死状态 https://gitee.com/xiaonuobase/snowy/issues/I64DLI 2022-12-04 01:24:54 +08:00
小诺
52a61577b8 【更新】重置密码时候bug修复,密码传输使用加密方式 2022-12-04 01:06:47 +08:00
小诺
2275380e00 【更新】修复BC端鉴权问题,感谢码云小伙(可达鸭给我冲鸭) https://gitee.com/xiaonuobase/snowy/issues/I62WRX 2022-12-04 00:46:38 +08:00
小诺
1f7c06b777 【更新】修复任务(找回密码返回validCodeReqNo不为空) https://gitee.com/xiaonuobase/snowy/issues/I644Q8 2022-12-04 00:33:56 +08:00
小诺
999e725a3f 【更新】修复任务(编辑单页选择图标报错问题) https://gitee.com/xiaonuobase/snowy/issues/I63CSX 2022-12-03 23:46:29 +08:00
小诺
87216deed1 【更新】修复任务 https://gitee.com/xiaonuobase/snowy/issues/I63TJ2 2022-12-03 23:34:23 +08:00
小诺
46b35d8232
!69 修改表格刷新问题
Merge pull request !69 from sol/dev
2022-12-03 15:14:03 +00:00
卢杰
8ff7310075 1.删除无法刷新表格
修改table.refresh(true)======>table.value.refresh(true)
2.修改注释错误
2022-12-03 13:02:31 +08:00
小诺
86ed69f161
!62 update AuthServiceImpl.java.
Merge pull request !62 from 微笑/N/A
2022-11-27 13:11:31 +00:00
微笑
518c971c88
update AuthServiceImpl.java.
原写法导致 set null 不生效,getClientLoginUser() 多次调用返回不同对象

Signed-off-by: 微笑 <1572089876@qq.com>
2022-11-25 09:22:48 +00:00
小诺
2f940b0cd1 【新增】readme新增github代码下载镜像地址 2022-11-24 18:34:02 +08:00
小诺
18e74e0243
!60 v2.1.3
Merge pull request !60 from 小诺/dev
2022-11-23 17:10:50 +00:00
xlzy
35364c44bf 【优化】封装登录成功后的处理逻辑 2022-11-23 23:45:14 +08:00
xlzy
0511e9f877 【优化】登录页代码逻辑、样式优化 2022-11-23 23:33:33 +08:00
xlzy
0c91118e09 【更新】优化表单必填方法的参数名称 2022-11-23 23:33:33 +08:00
小诺
304fa3e315 【更新】更新适配新的tinymce上传文件方法 2022-11-22 23:55:30 +08:00
小诺
a64f6e4c6e 【更新】更新代码生成表单内多一个变量,修正系统配置中删除方法 2022-11-22 23:54:41 +08:00
小诺
f38c2bc0b8 【更新】解决代码生成前端多生成tool工具类导入跟配置时不显示上级目录问题 2022-11-19 23:25:35 +08:00
xuyuxiang
892ae19176 【更新】重置误提交 2022-11-17 13:35:04 +08:00
xuyuxiang
14808f7597 【更新】修复 #I60MMT 执行代码生成(项目内)后端地址判断错误的bug 2022-11-17 13:35:04 +08:00
小诺
631541083e 【更新】更新编辑器因为自身升级导致的错误 2022-11-17 05:18:41 +00:00
小诺
087a369fbf 【更新】去掉角色管理功能界面上面增加的合并行 2022-11-17 05:18:41 +00:00
xuyuxiang
6da4e83140 【更新】完善gitignore 2022-11-17 05:18:41 +00:00
xuyuxiang
edb713ae48 【更新】修复业务模块获取机构树构造结果为空的bug 2022-11-17 05:18:41 +00:00
小诺
ef07a18847 【更新】接受一个iss中建议,Delete ␍eslint 2022-11-17 05:18:41 +00:00
徐玉祥
1e00b2a38b 【更新】修复SysRoleServiceImpl方法注释错别字 2022-11-17 05:18:41 +00:00
徐玉祥
330cd62dcc 【更新】去除误提交 2022-11-17 05:18:41 +00:00
徐玉祥
bc37ff08d7 【更新】修复SysRolePageParam字段注释错误 2022-11-17 05:18:41 +00:00
徐玉祥
61c23ff794 【更新】去掉代码生成的菜单自动加上的管理二字 2022-11-17 05:18:41 +00:00
徐玉祥
09af5dac2c 【更新】修复代码生成BigDecimal未导入包的bug 2022-11-17 05:18:41 +00:00
徐玉祥
653fd3f15c 【更新】更新gitignore 2022-11-17 05:18:41 +00:00
徐玉祥
e835101242 【更新】删除不需要提交的auto-imports.d.ts 2022-11-17 05:18:41 +00:00
徐玉祥
6f6a6c45c3 【更新】代码生成的sql注释规范 2022-11-17 05:18:41 +00:00
微笑
283e0d6ab4 update snowy-web-app/pom.xml.
junit 单词拼写错误
2022-11-17 05:18:41 +00:00
小诺
35bb3b1244 【更新】更新前端依赖,固定出错误的版本 2022-11-17 05:18:41 +00:00
xuyuxiang
7e9ccac572 【更新】修复阿里云上传文件地址返回错误,修复文件key构造错误 2022-11-17 05:18:41 +00:00
小诺
24bd54b0ef 【更新】更新编辑器因为自身升级导致的错误 2022-11-16 19:45:32 +08:00
小诺
35849994a8 【更新】去掉角色管理功能界面上面增加的合并行 2022-11-16 14:41:11 +08:00
xuyuxiang
e62387d684 【更新】完善gitignore 2022-11-15 15:54:46 +08:00
xuyuxiang
cf578f4ee3 【更新】修复业务模块获取机构树构造结果为空的bug 2022-11-15 15:52:57 +08:00
小诺
a80fcbbde6 【更新】接受一个iss中建议,Delete ␍eslint 2022-11-13 17:06:46 +08:00
徐玉祥
61b7d639cc 【更新】修复SysRoleServiceImpl方法注释错别字 2022-11-13 11:57:17 +08:00
徐玉祥
f79e813b69 【更新】去除误提交 2022-11-13 11:42:18 +08:00
徐玉祥
13b25bd0c7 【更新】修复SysRolePageParam字段注释错误 2022-11-13 11:19:48 +08:00
徐玉祥
79ceea9b6f 【更新】去掉代码生成的菜单自动加上的管理二字 2022-11-12 23:40:14 +08:00
徐玉祥
fc7160e074 【更新】修复代码生成BigDecimal未导入包的bug 2022-11-12 23:13:47 +08:00
徐玉祥
45ff7b8931 【更新】更新gitignore 2022-11-12 21:56:05 +08:00
徐玉祥
124bc3ec22 【更新】删除不需要提交的auto-imports.d.ts 2022-11-12 21:49:09 +08:00
徐玉祥
3088dd53f0 【更新】代码生成的sql注释规范 2022-11-12 21:40:03 +08:00
微笑
65626b59b6
update snowy-web-app/pom.xml.
junit 单词拼写错误
2022-11-11 05:43:53 +00:00
小诺
90ce0c92b3 【更新】更新前端依赖,固定出错误的版本 2022-11-10 22:31:51 +08:00
xuyuxiang
dc93da7f81 【更新】修复阿里云上传文件地址返回错误,修复文件key构造错误 2022-11-10 10:26:01 +08:00
小诺
6634bdf0e6
v2.1.1 更多细节问题修复(快来看看你提的Iss是否更新),增加菜单搜索功能 2022-11-09 12:29:04 +00:00
小诺
84888ca6da 【更新】代码生成下载压缩包名字乱码问题修复 2022-11-09 20:19:36 +08:00
小诺
e1780efdfd 【更新】新增或编辑菜单失败后loading一直加载问题解决 2022-11-09 20:15:38 +08:00
小诺
05bb1d2f9d 【更新】优化前端配置缓存、双排菜单布局下页脚与经典布局同步 2022-11-08 21:23:27 +08:00
小诺
c5e9ad95f1 【更新】更新代码生成界面小细节,同时改进stable表格组件 2022-11-08 21:09:39 +08:00
小诺
44a68be040 【更新】更新gitee提到生成后的表单中字典配置错误 2022-11-08 17:48:03 +08:00
小诺
3817434d74 【更新】s-table问题修复,同时修改斑马纹的是否显示由开关变为选择框更美观 2022-11-08 17:10:03 +08:00
小诺
07f5caf73b 【更新】更新个人信息修改手机号不加密问题 2022-11-07 23:20:35 +08:00
小诺
56337192ae 【更新】更新一个C端控制器的枚举类型参数 2022-11-07 03:04:04 +08:00
小诺
f5cad22740 【修复】修复iss中提到的问题:模块现身省略号的问题 2022-11-07 02:59:08 +08:00
小诺
6cdbca8f38 【更新】升级前端该升级的依赖,优化该优化的优化,同时增加了gzip的配置,生产环境按照官网的配置部署速度更快 2022-11-06 21:35:16 +08:00
小诺
e1efbab2dc 【更新】优化一些前端警告 2022-11-04 20:26:11 +08:00
小诺
362b538bae 【更新】优化菜单搜索功能,感谢CcSimple兄弟送来的PR 2022-11-03 21:28:12 +08:00
xuyuxiang
887fa9d735 【更新】修复一个注释错误 2022-11-03 16:06:38 +08:00
xuyuxiang
d8d760aa0d 【更新】修复代码生成zip时sql未打包进去的bug 2022-11-03 16:05:16 +08:00
xuyuxiang
fdda070a88 【更新】同步beetl版本 2022-11-03 14:57:17 +08:00
xuyuxiang
9a83b2f251 【更新】同步beetl版本 2022-11-03 14:51:57 +08:00
xuyuxiang
8437c686be 【更新】修复一个命名错误 2022-11-03 14:02:59 +08:00
Cc-Mac
b60e86540a 【新增】菜单搜索功能 2022-11-02 19:21:16 +00:00
小诺
f094c30e46 【新增】大更新 v2.1 新增代码生成,具体使用看官方文档 2022-11-03 03:07:44 +08:00
小诺
db0fabb069 【更新】更新sql文件,增加代码生成表 2022-11-03 03:04:32 +08:00
徐玉祥
0ba8579cab 【更新】参数异常打印日志,方便查看 2022-11-02 23:47:52 +08:00
小诺
620edee09f 【修复】修复前端打包时 callback.apply 错误 2022-11-01 14:55:41 +08:00
徐玉祥
82344e240b 【更新】修复C端token名称带后缀导致的token无效的bug 2022-10-29 22:07:08 +08:00
徐玉祥
ab2e3e6573 【更新】修复C端接口校验登录的bug 2022-10-29 14:49:06 +08:00
小诺
32cf2ec404 【更新】更新一些 表格查询 loadData命名规范 2022-10-27 09:45:13 +00:00
小诺
db9e29a2d1 【更新】修复启动前端dayjs错误 2022-10-27 09:45:13 +00:00
小诺
1a49935026 【更新】修复微信开源1群提出的角色编辑bug,更新了首页图片尺寸高度 2022-10-27 09:45:13 +00:00
小诺
d7df6ff222 【更新】更新oracle环境下首页查询日志及站内信问题 #I5WOWD 2022-10-27 09:45:13 +00:00
小诺
cbacecb81e
v2.0.4 更新
Merge pull request !50 from 小诺/dev
2022-10-19 20:53:50 +00:00
小诺
dcd1c3481a
删除文件 .gitee/ISSUE_TEMPLATE.zh-CN.md 2022-10-19 20:52:14 +00:00
xuyuxiang
78d6521e6a 【更新】默认注释掉mssql的pom配置 2022-10-19 11:20:19 +08:00
xuyuxiang
94de8785b6 【更新】升级druid到1.2.9,新增MSSQL的配置,适配MSSQL 2022-10-19 11:00:54 +08:00
小诺
630d473efb 【更新】更新readme,增添免费视频教程 2022-10-19 01:51:17 +08:00
徐玉祥
01aa06ed98 【更新】用户签名统一压缩大小为100*50 2022-10-18 23:31:58 +08:00
俞宝山
10983218d9 Merge remote-tracking branch 'origin/dev' into dev 2022-10-18 23:31:39 +08:00
小诺
b3d5757f86 【注释】注释一个暂时不适于展示在此角色列表的合计 2022-10-18 23:31:31 +08:00
徐玉祥
98ab709793 【更新】1.全局异常处理中数据操作异常打印日志,2.用户修改头像和签名后端统一压缩大小,3.数据库关系表中object_id和target_id大小调整为varchar 255,4.修复issues 中 #I5V2YK oracle版本的bug,5.sql统一导出最新版 2022-10-18 23:28:47 +08:00
小诺
5dbebba20b 【更新】解决 issues 中 #I5WF6E <前端页面bug> 的问题 2022-10-18 23:07:54 +08:00
zoulifu
2404e96e5d 添加动态拖拉角色名称 列
添加角色底排序底部汇总伪代码
2022-10-18 14:31:16 +00:00
小诺
a06b36482c 新增issues提交规范
Signed-off-by: 小诺 <1253070437@qq.com>
2022-10-18 14:31:16 +00:00
小诺
27c88c020c 重命名 .gitee/.keep 为 .gitee/ISSUE_TEMPLATE.zh-CN.md 2022-10-18 14:31:16 +00:00
小诺
f820bec8eb 新建 .gitee 2022-10-18 14:31:16 +00:00
xuyuxiang
b4cb7e1fb4 【修复】修复注释错别字 2022-10-18 18:18:45 +08:00
小诺
214a1995fb
新增issues提交规范
Signed-off-by: 小诺 <1253070437@qq.com>
2022-10-18 09:41:08 +00:00
小诺
29475e8a43
重命名 .gitee/.keep 为 .gitee/ISSUE_TEMPLATE.zh-CN.md 2022-10-18 09:39:47 +00:00
小诺
de0ee7eb69
新建 .gitee 2022-10-18 09:39:26 +00:00
小诺
f458156d80 【更新】修复一个角色授权资源界面无法展示数据错误(补充) 2022-10-18 02:09:54 +08:00
小诺
32f3f23916 【更新】修复一个角色授权资源界面无法展示数据错误 2022-10-18 02:05:13 +08:00
小诺
6cc720cfe2 Merge branch 'master' of gitee.com:xiaonuobase/snowy into dev
Signed-off-by: 小诺 <1253070437@qq.com>
2022-10-16 16:37:08 +00:00
小诺
e7a4834d6d 【更新】更新 issues 中 #I5TY0J 文件配置中修改了上传路径,但是缓存中没有更新问题,去掉前端上传成功后的提醒为刷新列表 2022-10-14 14:13:32 +08:00
小诺
4e78ba3143 【更新】更新 issues 中 #I5V6OD 菜单管理选中新创建的模块,菜单列表不为空问题 2022-10-14 13:31:16 +08:00
小诺
c28185ee78 【更新】更新mp配置,新增oracle.nls.orai18n编码包 2022-10-14 11:25:11 +08:00
xuyuxiang
a04382c0c3 【更新】文件、短信、邮件、站内信的重要接口仅超管可访问,非重要接口登陆后即可访问 2022-10-13 15:24:43 +08:00
xuyuxiang
4ded451f88 【更新】升级spring-boot-maven-plugin为2.15.2 2022-10-13 15:09:03 +08:00
xuyuxiang
2a585e3a5c 【更新】升级springboot为2.15.2,与satoken依赖boot版本一致,防止log4j漏洞风险 2022-10-13 14:55:03 +08:00
xuyuxiang
7094edbd2b 【更新】升级satoken为1.31.0 2022-10-13 14:54:02 +08:00
小诺
6300e29cd3 【更新】更新readme文件,增加分支说明 2022-10-11 15:26:51 +08:00
小诺
17bdad85bc 【升级】升级maven依赖项,可能会有重复引用问题,此提交需要测试 2022-10-11 11:21:42 +08:00
xuyuxiang
410013a669 【更新】删除无用代码,优化导包 2022-10-10 10:30:10 +08:00
dongxiayu
6fef9486e2 【更新】优化代码规范 2022-10-09 10:22:21 +08:00
xuyuxiang
9746ac4b98 【修复】删除角色时应该级联删除角色与权限关系 2022-10-09 10:17:57 +08:00
小诺
8d503f2fa5 【更新】更新用户界面编辑后,因任职机构传输null字符串,导致回显错误问题 2022-10-08 21:49:41 +08:00
徐玉祥
823eb59a5c 【修复】修复C端用户接口解密失败的bug 2022-10-08 21:02:06 +08:00
dongxiayu
6f5939e555 【更新】优化代码规范 2022-10-08 10:13:32 +08:00
徐玉祥
9fecd72f4c 【更新】优化代码规范 2022-10-07 16:27:51 +00:00
徐玉祥
ea670e7d22 【修复】修正职位分类枚举 2022-10-07 16:27:51 +00:00
小诺
9c0a63b9fd 【更新】优化前端代码,更改模块坞名称、删除无用的工具类、操作日志增加IP跟IP地址显示、修复文件上传组件 2022-10-07 16:27:51 +00:00
徐玉祥
2573c7a1ed 【更新】完善异常处理 2022-10-07 16:27:51 +00:00
徐玉祥
0b58e4ee1f 【更新】更新启动后访问后端时异常提示语的处理 2022-10-07 16:27:51 +00:00
小诺
6ed1b6004b 【更新】更新readme文件,增加代码结构说明,文档地址 2022-10-07 16:27:51 +00:00
徐玉祥
5182d9d7fa 【更新】优化代码 2022-10-07 16:27:51 +00:00
徐玉祥
65b49420c3 【更新】C端用户的增加和编辑使用easy trans加密 2022-10-07 16:27:51 +00:00
徐玉祥
62d6c38113 【更新】新增MyBatisSystemException异常拦截处理 2022-10-07 16:27:51 +00:00
徐玉祥
99e8ff82cc 【更新】异常处理返回请求地址信息 2022-10-07 16:27:51 +00:00
徐玉祥
1dcc3d799f 【更新】优化代码规范 2022-10-07 00:57:05 +08:00
徐玉祥
ab9ee3ce70 【修复】修正职位分类枚举 2022-10-07 00:45:21 +08:00
小诺
02a9c117d0 【更新】优化前端代码,更改模块坞名称、删除无用的工具类、操作日志增加IP跟IP地址显示、修复文件上传组件 2022-10-07 00:34:26 +08:00
徐玉祥
6f67b0f433 【更新】完善异常处理 2022-10-06 23:19:23 +08:00
徐玉祥
959dea0f8c 【更新】更新启动后访问后端时异常提示语的处理 2022-10-06 23:11:05 +08:00
小诺
cee8097690 【更新】更新readme文件,增加代码结构说明,文档地址 2022-10-06 18:32:15 +08:00
徐玉祥
c0959b8aed 【更新】优化代码 2022-10-04 23:00:06 +08:00
徐玉祥
2deeedc024 【更新】C端用户的增加和编辑使用easy trans加密 2022-10-04 22:51:30 +08:00
徐玉祥
6671d2bbcc 【更新】新增MyBatisSystemException异常拦截处理 2022-10-04 19:14:51 +08:00
徐玉祥
1d9934bd48 【更新】异常处理返回请求地址信息 2022-10-03 16:00:52 +08:00
小诺
0d8b7a6834
!44 【修复】解决 issues中 #I5U4A7 最新代码拉取报错问题
Merge pull request !44 from 小诺/dev
2022-10-03 03:55:12 +00:00
小诺
2711435494 【修复】解决 issues中 #I5U4A7 最新代码拉取报错问题 2022-10-03 03:43:44 +08:00
413 changed files with 25750 additions and 5676 deletions

View File

@ -0,0 +1,13 @@
### 当前使用版本、分支(必填,否则不予处理)
### 该问题是如何引起的?(确定最新版也有问题再提!!!)
### 重现步骤(如果有就写完整)
### 报错信息

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ logs/
# idea
.idea/
*.iml
.murphy.yml
*velocity.log*

107
README.md
View File

@ -6,18 +6,15 @@
## 框架介绍
SnowySnowyAdmin是国内首个国产化前后端分离快速开发平台,集成国密加解密插件,
SnowySnowyAdmin是国内首个国前后端分离快速开发平台,集成国密加解密插件,
软件层面完全符合等保测评要求,同时实现国产化机型、中间件、数据库适配,是您的不二之选!
技术框架与密码结合,让更多的人认识密码,使用密码;更是让前后分离“密”不可分。
采用SpringBoot+MybatisPlus+AntDesignVue+Vite 等更多优秀组件及前沿技术开发,注释丰富,代码简洁,开箱即用!
Snowy谐音“小诺”恰应小诺团队名称意思为”下雪的、纯洁的“寓意框架追求简洁至上大道至简。
欢迎加入QQ技术群互相解决问题732230670
<p align="center">
<p align="center">
<a href="https://gitee.com/xiaonuobase/snowy">
@ -44,16 +41,23 @@ Snowy谐音“小诺”恰应小诺团队名称意思为”下雪的、纯
<a href="./LICENSE">
<img src="https://img.shields.io/badge/license-Apache%202-red" alt="license Apache 2.0">
</a>
<a href="https://old.murphysec.com/dr/mQ1xAybeOLMLOxH8pU" alt="OSCS Status">
<img src="https://www.oscs1024.com/platform/badge//xiaonuobase/snowy.git.svg?size=small"/>
</a>
</p>
</p>
## 快速链接
下载地址https://gitee.com/xiaonuobase/snowy
gitee下载地址:[https://gitee.com/xiaonuobase/snowy](https://gitee.com/xiaonuobase/snowy)
演示地址https://snowy.xiaonuo.vip
github下载地址镜像[https://github.com/xiaonuobase/Snowy](https://github.com/xiaonuobase/Snowy)
## 支撑组件及启动
演示地址:[https://snowy.xiaonuo.vip](https://snowy.xiaonuo.vip)
文档地址:[https://xiaonuo.vip/doc](https://xiaonuo.vip/doc)
## 快速启动
全栈工程师推荐idea
@ -62,7 +66,7 @@ Snowy谐音“小诺”恰应小诺团队名称意思为”下雪的、纯
|--- | ----- | ----- |
| node.js | 最新版 | JavaScript运行环境 |
#### 启动前端
### 启动前端
```
npm install
@ -74,15 +78,78 @@ npm run dev
| 插件 | 版本 | 用途 |
| --- | ----- | ----- |
| jdk | 11 / 1.8 |java环境 |
| lombok | idea内 |代码简化插件 |
| maven | 最新版 |包管理工具 |
| redis | 最新版 | 缓存库 |
| mysql | 8.0 / 5.7 | 数据库 |
#### 启动后端
### 启动后端
开发工具内配置好maven并在代码中配置数据库即可启动
## 代码结构
Snowy2.0框架对代码以插件化的模式进行分包使得包层级结构更加清晰合理同时降低了耦合度关于插件模块化开发的规范请查阅文档【SNOWY开源文档——前端手册or后端手册——开发规范】板块。
```
snowy
|-snowy-admin-web == 前端
|-public == 基础静态文件
|-src == 前端源代码
|-api == API接口转发
|-assets == 静态文件
|-components == VUE组件
|-config == 基础配置
|-layout == 基础布局
|-locales == 多语言配置
|-router == 基础路由配置
|-store == Pinia缓存配置
|-style == 样式风格配置
|-utils == 工具类
|-views == 所有视图界面
|-snowy-common == 基础通用模块
|-snowy-plugin == 插件包
|-snowy-plugin-auth == 登录鉴权插件
|-snowy-plugin-biz == 业务功能插件
|-snowy-plugin-client == C端功能插件
|-snowy-plugin-dev == 开发工具插件
|-snowy-plugin-gen == 代码生成插件
|-snowy-plugin-mobile == 移动端管理插件
|-snowy-plugin-sys == 系统功能插件
|-snowy-plugin-api == 插件api包
|-snowy-plugin-auth-api == 登录鉴权插件api接口
|-snowy-plugin-biz-api == 业务功能插件api接口
|-snowy-plugin-client-api == C端功能插件api接口
|-snowy-plugin-dev-api == 开发工具插件api接口
|-snowy-plugin-gen == 代码生成插件api接口
|-snowy-plugin-mobile == 移动端管理插件api接口
|-snowy-plugin-sys-api == 系统功能插件api接口
|-snowy-web-app == 主启动模块
```
## 分支说明
- master
正式稳定版本,具体版本升级内容看更新标签
- dev
团队开发的分支(代码可能随时会推,不保证运行和使用)
- snowy1.8
1.x分支目前已停止新增功能只限于bug的维护推荐使用2x版本
## 视频教程
教程地址(免费开放):[https://space.bilibili.com/50101698/channel/collectiondetail?sid=739071](https://space.bilibili.com/50101698/channel/collectiondetail?sid=739071)
<img src="https://pan.xiaonuo.vip/?explorer/share/fileOut&shareID=8nOccuKg&path=%7BshareItemLink%3A8nOccuKg%7D%2F"/>
作者也在上班工作,所以在利用休息时间为大家创作,录制视频的目的也是为各位小伙伴提供文档跟技术交流群聊之外的上手学习资料
> 视频由小诺开源技术团队王同学(每天一点)进行录制
## 效果图:fire:
@ -116,9 +183,12 @@ npm run dev
| 用户密码 | SM3完整性保护存储登录时做完整性校验 |
| 用户手机号 | SM4cbc模式加解密使用字段脱敏 |
## 官方微信
## 官方技术
因群达到200人以上需加微信拉群
QQ技术群732230670已满、685395081
微信技术群因群达到200人以上需加微信拉群
<table>
<tr>
@ -127,7 +197,17 @@ npm run dev
</tr>
</table>
## 原理图解
## 代码贡献
近期有很多热心开源的小伙伴陆续为咱们Snowy框架提交PR或者提出好的建议基本合格的PR我们都接受这样您的头像就列入到咱们Snowy仓库的贡献者列表啦
如何贡献:
1、fork一份代码至自己的账号下本地修改您要提的代码提交至您fork的仓库
2、登录gitee后到Snowy仓库下创建Pull Requests,选择您的仓库到Snowy的dev分支提交即可
因为dev分支是团队开发分支并不是统一发版本的测试过的所以我们建议提代码至dev即可
## 团队成员
@ -136,11 +216,12 @@ npm run dev
| 俞宝山 | 全栈 | 俞宝山 |
| 徐玉祥 | 全栈 | 就是那个锅 |
| 董夏雨 | 全栈 | 阿董 |
| 王鹏 | 全栈 | 每天一点 |
## 曾获荣誉
<p align="center">
<img src="https://pan.xiaonuo.vip/?explorer/share/fileOut&shareID=7xtGQLOA&path=%7BshareItemLink%3A7xtGQLOA%7D%2F"/>
<img src="https://pan.xiaonuo.vip/?explorer/share/file&hash=ec54DtG4v8DfcUEPF0ACAHWW-urCcymI_0fSSaqMmMXKLsTWdHpQqH0e&name=/%E8%8D%A3%E8%AA%892021%E4%B8%8E2022.jpg"/>
</p>
## 版权说明

617
pom.xml
View File

@ -13,13 +13,74 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<version>2.5.12</version>
</parent>
<properties>
<java.version>1.8</java.version>
<snowy.version>2.0.0</snowy.version>
<spring-framework.version>5.3.26</spring-framework.version>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<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.3</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>
<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>6.0.2</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>
<modules>
@ -36,6 +97,556 @@
<module>snowy-web-app</module>
</modules>
<dependencyManagement>
<dependencies>
<!-- snowy-common -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-common</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-auth-api -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-auth-api</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-biz-api -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-biz-api</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-client-api -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-client-api</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-dev-api -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-dev-api</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-gen-api -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-gen-api</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-mobile-api -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-mobile-api</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-sys-api -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-sys-api</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-auth -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-auth</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-biz -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-biz</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-client -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-client</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-dev -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-dev</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-gen -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-gen</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-mobile -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-mobile</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- snowy-plugin-sys -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-sys</artifactId>
<version>${snowy.version}</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.versin}</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</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>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!-- easy-trans -->
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-spring-boot-starter</artifactId>
<version>${easy.trans.version}</version>
</dependency>
<!-- easy-trans-mybatis-plus-extend -->
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-mybatis-plus-extend</artifactId>
<version>${easy.trans.version}</version>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>${commons.pool2.version}</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>
<!-- hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!-- pinyin4j -->
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>${pinyin.version}</version>
</dependency>
<!-- ip2region -->
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>${ip2region.version}</version>
</dependency>
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- easy-poi -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>${easypoi.version}</version>
</dependency>
<!-- sm-crypto -->
<dependency>
<groupId>com.antherd</groupId>
<artifactId>sm-crypto</artifactId>
<version>${smcrypto.version}</version>
</dependency>
<!-- easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
</dependency>
<!-- sa-token-core -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${sa.token.version}</version>
</dependency>
<!-- sa-token -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>${sa.token.version}</version>
</dependency>
<!-- sa-token 整合 redis 使用jackson序列化方式 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>${sa.token.version}</version>
</dependency>
<!-- Sa-Token插件权限缓存与业务缓存分离 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-alone-redis</artifactId>
<version>${sa.token.version}</version>
</dependency>
<!-- Sa-Token 插件整合SSO -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId>
<version>${sa.token.version}</version>
</dependency>
<!-- JustAuth 第三方登录 -->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>${just.auth.version}</version>
</dependency>
<!-- beetl模板引擎 -->
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl-framework-starter</artifactId>
<version>${beetl.version}</version>
</dependency>
<!--腾讯云上传文件客户端-->
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>${ten.cos.version}</version>
</dependency>
<!--阿里云上传文件客户端-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${ali.oss.version}</version>
</dependency>
<!--minio上传文件客户端-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
<!--java邮件发送-->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>${javax.mail.version}</version>
</dependency>
<!--阿里云邮件发送-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dm</artifactId>
<version>${aliyun.sdk.dm.version}</version>
</dependency>
<!-- 腾讯云邮件发送 -->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-ses</artifactId>
<version>${ten.sdk.ses.version}</version>
</dependency>
<!--阿里云短信发送-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>${aliyun.sdk.dysmsapi.version}</version>
</dependency>
<!--腾讯云短信发送-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-sms</artifactId>
<version>${ten.sdk.sms.version}</version>
</dependency>
<!--系统硬件信息-->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>${oshi.core.version}</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>
<!-- dynamic-datasource -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${dynamic.datasource.version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.java.version}</version>
</dependency>
<!-- postgresql -->
<!--<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgres.connector.java.version}</version>
</dependency>-->
<!-- oracle -->
<!--<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>${oracle.connector.java.version}</version>
</dependency>
<dependency>
<groupId>com.oracle.database.nls</groupId>
<artifactId>orai18n</artifactId>
<version>${oracle.nls.orai18n.version}</version>
</dependency>-->
<!-- mssql -->
<!--<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>${mssql.connector.java.version}</version>
</dependency>-->
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
@ -67,10 +678,6 @@
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>*.xdb</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>

View File

@ -9,3 +9,6 @@ VITE_API_BASEURL = http://127.0.0.1:82
# 本地端口
VITE_PORT = 81
# 开启设置抽屉
VITE_SET_DRAWER = true

View File

@ -9,3 +9,6 @@ VITE_API_BASEURL = http://127.0.0.1:82
# 本地端口
VITE_PORT = 81
# 开启设置抽屉
VITE_SET_DRAWER = false

View File

@ -33,6 +33,7 @@ module.exports = {
'vue/require-default-prop': 'off',
'vue/html-self-closing': 'off',
'vue/v-on-event-hyphenation': 'off',
'vue/multi-word-component-names': 'off'
'vue/multi-word-component-names': 'off',
'prettier/prettier': ['error', { endOfLine: 'auto' }]
}
}

View File

@ -1,6 +1,8 @@
.DS_Store
node_modules
/dist
*.lock
package-lock.json
# local env files
.env.local
@ -12,7 +14,9 @@ yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
package-lock.json
# other files
stats.html
auto-imports.d.ts
# Editor directories and files
.idea

View File

@ -10,69 +10,73 @@
"license": "Apache-2.0",
"author": "yubaoshan",
"scripts": {
"serve": "vite",
"dev": "vite --mode development",
"serve": "vite --host 0.0.0.0",
"dev": "vite --mode development --host 0.0.0.0",
"preview": "vite preview",
"build": "vite build --mode production",
"prod": "vite --mode production"
},
"dependencies": {
"@ant-design/colors": "4.0.1",
"@ant-design/icons-vue": "^6.0.1",
"@antv/g2plot": "^2.4.10",
"@chenfengyuan/vue-qrcode": "2",
"@highlightjs/vue-plugin": "^2.1.0",
"@tinymce/tinymce-vue": "4.0.5",
"ant-design-vue": "3.2.10",
"axios": "0.24.0",
"@ant-design/colors": "7.0.0",
"@ant-design/icons-vue": "6.1.0",
"@antv/g2plot": "2.4.28",
"@chenfengyuan/vue-qrcode": "2.0.0",
"@highlightjs/vue-plugin": "2.1.0",
"@tinymce/tinymce-vue": "5.0.0",
"ant-design-vue": "3.2.14",
"axios": "1.1.3",
"cropperjs": "1.5.12",
"dayjs": "^1.11.5",
"echarts": "5.2.2",
"echarts-stat": "^1.2.0",
"enquire.js": "^2.1.6",
"highlight.js": "^11.6.0",
"lodash-es": "^4.17.21",
"dayjs": "1.11.7",
"echarts": "5.4.0",
"echarts-stat": "1.2.0",
"enquire.js": "2.1.6",
"fuse.js": "6.6.2",
"highlight.js": "11.6.0",
"hotkeys-js": "3.10.1",
"js-pinyin": "0.1.9",
"lodash-es": "4.17.21",
"nprogress": "0.2.0",
"screenfull": "^6.0.2",
"sm-crypto": "^0.3.11",
"snowflake-id": "^1.1.0",
"sortablejs": "1.14.0",
"tinymce": "5.10.2",
"vue": "3.2.31",
"vue-cropper": "^1.0.1",
"vue-i18n": "^9.1.10",
"vue-router": "4.0.12",
"vue3-colorpicker": "^2.0.4",
"vue3-tree-org": "^3.1.6",
"vuedraggable-es": "4.1.0",
"vuex": "4.0.2"
"pinia": "2.0.33",
"qs": "6.11.1",
"screenfull": "6.0.2",
"sm-crypto": "0.3.11",
"snowflake-id": "1.1.0",
"sortablejs": "1.15.0",
"tinymce": "6.2.0",
"vue": "3.2.44",
"vue-cropper": "1.0.5",
"vue-i18n": "9.2.2",
"vue-router": "4.1.6",
"vue3-colorpicker": "2.0.4",
"vue3-tree-org": "4.1.1",
"vuedraggable-es": "4.1.1"
},
"devDependencies": {
"@antfu/eslint-config": "^0.18.3",
"@vitejs/plugin-legacy": "^1.6.4",
"@vitejs/plugin-vue": "^2.1.0",
"@vitejs/plugin-vue-jsx": "^1.3.8",
"@vue/compiler-sfc": "^3.2.31",
"@vue/eslint-config-standard": "^4.0.0",
"antd-dayjs-vite-plugin": "^1.2.0",
"antd-less-to-css-variable": "^1.0.5",
"autoprefixer": "^10.4.2",
"babel-eslint": "10.1.0",
"eslint": "^7.11.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^9.1.1",
"less": "^4.1.2",
"postcss": "^8.4.7",
"prettier": "^2.4.1",
"rollup-plugin-visualizer": "^5.7.1",
"tailwindcss": "^3.0.23",
"typescript": "^4.5.5",
"unplugin-auto-import": "^0.11.1",
"unplugin-vue-components": "^0.17.14",
"vite": "2.8.6",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vue-eslint-parser": "^9.0.3"
"@antfu/eslint-config": "0.29.4",
"@babel/eslint-parser": "7.19.1",
"@vitejs/plugin-legacy": "3.0.2",
"@vitejs/plugin-vue": "4.1.0",
"@vitejs/plugin-vue-jsx": "3.0.1",
"@vue/compiler-sfc": "3.2.47",
"@vue/eslint-config-standard": "8.0.1",
"antd-less-to-css-variable": "1.0.5",
"autoprefixer": "10.4.13",
"eslint": "8.26.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-vue": "9.7.0",
"less": "4.1.3",
"postcss": "8.4.21",
"prettier": "2.8.7",
"rollup-plugin-visualizer": "5.8.3",
"tailwindcss": "3.2.7",
"typescript": "4.9.5",
"unplugin-auto-import": "0.15.2",
"unplugin-vue-components": "0.24.1",
"vite": "4.2.1",
"vite-plugin-compression": "0.5.1",
"vite-plugin-vue-setup-extend": "0.4.0",
"vue-eslint-parser": "9.1.0"
},
"browserslist": [
"> 1%",

View File

@ -15,7 +15,7 @@ module.exports = {
tabWidth: 2,
// 使用tab符缩进false为空格缩进
useTabs: true,
// 行尾需要分号
// 行尾需要分号
semi: false,
// 使用单引号
singleQuote: true,
@ -31,15 +31,6 @@ module.exports = {
jsxBracketSameLine: true,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// 换行符使用 lf

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 750 750" style="enable-background:new 0 0 750 750;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.35;fill:#B3B3B3;}
.st1{opacity:0.1;fill:#B3B3B3;}
.st2{opacity:0.3;fill:#B3B3B3;}
.st3{opacity:0.1;}
.st4{fill:#B3B3B3;}
</style>
<g>
<path class="st0" d="M465.1,261.4H264c-1.3,0-2.4,1.1-2.4,2.4v255.6c0,1.3,1.1,2.4,2.4,2.4h201.1c1.3,0,2.4-1.1,2.4-2.4V263.8
C467.5,262.4,466.4,261.4,465.1,261.4z M417.9,443c0,1.3-1.1,2.4-2.4,2.4h-102c-1.3,0-2.4-1.1-2.4-2.4v-11.3c0-1.3,1.1-2.4,2.4-2.4
h102c1.3,0,2.4,1.1,2.4,2.4V443z M417.9,397.2c0,1.3-1.1,2.4-2.4,2.4h-102c-1.3,0-2.4-1.1-2.4-2.4v-11.3c0-1.3,1.1-2.4,2.4-2.4h102
c1.3,0,2.4,1.1,2.4,2.4V397.2z M417.9,351.5c0,1.3-1.1,2.4-2.4,2.4h-102c-1.3,0-2.4-1.1-2.4-2.4v-11.3c0-1.3,1.1-2.4,2.4-2.4h102
c1.3,0,2.4,1.1,2.4,2.4V351.5z"/>
<g>
<path class="st1" d="M462.1,236.8L462.1,236.8C384.8,236.2,321,295.1,314,370.7c-18.5-19.1-44.4-31.1-73.1-31.3h0
c-56.8-0.4-103.2,45.3-103.6,102.1l-0.8,101.4l175.6,1.3l30.1,0.2l265.1,2l1.2-160.9C609.2,304,543.6,237.4,462.1,236.8z"/>
<path class="st2" d="M216.9,227.4c-3.4,0-6.5,1.1-9,2.9c0.2-1,0.3-2,0.3-3c0.1-8.3-6.6-15.1-15-15.2s-15.1,6.6-15.2,15
c0,0.3,0,0.6,0,0.9c-1.6-0.6-3.4-1-5.2-1c-8.3-0.1-15.1,6.6-15.2,15c-0.1,8.2,6.4,14.9,14.5,15.2l0,0l44.6,0.3
c8.3,0.1,15.1-6.6,15.2-15S225.2,227.5,216.9,227.4z"/>
<path class="st2" d="M596.4,194.2c-3.4,0-6.5,1.1-9,2.9c0.2-1,0.3-2,0.3-3c0.1-8.3-6.6-15.1-15-15.2s-15.1,6.6-15.2,15
c0,0.3,0,0.6,0,0.9c-1.6-0.6-3.4-1-5.2-1c-8.3-0.1-15.1,6.6-15.2,15c-0.1,8.2,6.4,14.9,14.5,15.2l0,0l44.6,0.3
c8.3,0.1,15.1-6.6,15.2-15S604.7,194.3,596.4,194.2z"/>
<g>
<g class="st3">
<path class="st4" d="M496.9,497.5c-2.1,0-3.7,1.6-3.7,3.7c0,1.5,0.8,2.7,2,3.3l-0.5,65.1l3.5,0l0.5-65.3
c1.1-0.6,1.8-1.8,1.8-3.1C500.6,499.1,499,497.6,496.9,497.5z"/>
<path class="st4" d="M572.3,501.7c0-1.9-1.6-3.6-3.7-3.7c-2.1,0-3.7,1.6-3.7,3.7c0,1.4,0.8,2.6,1.9,3.2l-0.5,65.2l3.5,0
l0.5-65.2C571.5,504.3,572.2,503.1,572.3,501.7z"/>
</g>
<rect x="522.7" y="472.2" transform="matrix(7.448311e-03 -1 1 7.448311e-03 8.6828 1045.4733)" class="st1" width="16.5" height="92.3"/>
<polygon class="st1" points="495.4,509.8 495.2,510.1 485.5,526.3 484.8,526.3 484.9,509.8 "/>
<polygon class="st1" points="518.7,510 508.8,526.5 496.3,526.4 500.2,519.8 506,509.9 "/>
<polygon class="st1" points="542,510.2 532.1,526.6 519.6,526.5 529.3,510.1 "/>
<polygon class="st1" points="565.3,510.4 555.5,526.8 542.9,526.7 552.7,510.3 "/>
<polygon class="st1" points="577.2,510.4 577.1,527 566.2,526.9 576,510.4 "/>
<rect x="522.5" y="497.7" transform="matrix(7.448311e-03 -1 1 7.448311e-03 -17.0149 1070.603)" class="st1" width="16.5" height="92.3"/>
<polygon class="st1" points="495.2,535.3 495,535.6 485.3,551.8 484.6,551.8 484.7,535.3 "/>
<polygon class="st1" points="518.5,535.5 508.6,552 496.1,551.9 500,545.3 505.8,535.4 "/>
<polygon class="st1" points="541.8,535.7 531.9,552.1 519.4,552 529.1,535.6 "/>
<polygon class="st1" points="565.1,535.9 555.4,552.3 542.7,552.2 552.5,535.8 "/>
<polygon class="st1" points="577,536 576.9,552.5 566,552.4 575.8,536 "/>
<path class="st1" d="M577.1,527c0,0,0-0.1,0-0.3l0-0.9c0-0.7,0-1.8,0-3.2c0-2.8,0.1-6.9,0.1-12.2l0.1,0.1l-92.3-0.5l0,0l0.1-0.1
c0,5.6-0.1,11.2-0.1,16.5l-0.1-0.1l65.8,0.6l19.5,0.1l5.3,0l0,0l-5.3,0l-19.5-0.1l-65.8-0.3l-0.3,0l0.1-16.8l0.1,0l92.3,0.8
l0.1,0l0,0.1c0,5.3-0.1,9.4-0.1,12.2c0,1.5,0,2.5,0,3.2l0,0.7C577.1,526.8,577.1,527,577.1,527z"/>
<path class="st1" d="M576.9,552.5c0,0,0-0.1,0-0.3l0-0.9c0-0.7,0-1.8,0-3.2c0-2.8,0.1-6.9,0.1-12.2l0.1,0.1l-92.3-0.5l0,0
l0.1-0.1c0,5.6-0.1,11.2-0.1,16.5l-0.1-0.1l65.8,0.6l19.5,0.1l5.3,0l0,0l-5.3,0l-19.5-0.1l-65.8-0.3l-0.3,0l0.1-16.7l0.1,0
l92.3,0.8l0.1,0l0,0.1c0,5.3-0.1,9.4-0.1,12.2c0,1.5,0,2.5,0,3.2l0,0.7C576.9,552.3,576.9,552.5,576.9,552.5z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

File diff suppressed because one or more lines are too long

View File

@ -1,236 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 456 262.1" style="enable-background:new 0 0 456 262.1;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.4;fill:url(#SVGID_1_);enable-background:new ;}
.st1{opacity:0.7;}
.st2{opacity:0.4;fill:url(#SVGID_2_);enable-background:new ;}
.st3{opacity:0.4;fill:url(#SVGID_3_);enable-background:new ;}
.st4{opacity:0.4;fill:url(#SVGID_4_);enable-background:new ;}
.st5{opacity:0.4;fill:url(#SVGID_5_);enable-background:new ;}
.st6{opacity:0.6;}
.st7{fill:#0073CD;}
.st8{fill:#40A8F5;}
.st9{fill:#53B9F5;}
.st10{fill:#85D3FF;}
.st11{fill:#8CD7FF;}
.st12{fill:#EBFCFF;}
.st13{fill:none;stroke:url(#SVGID_6_);stroke-width:2;stroke-miterlimit:10;}
.st14{fill:none;stroke:url(#SVGID_7_);stroke-width:2;stroke-miterlimit:10;}
.st15{fill:none;stroke:url(#SVGID_8_);stroke-width:2;stroke-miterlimit:10;}
.st16{fill:none;stroke:url(#SVGID_9_);stroke-width:2;stroke-miterlimit:10;}
.st17{fill:none;stroke:url(#SVGID_10_);stroke-width:2;stroke-miterlimit:10;}
.st18{fill:none;stroke:url(#SVGID_11_);stroke-width:2;stroke-miterlimit:10;}
</style>
<title>升级中</title>
<g id="图层_2_1_">
<g id="图层_1-2">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="232.745" y1="39.57" x2="232.745" y2="1.88" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<path class="st0" d="M412.3,262.1c-23-23-61-37.7-179.5-37.7S76.2,239.1,53.2,262.1H412.3z"/>
<g class="st1">
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="349.365" y1="237.3224" x2="349.365" y2="59.9676" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<path class="st2" d="M380.7,26.7h-62.6c-1.5-0.1-2.8,1.1-2.8,2.6v172.2c0.1,1.5,1.3,2.7,2.8,2.6h62.6c1.5,0.1,2.7-1.1,2.8-2.6
V29.3C383.4,27.8,382.2,26.6,380.7,26.7z M328.3,147c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.8c0,0,0,0,0,0
v-19.7c0-0.5,0.4-0.9,0.9-0.9c0,0,0,0,0,0h3.6c0.5,0,0.9,0.4,0.9,0.9c0,0,0,0,0,0V147z M328.3,116.8c0,0.5-0.4,0.9-0.9,0.9
c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0V97c0-0.5,0.4-0.9,0.9-0.9c0,0,0,0,0,0h3.6c0.5,0,0.9,0.4,0.9,0.9
c0,0,0,0,0,0V116.8z M328.3,86.5c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0V66.8
c0-0.5,0.4-0.9,0.9-0.9c0,0,0,0,0,0h3.6c0.5,0,0.9,0.4,0.9,0.9c0,0,0,0,0,0V86.5z M328.3,56.3c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0
h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0V36.6c0-0.5,0.4-0.9,0.9-0.9c0,0,0,0,0,0h3.6c0.5,0,0.9,0.4,0.9,0.9c0,0,0,0,0,0V56.3z
M340,147c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0v-19.7c0-0.5,0.4-0.9,1-0.9h3.6
c0.5,0,0.9,0.4,0.9,0.9V147z M340,116.8c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-1-0.9V97c0-0.5,0.4-0.9,1-0.9h3.6
c0.5,0,0.9,0.4,0.9,0.9V116.8z M340,86.5c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-1-0.9V66.8c0-0.5,0.4-0.9,1-0.9h3.6
c0.5,0,0.9,0.4,0.9,0.9V86.5z M340,56.3c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-1-0.9V36.6c0-0.5,0.4-0.9,1-0.9h3.6
c0.5,0,0.9,0.4,0.9,0.9V56.3z M351.7,147c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0v-19.7
c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V147z M351.7,116.8c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V97
c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V116.8z M351.7,86.5c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V66.8
c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V86.5z M351.7,56.3c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V36.6
c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V56.3z M363.4,147c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6
c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0v-19.7c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V147z M363.4,116.8
c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V97c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V116.8z M363.4,86.5
c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V66.8c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V86.5z M363.4,56.3
c0,0.5-0.4,0.9-0.9,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V36.6c0-0.5,0.4-0.9,0.9-0.9h3.6c0.5,0,0.9,0.4,0.9,0.9V56.3z M375.1,147
c0,0.5-0.4,0.9-0.9,0.9c0,0,0,0,0,0h-3.6c-0.5,0-0.9-0.4-0.9-0.9c0,0,0,0,0,0v-19.7c0-0.5,0.4-0.9,0.9-0.9h3.6
c0.5,0,0.9,0.4,1,0.9V147z M375.1,116.8c0,0.5-0.4,0.9-1,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V97c0-0.5,0.4-0.9,0.9-0.9h3.6
c0.5,0,0.9,0.4,1,0.9V116.8z M375.1,86.5c0,0.5-0.4,0.9-1,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V66.8c0-0.5,0.4-0.9,0.9-0.9h3.6
c0.5,0,0.9,0.4,1,0.9V86.5z M375.1,56.3c0,0.5-0.4,0.9-1,0.9h-3.6c-0.5,0-0.9-0.4-0.9-0.9V36.6c0-0.5,0.4-0.9,0.9-0.9h3.6
c0.5,0,0.9,0.4,1,0.9V56.3z"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="201.46" y1="208.3924" x2="201.46" y2="59.9976" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<path class="st3" d="M231.1,55.6h-59.3c-1.5-0.1-2.7,1.1-2.8,2.6v143.2c0.1,1.5,1.3,2.6,2.8,2.6h59.3c1.5,0.1,2.8-1.1,2.8-2.6
V58.2C233.9,56.7,232.6,55.5,231.1,55.6z M182.5,159.4c0,0.6-0.6,1.1-1.2,1.1h-5.4c-0.6,0-1.2-0.5-1.2-1.1v-5.2
c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V159.4z M182.5,146.5c0,0.6-0.6,1.1-1.2,1.1
c0,0,0,0,0,0h-5.4c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1V146.5z
M182.5,133.6c0,0.6-0.6,1.1-1.2,1.1h-5.4c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4
c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V133.6z M182.5,120.7c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-5.4c-0.6,0-1.2-0.5-1.2-1.1
c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1V120.7z M182.5,107.8c0,0.6-0.6,1.1-1.2,1.1h-5.4
c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V107.8z M182.5,94.9
c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-5.4c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4
c0.6,0,1.2,0.5,1.2,1.1V94.9z M182.5,82.1c0,0.6-0.6,1.1-1.2,1.1h-5.4c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1
c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V82.1z M182.5,69.2c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-5.4
c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0V64c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1V69.2z M192.6,159.4
c0,0.6-0.6,1.1-1.2,1.1H186c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1
c0,0,0,0,0,0L192.6,159.4z M192.6,146.5c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H186c-0.6,0-1.2-0.5-1.2-1.1v-5.2
c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1L192.6,146.5z M192.6,133.6c0,0.6-0.6,1.1-1.2,1.1H186
c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L192.6,133.6z
M192.6,120.7c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H186c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4
c0.6,0,1.2,0.5,1.2,1.1L192.6,120.7z M192.6,107.8c0,0.6-0.6,1.1-1.2,1.1H186c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2
c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L192.6,107.8z M192.6,94.9c0,0.6-0.6,1.1-1.2,1.1
c0,0,0,0,0,0H186c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1L192.6,94.9z
M192.6,82.1c0,0.6-0.6,1.1-1.2,1.1H186c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4
c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L192.6,82.1z M192.6,69.2c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H186c-0.6,0-1.2-0.5-1.2-1.1V64
c0-0.6,0.5-1.2,1.2-1.2c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1L192.6,69.2z M202.6,159.4c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H196
c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1L202.6,159.4z M202.6,146.5
c0,0.6-0.6,1.1-1.2,1.1H196c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1
c0,0,0,0,0,0L202.6,146.5z M202.6,133.6c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H196c-0.6,0-1.2-0.5-1.2-1.1v-5.2
c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1L202.6,133.6z M202.6,120.7c0,0.6-0.6,1.1-1.2,1.1H196
c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L202.6,120.7z
M202.6,107.8c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H196c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4
c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L202.6,107.8z M202.6,94.9c0,0.6-0.6,1.1-1.2,1.1H196c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0
v-5.2c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L202.6,94.9z M202.6,82.1c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0
H196c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h5.4c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L202.6,82.1z
M202.6,69.2c0,0.6-0.6,1.1-1.2,1.1H196c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0V64c0-0.6,0.6-1.1,1.2-1.1h5.4c0.6,0,1.2,0.4,1.2,1.1
c0,0,0,0,0,0V69.2z M227.8,159.4c0,0.6-0.6,1.1-1.2,1.1h-20.5c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0
h20.5c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L227.8,159.4z M227.8,146.5c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-20.5
c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h20.5c0.6,0,1.2,0.5,1.2,1.1L227.8,146.5z M227.8,133.6
c0,0.6-0.6,1.1-1.2,1.1h-20.5c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h20.5c0.6,0,1.2,0.5,1.2,1.1
c0,0,0,0,0,0L227.8,133.6z M227.8,120.7c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-20.5c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2
c0-0.6,0.6-1.1,1.2-1.1h20.5c0.6,0,1.2,0.5,1.2,1.1L227.8,120.7z M227.8,107.8c0,0.6-0.6,1.1-1.2,1.1h-20.5
c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h20.5c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L227.8,107.8z
M227.8,94.9c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-20.5c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1h20.5
c0.6,0,1.2,0.5,1.2,1.1L227.8,94.9z M227.8,82.1c0,0.6-0.6,1.1-1.2,1.1h-20.5c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1
c0,0,0,0,0,0h20.5c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0L227.8,82.1z M227.8,69.2c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0h-20.5
c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0V64c0-0.6,0.6-1.1,1.2-1.1h20.5c0.6,0,1.2,0.5,1.2,1.1L227.8,69.2z"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="122.975" y1="237.3228" x2="122.975" y2="59.9971" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<path class="st4" d="M161.1,26.7H84.8c-1.5-0.1-2.8,1.1-2.8,2.6c0,0,0,0,0,0v172.2c0.1,1.5,1.3,2.6,2.8,2.6h76.3
c1.5,0.1,2.8-1.1,2.8-2.6V29.3C163.9,27.8,162.6,26.6,161.1,26.7z M154.3,161c0,0.6-0.6,1.1-1.2,1.1H92.8c-0.6,0-1.2-0.5-1.2-1.1
c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V161z M154.3,146.3
c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H92.8c-0.6,0-1.2-0.5-1.2-1.1v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3
c0.6,0,1.2,0.5,1.2,1.1V146.3z M154.3,131.6c0,0.6-0.6,1.1-1.2,1.1H92.8c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2
c0-0.6,0.6-1.1,1.2-1.1h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V131.6z M154.3,117c0,0.6-0.6,1.1-1.2,1.1H92.8
c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.2c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V117z
M154.3,102.3c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H92.8c-0.6,0-1.2-0.5-1.2-1.1V97c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3
c0.6,0,1.2,0.5,1.2,1.1V102.3z M154.3,87.6c0,0.6-0.6,1.1-1.2,1.1H92.8c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.3
c0-0.6,0.6-1.1,1.2-1.1h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V87.6z M154.3,72.9c0,0.6-0.6,1.1-1.2,1.1H92.8
c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.3c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V72.9z
M154.3,58.3c0,0.6-0.6,1.1-1.2,1.1c0,0,0,0,0,0H92.8c-0.6,0-1.2-0.5-1.2-1.1V53c0-0.6,0.6-1.1,1.2-1.1c0,0,0,0,0,0h60.3
c0.6,0,1.2,0.5,1.2,1.1V58.3z M154.3,43.6c0,0.6-0.6,1.1-1.2,1.1H92.8c-0.6,0-1.2-0.5-1.2-1.1c0,0,0,0,0,0v-5.3
c0-0.6,0.6-1.1,1.2-1.1h60.3c0.6,0,1.2,0.5,1.2,1.1c0,0,0,0,0,0V43.6z"/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="273.51" y1="264" x2="273.51" y2="54.46" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<path class="st5" d="M306.2,0h-65.4c-1.4,0-2.5,1.2-2.4,2.6v204.4c-0.1,1.4,1,2.5,2.4,2.6c0,0,0,0,0,0h65.4
c1.4-0.1,2.5-1.2,2.4-2.6V2.6C308.7,1.2,307.6,0.1,306.2,0z M300.4,119.6c0,0.6-0.4,1.1-1,1.1h-51.7c-0.6,0-1-0.5-1-1.1v-5.2
c0-0.6,0.4-1.1,1-1.1h51.7c0.6,0,1,0.5,1,1.1L300.4,119.6z M300.4,90.3c0,0.6-0.4,1.1-1,1.1h-51.7c-0.6,0-1-0.5-1-1.1V85
c0-0.6,0.4-1.1,1-1.1h51.7c0.6,0,1,0.5,1,1.1L300.4,90.3z M300.4,60.9c0,0.6-0.4,1.1-1,1.1h-51.7c-0.6,0-1-0.5-1-1.1v-5.2
c0-0.6,0.4-1.1,1-1.1h51.7c0.6,0,1,0.5,1,1.1L300.4,60.9z M300.4,31.5c0,0.6-0.4,1.1-1,1.1h-51.7c-0.6,0-1-0.5-1-1.1v-5.2
c0-0.6,0.4-1.1,1-1.1h51.7c0.6,0,1,0.5,1,1.1L300.4,31.5z M300.4,16.9c0,0.6-0.4,1.1-1,1.1h-51.7c-0.6,0-1-0.5-1-1.1v-5.2
c0-0.6,0.4-1.1,1-1.1h51.7c0.6,0,1,0.5,1,1.1L300.4,16.9z"/>
</g>
<g class="st6">
<path class="st7" d="M244.2,130.7c3.3,1.9,5.7,13.6,1,20.7c-5.3,6.8-7,9-6.1,14c-4.3-7.3-0.6-7.4-5.8-14.2
c-4.6-6.2-2.5-17.4,0.7-20.5C237.4,131.3,240.8,131.3,244.2,130.7L244.2,130.7z"/>
<path class="st8" d="M280.4,211.9c-0.1,0.6-0.1,1.2-0.1,1.7c0,0.7,0.1,1.3,0.2,2c-2.1-0.8-4.3-1.2-6.5-1.2
c-2.6,0-5.2,0.6-7.5,1.7c-0.8-4.2-4.8-7-9-6.2c-2.8,0.5-5,2.5-5.9,5.2c-3.4-2.1-7.7-2-11.1,0.1c-0.4-5.7-4.1-0.8-9.8-0.8
c-6,0-11.8-4.4-11.8,1.7c0,1.1,0.2,2.2,0.4,3.2c-1.1,0.1-2.1,0.5-3,1c-0.9-7-6.8-12.4-13.9-12.7c22.6-10.3,22.4-44.6,24.8-74.6
c0.1-1.7,1.2-4.1,1.8-4.4l0,0c1.5,1.1,3.2,1.8,5.1,2.1c-3.2,3.1-5.4,14.3-0.7,20.5c5.3,6.8,1.6,6.9,5.8,14.2
c-0.9-5,0.8-7.2,6.1-14c4.8-7.2,2.3-18.8-1-20.7c1.8-0.3,3.6-1,5.1-2.1l0,0c0.6,0.3,1.7,2.7,1.8,4.4
C253.6,164.6,250.4,198.5,280.4,211.9z"/>
<path class="st9" d="M303.3,203.2c-5.4,0-9.8,4.4-9.8,9.8c0,0.3,0,0.6,0,0.9c-1.5-1.7-3.7-2.6-6-2.5c-0.7,0-1.4,0.1-2.1,0.3
c0.7-1.3,1.1-2.8,1.1-4.3c-0.1-4.6-3.9-8.3-8.5-8.2c-4,0.1-7.4,3-8.1,6.9c-0.1,0.4-0.1,0.9-0.1,1.3c0,0.5,0,1,0.1,1.6
c-3.5-1.4-7.4-1.3-10.8,0.4c-0.7-3.2-3.9-5.3-7.2-4.6c-2,0.4-3.6,1.9-4.3,3.8c-1.3-0.8-2.7-1.2-4.2-1.2c-1.5,0-3.1,0.4-4.4,1.3
c-0.2-4.6-4.1-8.2-8.7-8s-8.2,4.1-8,8.7l0,0c0,0.8,0.1,1.7,0.3,2.5c-0.8,0.1-1.6,0.4-2.3,0.8c-0.7-5.4-5.2-9.6-10.7-9.8h-0.4
c-3.4,0-6.7,1.6-8.8,4.3c-3-6.2-10.4-8.9-16.7-5.9c-2.9,1.4-5.2,3.9-6.3,7c4.1,3,6.6,7.8,6.6,12.9c0,2.3-0.5,4.6-1.5,6.6
c2-2.2,4.8-3.4,7.8-3.4c0.9,0,1.8,0.1,2.7,0.3c-2.9-5-1.2-11.5,3.8-14.4c1.2-0.7,2.6-1.2,3.9-1.3c0.5-0.1,0.9-0.1,1.4-0.1
c5.8,0,10.6,4.7,10.6,10.6l0,0c0,0.6-0.1,1.3-0.2,1.9c4.4-1.7,9.3-1.6,13.6,0.4c0.9-4.1,4.9-6.7,9-5.8c2.6,0.6,4.7,2.4,5.5,4.9
c1.6-0.9,3.5-1.4,5.3-1.4c1.9,0,3.8,0.5,5.4,1.5l0.1,0.1c0.3-4.5,3.6-8.4,8-9.4c0.8-0.2,1.7-0.3,2.5-0.3
c5.8,0,10.6,4.7,10.6,10.6c0,1-0.2,2-0.4,3c1.1,0.1,2.1,0.5,3,1c1-7,7-12.1,14-12.1c1.5,0,3,0.2,4.4,0.7c2.6,0.8,5,2.5,6.7,4.6
c2.4-4.8,7-8.2,12.4-8.8C311.4,205.9,307.6,203.2,303.3,203.2z"/>
<path class="st10" d="M314.4,209.9c-0.6,0-1.2,0-1.8,0.1c-5.4,0.6-10.1,3.9-12.5,8.7c-1.7-2.2-4-3.8-6.7-4.6
c-1.4-0.5-2.9-0.7-4.4-0.7c-7,0-13,5.2-14,12.1c-0.9-0.5-1.9-0.9-3-1c0.3-1,0.4-2,0.4-3c0-5.8-4.7-10.5-10.5-10.5
c-0.8,0-1.7,0.1-2.5,0.3c-4.4,1.1-7.7,4.9-8,9.4l-0.1-0.1c-1.6-1-3.5-1.5-5.4-1.5c-1.9,0-3.7,0.5-5.3,1.4c-1.4-3.9-5.7-6-9.6-4.6
c-2.5,0.9-4.3,3-4.9,5.5c-4.3-2-9.2-2.1-13.6-0.4c0.1-0.6,0.2-1.3,0.2-1.9c0-5.8-4.7-10.6-10.6-10.6l0,0c-0.5,0-0.9,0-1.4,0.1
c-5.8,0.8-9.9,6.1-9.1,11.8c0.2,1.4,0.6,2.7,1.3,3.9c-0.9-0.2-1.8-0.3-2.7-0.3c-2.9,0-5.8,1.2-7.8,3.4c1-2.1,1.5-4.3,1.5-6.6
c0-5.1-2.4-9.9-6.6-12.9l0,0c-7.1-5.2-17-3.6-22.2,3.5c-5.2,7.1-3.6,17,3.5,22.2c6.8,5,16.4,3.7,21.7-2.8
c-2.1,5.5,0.7,11.6,6.1,13.6c5.5,2.1,11.6-0.7,13.6-6.1c0.5-1.2,0.7-2.5,0.7-3.7c0-1.9,0.4-0.1,0.4,2.7c0,9.7,7.8,17.6,17.5,17.6
c9.7,0,17.6-7.8,17.6-17.5c0-2.4-0.5-4.8-1.4-7l0.5-0.1c0.5,5.8,5.7,10.1,11.5,9.5c5-0.5,9-4.4,9.5-9.4c1.7,1,3.6,1.6,5.5,1.6
c0.6,0,1.2,0,1.7-0.1v0.1c0,4.2,3.4,7.6,7.6,7.5c2.6,0,5-1.4,6.4-3.6c4.7,6.3,13.5,7.5,19.8,2.9c1.5-1.1,2.8-2.5,3.7-4.2
c4.9,7.3,14.8,9.1,22.1,4.2s9.1-14.8,4.2-22.1C324.5,212.5,319.6,209.9,314.4,209.9L314.4,209.9z"/>
</g>
<path class="st11" d="M239.1,70c6.4,0,11.6,5.2,11.6,11.6c0,6.4-5.2,11.6-11.6,11.6c-6.4,0-11.6-5.2-11.6-11.6c0,0,0,0,0,0
C227.5,75.2,232.7,70,239.1,70z"/>
<path class="st8" d="M239.1,137.2c8.3,0,13.5-1.7,16.6-7.9c0,3.2-1.5,6.2-4.1,8.1c-1.9,1.3-4,2.2-6.2,2.6c-4.1,0.8-8.4,0.8-12.5,0
c-2.2-0.4-4.3-1.3-6.2-2.6c-2.6-1.9-4.2-4.9-4.2-8.1C225.6,135.5,230.7,137.2,239.1,137.2z"/>
<path class="st8" d="M288.4,151.7c0,0.5-0.3,0.8-0.8,0.8c-0.3,0-0.5-0.1-0.7-0.3c-7.6-10.3-25.5-25-30.4-24.7
c2.4-6.1,3.4-15.9,3.6-31.2C271.5,100.3,288.3,122.4,288.4,151.7z"/>
<path class="st8" d="M218.1,96.3c0.3,15.2,1.2,25,3.6,31.1l-0.2,0.1c-4.9-0.3-22.8,14.5-30.4,24.7c-0.3,0.4-0.8,0.5-1.1,0.2
c-0.2-0.2-0.4-0.4-0.3-0.7C189.7,122.3,206.6,100.2,218.1,96.3L218.1,96.3z"/>
<path class="st8" d="M250.7,81.6c0-6.4-5.2-11.6-11.6-11.6c-6.4,0-11.6,5.2-11.6,11.6s5.2,11.6,11.6,11.6l0,0
C245.5,93.2,250.7,88,250.7,81.6z M252.9,81.6c0,7.6-6.2,13.8-13.8,13.8c-7.6,0-13.8-6.2-13.8-13.8c0-7.6,6.2-13.8,13.8-13.8
c0,0,0,0,0,0C246.7,67.8,252.9,74,252.9,81.6z"/>
<path class="st8" d="M239.1,48.7c5.7,0,10.7-2,13.8-4.9c0.5,1.3,1,2.6,1.4,4c-3.3,3.3-8.9,5.4-15.3,5.4s-11.9-2.1-15.3-5.4
c0.5-1.3,1-2.7,1.4-4C228.4,46.8,233.4,48.7,239.1,48.7z"/>
<path class="st9" d="M252.9,43.8c-3.1,3-8.1,4.9-13.8,4.9s-10.7-2-13.8-4.9c2-5.1,4.5-10,7.6-14.5c0.5-0.7,0.9-1.3,1.4-1.9
c2-2.7,5.8-3.2,8.5-1.2c0.4,0.3,0.8,0.7,1.2,1.2c0.5,0.6,0.9,1.2,1.4,1.9C248.4,33.8,250.9,38.7,252.9,43.8z"/>
<path class="st10" d="M260.1,96.4c-0.3,15.3-1.2,25-3.6,31.2c-0.2,0.6-0.5,1.2-0.8,1.7c-3.1,6.2-8.3,7.9-16.6,7.9
s-13.5-1.7-16.6-7.9c-0.3-0.6-0.5-1.1-0.8-1.8c-2.4-6.2-3.4-15.9-3.6-31.1c-0.1-3.4-0.1-7.1-0.1-11.1c-0.1-12.7,1.8-25.4,5.8-37.5
c3.3,3.3,8.9,5.4,15.3,5.4s11.9-2.1,15.3-5.4c4,12.1,6,24.8,5.8,37.5C260.2,89.2,260.1,92.9,260.1,96.4z M252.9,81.6
c0-7.6-6.2-13.8-13.8-13.8c-7.6,0-13.8,6.2-13.8,13.8c0,7.6,6.2,13.8,13.8,13.8c0,0,0,0,0,0C246.7,95.4,252.9,89.2,252.9,81.6
L252.9,81.6z"/>
<path class="st12" d="M139.2,246.1l18.4,0.4v0.7l-19.4-0.4v-0.7V246C138.4,246.1,138.6,246.1,139.2,246.1z"/>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="112.2357" y1="190.775" x2="112.2357" y2="101.005" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<line class="st13" x1="112.2" y1="73.2" x2="112.2" y2="163"/>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="348.955" y1="195.605" x2="348.955" y2="105.835" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<line class="st14" x1="349" y1="68.4" x2="349" y2="158.2"/>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="40.9" y1="120.12" x2="40.9" y2="64.49" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<line class="st15" x1="40.9" y1="143.9" x2="40.9" y2="199.5"/>
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="64.97" y1="168.64" x2="64.97" y2="140.83" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<line class="st16" x1="65" y1="95.4" x2="65" y2="123.2"/>
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="397.23" y1="159.8" x2="397.23" y2="131.98" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<line class="st17" x1="397.2" y1="104.2" x2="397.2" y2="132"/>
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="424.75" y1="130.51" x2="424.75" y2="74.87" gradientTransform="matrix(1 0 0 -1 0 264)">
<stop offset="0" style="stop-color:#81CFFF"/>
<stop offset="1" style="stop-color:#5ECFFF;stop-opacity:0"/>
</linearGradient>
<line class="st18" x1="424.8" y1="133.5" x2="424.8" y2="189.1"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,29 +1,14 @@
<template>
<a-config-provider :locale="locale">
<router-view></router-view>
<router-view />
</a-config-provider>
</template>
<script setup name="App">
import i18n from '@/locales'
import store from '@/store'
import config from '@/config'
import { globalStore } from '@/store'
import configApi from '@/api/dev/configApi'
import { message } from 'ant-design-vue'
import tool from '@/utils/tool'
store.commit('initTheme')
const store = globalStore()
store.initTheme()
const locale = i18n.global.messages[i18n.global.locale].lang
let formData = ref(config.SYS_BASE_CONFIG)
configApi.configSysBaseList().then((data) => {
if (data) {
data.forEach((item) => {
formData.value[item.configKey] = item.configValue
})
tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
store.commit('SET_sysBaseConfig', formData.value)
}
})
</script>

View File

@ -8,9 +8,9 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
import { baseRequest } from '@/utils/request'
import { moduleRequest } from '@/utils/request'
const request = (url, ...arg) => baseRequest(`/auth/b/${url}`, ...arg)
const request = moduleRequest(`/auth/b/`)
/**
* 登录
*

View File

@ -69,5 +69,17 @@ export default {
// 给人员授权角色
grantRole(data) {
return request('grantRole', data)
},
// 人员导出
userExport(data) {
return request('export', data, 'get', {
responseType: 'blob'
})
},
// 导出人员个人信息
userExportUserInfo(data) {
return request('exportUserInfo', data, 'get', {
responseType: 'blob'
})
}
}

View File

@ -46,6 +46,10 @@ export default {
jobRunJob(data) {
return request('runJob', data)
},
// 运行定时任务
jobRunJobNow(data) {
return request('runJobNow', data)
},
// 获取定时任务类
jobGetActionClass(data) {
return request('getActionClass', data, 'get')

View File

@ -0,0 +1,45 @@
import { baseRequest } from '@/utils/request'
const request = (url, ...arg) => baseRequest(`/gen/basic/${url}`, ...arg)
export default {
// 获取代码生成基础分页
basicPage(data) {
return request('page', data, 'get')
},
// 提交表单 edit为true时为编辑默认为新增
submitForm(data, edit = false) {
return request(edit ? 'add' : 'edit', data)
},
// 删除代码生成基础
basicDelete(data) {
return request('delete', data)
},
// 获取代码生成基础详情
basicDetail(data) {
return request('detail', data, 'get')
},
// 获取所有表信息
basicTables(data) {
return request('tables', data, 'get')
},
// 获取表内所有字段信息
basicTableColumns(data) {
return request('tableColumns', data, 'get')
},
// 执行代码生成 压缩包
basicExecGenBiz(data) {
const options = {
responseType: 'blob'
}
return request('execGenZip', data, 'get', options)
},
// 执行代码生成 项目内
basicExecGenPro(data) {
return request('execGenPro', data)
},
// 预览代码生成
basicPreviewGen(data) {
return request('previewGen', data, 'get')
}
}

View File

@ -0,0 +1,26 @@
import { baseRequest } from '@/utils/request'
const request = (url, ...arg) => baseRequest(`/gen/config/${url}`, ...arg)
export default {
// 获取代码生成详情配置列表
configList(data) {
return request('list', data, 'get')
},
// 提交表单 edit为true时为编辑默认为新增
submitForm(data, edit = false) {
return request(edit ? 'add' : 'edit', data)
},
// 删除代码生成详情配置
configDelete(data) {
return request('delete', data)
},
// 获取代码生成详情配置详情
configDetail(data) {
return request('detail', data, 'get')
},
// 批量编辑代码生成详细配置
configEditBatch(data) {
return request('editBatch', data)
}
}

View File

@ -0,0 +1,37 @@
/**
* 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
*/
import { baseRequest } from '@/utils/request'
const request = (url, ...arg) => baseRequest(`/mobile/button/${url}`, ...arg)
/**
* 按钮
*
* @author yubaoshan
* @date 2022-09-22 22:33:20
*/
export default {
// 获取按钮分页
mobileButtonPage(data) {
return request('page', data, 'get')
},
// 提交表单 edit为true时为编辑默认为新增
mobileButtonSubmitForm(data, edit = false) {
return request(edit ? 'add' : 'edit', data)
},
// 删除按钮
mobileButtonDelete(data) {
return request('delete', data)
},
// 获取按钮详情
mobileButtonDetail(data) {
return request('detail', data, 'get')
}
}

View File

@ -0,0 +1,44 @@
import { baseRequest } from '@/utils/request'
const request = (url, ...arg) => baseRequest(`/mobile/menu/` + url, ...arg)
/**
* 移动端菜单Api接口管理器
*
* @author yubaoshan
* @date 2023/01/28 22:42
**/
export default {
// 获取移动端菜单tree
mobileMenuTree(data) {
return request('tree', data, 'get')
},
// 获取移动端菜单列表
mobileMenuList(data) {
return request('list', data, 'get')
},
// 提交移动端菜单表单 edit为true时为编辑默认为新增
mobileMenuSubmitForm(data, edit = false) {
return request(edit ? 'add' : 'edit', data)
},
// 更改菜单所属模块
mobileMenuChangeModule(data) {
return request('changeModule', data)
},
// 删除移动端菜单
mobileMenuDelete(data) {
return request('delete', data)
},
// 获取移动端菜单详情
mobileMenuDetail(data) {
return request('detail', data, 'get')
},
// 获取模块选择器
mobileMenuModuleSelector(data) {
return request('moduleSelector', data, 'get')
},
// 获取菜单树选择器
mobileMenuTreeSelector(data) {
return request('menuTreeSelector', data, 'get')
}
}

View File

@ -0,0 +1,37 @@
/**
* 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
*/
import { baseRequest } from '@/utils/request'
const request = (url, ...arg) => baseRequest(`/mobile/module/${url}`, ...arg)
/**
* 类别
*
* @author yubaoshan
* @date 2022-09-22 22:33:20
*/
export default {
// 获取类别分页
modulePage(data) {
return request('page', data, 'get')
},
// 提交表单 edit为true时为编辑默认为新增
submitForm(data, edit = false) {
return request(edit ? 'add' : 'edit', data)
},
// 删除类别
moduleDelete(data) {
return request('delete', data)
},
// 获取类别详情
moduleDetail(data) {
return request('detail', data, 'get')
}
}

View File

@ -46,6 +46,14 @@ export default {
roleGrantResource(data) {
return request('grantResource', data)
},
// 获取角色拥有移动端菜单
roleOwnMobileMenu(data) {
return request('ownMobileMenu', data, 'get')
},
// 给角色授权移动端菜单
roleGrantMobileMenu(data) {
return request('grantMobileMenu', data)
},
// 获取角色拥有权限
roleOwnPermission(data) {
return request('ownPermission', data, 'get')
@ -70,6 +78,10 @@ export default {
roleResourceTreeSelector(data) {
return request('resourceTreeSelector', data, 'get')
},
// 获取移动端菜单授权树
roleMobileMenuTreeSelector(data) {
return request('mobileMenuTreeSelector', data, 'get')
},
// 获取权限授权树
rolePermissionTreeSelector(data) {
return request('permissionTreeSelector', data, 'get')

View File

@ -69,5 +69,43 @@ export default {
// 给用户授权角色
grantRole(data) {
return request('grantRole', data)
},
// 获取用户拥有资源
userOwnResource(data) {
return request('ownResource', data, 'get')
},
// 给用户授权资源
userGrantResource(data) {
return request('grantResource', data)
},
// 获取用户拥有权限
userOwnPermission(data) {
return request('ownPermission', data, 'get')
},
// 给用户授权权限
userGrantPermission(data) {
return request('grantPermission', data)
},
// 下载用户导入模板
userDownloadImportUserTemplate(data) {
return request('downloadImportUserTemplate', data, 'get', {
responseType: 'blob'
})
},
// 用户导入
userImport(data) {
return request('import', data)
},
// 用户导出
userExport(data) {
return request('export', data, 'get', {
responseType: 'blob'
})
},
// 导出用户个人信息
userExportUserInfo(data) {
return request('exportUserInfo', data, 'get', {
responseType: 'blob'
})
}
}

View File

@ -0,0 +1,173 @@
@font-face {
font-family: "snowy"; /* Project id 3880534 */
src: url('iconfont.ttf?t=1675528061732') format('truetype');
}
.snowy {
font-family: "snowy" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.arrow-up-filling:before {
content: "\e688";
}
.arrow-down-filling:before {
content: "\e689";
}
.arrow-left-filling:before {
content: "\e68a";
}
.arrow-right-filling:before {
content: "\e68b";
}
.caps-unlock-filling:before {
content: "\e68c";
}
.comment-filling:before {
content: "\e68d";
}
.check-item-filling:before {
content: "\e68e";
}
.clock-filling:before {
content: "\e68f";
}
.delete-filling:before {
content: "\e690";
}
.decline-filling:before {
content: "\e691";
}
.dynamic-filling:before {
content: "\e692";
}
.intermediate-filling:before {
content: "\e693";
}
.favorite-filling:before {
content: "\e694";
}
.layout-filling:before {
content: "\e695";
}
.help-filling:before {
content: "\e696";
}
.history-filling:before {
content: "\e697";
}
.filter-filling:before {
content: "\e698";
}
.file-common-filling:before {
content: "\e699";
}
.news-filling:before {
content: "\e69a";
}
.edit-filling:before {
content: "\e69b";
}
.fullscreen-expand-filling:before {
content: "\e69c";
}
.smile-filling:before {
content: "\e69d";
}
.rise-filling:before {
content: "\e69e";
}
.picture-filling:before {
content: "\e69f";
}
.notification-filling:before {
content: "\e6a0";
}
.user-filling:before {
content: "\e6a1";
}
.setting-filling:before {
content: "\e6a2";
}
.switch-filling:before {
content: "\e6a3";
}
.work-filling:before {
content: "\e6a4";
}
.task-filling:before {
content: "\e6a5";
}
.success-filling:before {
content: "\e6a6";
}
.warning-filling:before {
content: "\e6a7";
}
.folder-filling:before {
content: "\e6a8";
}
.map-filling:before {
content: "\e6a9";
}
.prompt-filling:before {
content: "\e6aa";
}
.meh-filling:before {
content: "\e6ab";
}
.cry-filling:before {
content: "\e6ac";
}
.top-filling:before {
content: "\e6ad";
}
.home-filling:before {
content: "\e6ae";
}
.sorting:before {
content: "\e6af";
}

View File

@ -0,0 +1,289 @@
{
"id": "3880534",
"name": "snowy-app-filled",
"font_family": "snowy",
"css_prefix_text": "",
"description": "",
"glyphs": [
{
"icon_id": "15838581",
"name": "arrow-up-filling",
"font_class": "arrow-up-filling",
"unicode": "e688",
"unicode_decimal": 59016
},
{
"icon_id": "15838582",
"name": "arrow-down-filling",
"font_class": "arrow-down-filling",
"unicode": "e689",
"unicode_decimal": 59017
},
{
"icon_id": "15838583",
"name": "arrow-left-filling",
"font_class": "arrow-left-filling",
"unicode": "e68a",
"unicode_decimal": 59018
},
{
"icon_id": "15838584",
"name": "arrow-right-filling",
"font_class": "arrow-right-filling",
"unicode": "e68b",
"unicode_decimal": 59019
},
{
"icon_id": "15838585",
"name": "caps-unlock-filling",
"font_class": "caps-unlock-filling",
"unicode": "e68c",
"unicode_decimal": 59020
},
{
"icon_id": "15838586",
"name": "comment-filling",
"font_class": "comment-filling",
"unicode": "e68d",
"unicode_decimal": 59021
},
{
"icon_id": "15838587",
"name": "check-item-filling",
"font_class": "check-item-filling",
"unicode": "e68e",
"unicode_decimal": 59022
},
{
"icon_id": "15838588",
"name": "clock-filling",
"font_class": "clock-filling",
"unicode": "e68f",
"unicode_decimal": 59023
},
{
"icon_id": "15838589",
"name": "delete-filling",
"font_class": "delete-filling",
"unicode": "e690",
"unicode_decimal": 59024
},
{
"icon_id": "15838590",
"name": "decline-filling",
"font_class": "decline-filling",
"unicode": "e691",
"unicode_decimal": 59025
},
{
"icon_id": "15838591",
"name": "dynamic-filling",
"font_class": "dynamic-filling",
"unicode": "e692",
"unicode_decimal": 59026
},
{
"icon_id": "15838592",
"name": "intermediate-filling",
"font_class": "intermediate-filling",
"unicode": "e693",
"unicode_decimal": 59027
},
{
"icon_id": "15838593",
"name": "favorite-filling",
"font_class": "favorite-filling",
"unicode": "e694",
"unicode_decimal": 59028
},
{
"icon_id": "15838594",
"name": "layout-filling",
"font_class": "layout-filling",
"unicode": "e695",
"unicode_decimal": 59029
},
{
"icon_id": "15838595",
"name": "help-filling",
"font_class": "help-filling",
"unicode": "e696",
"unicode_decimal": 59030
},
{
"icon_id": "15838596",
"name": "history-filling",
"font_class": "history-filling",
"unicode": "e697",
"unicode_decimal": 59031
},
{
"icon_id": "15838597",
"name": "filter-filling",
"font_class": "filter-filling",
"unicode": "e698",
"unicode_decimal": 59032
},
{
"icon_id": "15838598",
"name": "file-common-filling",
"font_class": "file-common-filling",
"unicode": "e699",
"unicode_decimal": 59033
},
{
"icon_id": "15838599",
"name": "news-filling",
"font_class": "news-filling",
"unicode": "e69a",
"unicode_decimal": 59034
},
{
"icon_id": "15838600",
"name": "edit-filling",
"font_class": "edit-filling",
"unicode": "e69b",
"unicode_decimal": 59035
},
{
"icon_id": "15838601",
"name": "fullscreen-expand-filling",
"font_class": "fullscreen-expand-filling",
"unicode": "e69c",
"unicode_decimal": 59036
},
{
"icon_id": "15838602",
"name": "smile-filling",
"font_class": "smile-filling",
"unicode": "e69d",
"unicode_decimal": 59037
},
{
"icon_id": "15838603",
"name": "rise-filling",
"font_class": "rise-filling",
"unicode": "e69e",
"unicode_decimal": 59038
},
{
"icon_id": "15838604",
"name": "picture-filling",
"font_class": "picture-filling",
"unicode": "e69f",
"unicode_decimal": 59039
},
{
"icon_id": "15838605",
"name": "notification-filling",
"font_class": "notification-filling",
"unicode": "e6a0",
"unicode_decimal": 59040
},
{
"icon_id": "15838606",
"name": "user-filling",
"font_class": "user-filling",
"unicode": "e6a1",
"unicode_decimal": 59041
},
{
"icon_id": "15838607",
"name": "setting-filling",
"font_class": "setting-filling",
"unicode": "e6a2",
"unicode_decimal": 59042
},
{
"icon_id": "15838608",
"name": "switch-filling",
"font_class": "switch-filling",
"unicode": "e6a3",
"unicode_decimal": 59043
},
{
"icon_id": "15838609",
"name": "work-filling",
"font_class": "work-filling",
"unicode": "e6a4",
"unicode_decimal": 59044
},
{
"icon_id": "15838610",
"name": "task-filling",
"font_class": "task-filling",
"unicode": "e6a5",
"unicode_decimal": 59045
},
{
"icon_id": "15838611",
"name": "success-filling",
"font_class": "success-filling",
"unicode": "e6a6",
"unicode_decimal": 59046
},
{
"icon_id": "15838612",
"name": "warning-filling",
"font_class": "warning-filling",
"unicode": "e6a7",
"unicode_decimal": 59047
},
{
"icon_id": "15838613",
"name": "folder-filling",
"font_class": "folder-filling",
"unicode": "e6a8",
"unicode_decimal": 59048
},
{
"icon_id": "15838614",
"name": "map-filling",
"font_class": "map-filling",
"unicode": "e6a9",
"unicode_decimal": 59049
},
{
"icon_id": "15838615",
"name": "prompt-filling",
"font_class": "prompt-filling",
"unicode": "e6aa",
"unicode_decimal": 59050
},
{
"icon_id": "15838616",
"name": "meh-filling",
"font_class": "meh-filling",
"unicode": "e6ab",
"unicode_decimal": 59051
},
{
"icon_id": "15838617",
"name": "cry-filling",
"font_class": "cry-filling",
"unicode": "e6ac",
"unicode_decimal": 59052
},
{
"icon_id": "15838618",
"name": "top-filling",
"font_class": "top-filling",
"unicode": "e6ad",
"unicode_decimal": 59053
},
{
"icon_id": "15838619",
"name": "home-filling",
"font_class": "home-filling",
"unicode": "e6ae",
"unicode_decimal": 59054
},
{
"icon_id": "15838620",
"name": "sorting",
"font_class": "sorting",
"unicode": "e6af",
"unicode_decimal": 59055
}
]
}

View File

@ -0,0 +1,36 @@
/**
* 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
*/
import './line/iconfont.css'
import lineJsonData from './line/iconfont.json'
import './filled/iconfont.css'
import filledJsonData from './filled/iconfont.json'
export default {
icons: [
{
name: '基础',
key: 'default',
iconItem: [
{
name: '线框风格',
key: 'default',
item: lineJsonData.glyphs
},
{
name: '实底风格',
key: 'filled',
item: filledJsonData.glyphs
}
]
}
]
}

View File

@ -0,0 +1,825 @@
@font-face {
font-family: "snowy"; /* Project id 3791763 */
src: url('iconfont.ttf?t=1675526220710') format('truetype');
}
.snowy {
font-family: "snowy" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.export-outlined:before {
content: "\e792";
}
.experiment-outlined:before {
content: "\e7c9";
}
.expand-outlined:before {
content: "\e915";
}
.expand-alt-outlined:before {
content: "\e7e9";
}
.exception-outlined:before {
content: "\e7bb";
}
.euro-outlined:before {
content: "\e78f";
}
.euro-circle-outlined:before {
content: "\eb62";
}
.environment-outlined:before {
content: "\e790";
}
.ellipsis-outlined:before {
content: "\e815";
}
.download-outlined:before {
content: "\e814";
}
.dollar-outlined:before {
content: "\e78d";
}
.dollar-circle-outlined:before {
content: "\eb61";
}
.dislike-outlined:before {
content: "\e7c8";
}
.disconnect-outlined:before {
content: "\e7e8";
}
.dingtalk-outlined:before {
content: "\e881";
}
.desktop-outlined:before {
content: "\e845";
}
.deployment-unit-outlined:before {
content: "\e7d2";
}
.delivered-procedure-outlined:before {
content: "\e911";
}
.delete-column-outlined:before {
content: "\e901";
}
.delete-row-outlined:before {
content: "\e902";
}
.database-outlined:before {
content: "\e7b9";
}
.dashboard-outlined:before {
content: "\e78b";
}
.customer-service-outlined:before {
content: "\e7ca";
}
.crown-outlined:before {
content: "\e844";
}
.credit-card-outlined:before {
content: "\e7e5";
}
.copyright-outlined:before {
content: "\e789";
}
.copyright-circle-outlined:before {
content: "\eb60";
}
.control-outlined:before {
content: "\e79c";
}
.container-outlined:before {
content: "\e7b8";
}
.contacts-outlined:before {
content: "\e7e4";
}
.console-sql-outlined:before {
content: "\e910";
}
.compress-outlined:before {
content: "\e914";
}
.compass-outlined:before {
content: "\e786";
}
.comment-outlined:before {
content: "\e8ea";
}
.coffee-outlined:before {
content: "\e6b5";
}
.code-outlined:before {
content: "\e79b";
}
.cloud-server-outlined:before {
content: "\e7db";
}
.cloud-upload-outlined:before {
content: "\e7dc";
}
.cloud-outlined:before {
content: "\e7dd";
}
.cloud-download-outlined:before {
content: "\e7de";
}
.cloud-sync-outlined:before {
content: "\e7e0";
}
.clear-outlined:before {
content: "\e900";
}
.ci-circle-outlined:before {
content: "\e77f";
}
.carry-out-outlined:before {
content: "\e7d6";
}
.car-outlined:before {
content: "\e7da";
}
.ci-outlined:before {
content: "\eb5f";
}
.camera-outlined:before {
content: "\e7d9";
}
.calendar-outlined:before {
content: "\e7d4";
}
.calculator-outlined:before {
content: "\e79a";
}
.bulb-outlined:before {
content: "\e7c7";
}
.build-outlined:before {
content: "\e7d5";
}
.bug-outlined:before {
content: "\e8e9";
}
.branches-outlined:before {
content: "\e7e7";
}
.borderless-table-outlined:before {
content: "\e813";
}
.border-outlined:before {
content: "\e7b7";
}
.book-outlined:before {
content: "\e7b6";
}
.block-outlined:before {
content: "\e7df";
}
.bell-outlined:before {
content: "\e7c5";
}
.bars-outlined:before {
content: "\e71a";
}
.barcode-outlined:before {
content: "\e7d8";
}
.bank-outlined:before {
content: "\e7c6";
}
.audit-outlined:before {
content: "\e7c0";
}
.audio-outlined:before {
content: "\e89b";
}
.audio-muted-outlined:before {
content: "\e8e8";
}
.api-outlined:before {
content: "\e7e3";
}
.apartment-outlined:before {
content: "\e89a";
}
.alert-outlined:before {
content: "\e7c4";
}
.aim-outlined:before {
content: "\e913";
}
.account-book-outlined:before {
content: "\e7d3";
}
.column-height-outlined:before {
content: "\e811";
}
.column-width-outlined:before {
content: "\e812";
}
.radius-setting-outlined:before {
content: "\e7b5";
}
.unordered-list-outlined:before {
content: "\e80f";
}
.ordered-list-outlined:before {
content: "\e810";
}
.drag-outlined:before {
content: "\e843";
}
.sort-descending-outlined:before {
content: "\e80d";
}
.sort-ascending-outlined:before {
content: "\e80e";
}
.font-colors-outlined:before {
content: "\e808";
}
.font-size-outlined:before {
content: "\e809";
}
.line-height-outlined:before {
content: "\e80a";
}
.dash-outlined:before {
content: "\e80b";
}
.small-dash-outlined:before {
content: "\e80c";
}
.zoom-out-outlined:before {
content: "\e898";
}
.zoom-in-outlined:before {
content: "\e899";
}
.undo-outlined:before {
content: "\e787";
}
.redo-outlined:before {
content: "\e788";
}
.bold-outlined:before {
content: "\e804";
}
.strikethrough-outlined:before {
content: "\e805";
}
.underline-outlined:before {
content: "\e806";
}
.italic-outlined:before {
content: "\e807";
}
.bg-colors-outlined:before {
content: "\e803";
}
.align-right-outlined:before {
content: "\e7fb";
}
.align-left-outlined:before {
content: "\e802";
}
.align-center-outlined:before {
content: "\e7f5";
}
.highlight-outlined:before {
content: "\e7e2";
}
.diff-outlined:before {
content: "\e7bf";
}
.snippets-outlined:before {
content: "\e7bd";
}
.delete-outlined:before {
content: "\e7c3";
}
.scissor-outlined:before {
content: "\e7e6";
}
.copy-outlined:before {
content: "\e7bc";
}
.form-outlined:before {
content: "\e791";
}
.edit-outlined:before {
content: "\e7e1";
}
.stop-outlined:before {
content: "\e842";
}
.issues-close-outlined:before {
content: "\e68e";
}
.warning-outlined:before {
content: "\e682";
}
.clock-circle-outlined:before {
content: "\e784";
}
.check-circle-outlined:before {
content: "\e77d";
}
.check-square-outlined:before {
content: "\e794";
}
.check-outlined:before {
content: "\e7fc";
}
.exclamation-circle-outlined:before {
content: "\e785";
}
.exclamation-outlined:before {
content: "\e7fa";
}
.info-circle-outlined:before {
content: "\e77e";
}
.info-outlined:before {
content: "\e7f9";
}
.minus-square-outlined:before {
content: "\e796";
}
.plus-square-outlined:before {
content: "\e797";
}
.minus-circle-outlined:before {
content: "\e780";
}
.minus-outlined:before {
content: "\e801";
}
.pause-circle-outlined:before {
content: "\e783";
}
.pause-outlined:before {
content: "\e800";
}
.plus-circle-outlined:before {
content: "\e781";
}
.plus-outlined:before {
content: "\e8fe";
}
.question-circle-outlined:before {
content: "\e782";
}
.question-outlined:before {
content: "\e7ff";
}
.fullscreen-outlined:before {
content: "\e7ec";
}
.fullscreen-exit-outlined:before {
content: "\e7ed";
}
.radius-bottomleft-outlined:before {
content: "\e7b1";
}
.radius-bottomright-outlined:before {
content: "\e7b2";
}
.radius-upleft-outlined:before {
content: "\e7b3";
}
.radius-upright-outlined:before {
content: "\e7b4";
}
.pic-center-outlined:before {
content: "\e7f6";
}
.pic-right-outlined:before {
content: "\e7f7";
}
.pic-left-outlined:before {
content: "\e7f8";
}
.border-outer-outlined:before {
content: "\e7a9";
}
.border-top-outlined:before {
content: "\e7aa";
}
.border-bottom-outlined:before {
content: "\e7ab";
}
.border-left-outlined:before {
content: "\e7ac";
}
.border-right-outlined:before {
content: "\e7ad";
}
.border-inner-outlined:before {
content: "\e7ae";
}
.border-verticle-outlined:before {
content: "\e7af";
}
.border-horizontal-outlined:before {
content: "\e7b0";
}
.menu-unfold-outlined:before {
content: "\e7f3";
}
.menu-fold-outlined:before {
content: "\e7f4";
}
.logout-outlined:before {
content: "\e78c";
}
.login-outlined:before {
content: "\e8f4";
}
.cluster-outlined:before {
content: "\e7d7";
}
.down-square-outlined:before {
content: "\e793";
}
.left-square-outlined:before {
content: "\e795";
}
.right-square-outlined:before {
content: "\e798";
}
.up-Square-outlined:before {
content: "\e799";
}
.play-circle-outlined:before {
content: "\e67a";
}
.arrow-down-outlined:before {
content: "\e66d";
}
.arrow-right-outlined:before {
content: "\e66e";
}
.arrow-up-outlined:before {
content: "\e66f";
}
.arrow-left-outlined:before {
content: "\e670";
}
.swap-outlined:before {
content: "\e7f2";
}
.swap-right-outlined:before {
content: "\e8f2";
}
.swap-left-outlined:before {
content: "\e8f3";
}
.enter-outlined:before {
content: "\e7fd";
}
.rollback-outlined:before {
content: "\e7fe";
}
.retweet-outlined:before {
content: "\e8f1";
}
.fast-backward-outlined:before {
content: "\e8ed";
}
.fast-forward-outlined:before {
content: "\e8ee";
}
.vertical-align-bottom-outlined:before {
content: "\e7ef";
}
.vertical-align-middle-outlined:before {
content: "\e7f0";
}
.vertical-align-top-outlined:before {
content: "\e7f1";
}
.vertical-right-outlined:before {
content: "\e7ea";
}
.vertical-left-outlined:before {
content: "\e7eb";
}
.double-left-outlined:before {
content: "\e66b";
}
.double-right-outlined:before {
content: "\e66c";
}
.up-circle-outlined:before {
content: "\e666";
}
.right-circle-outlined:before {
content: "\e667";
}
.left-circle-outlined:before {
content: "\e66a";
}
.down-circle-outlined:before {
content: "\eb5e";
}
.caret-up-outlined:before {
content: "\e689";
}
.caret-down-outlined:before {
content: "\e68a";
}
.caret-left-outlined:before {
content: "\e68b";
}
.caret-right-outlined:before {
content: "\e68c";
}
.left-outlined:before {
content: "\e685";
}
.up-outlined:before {
content: "\e686";
}
.down-outlined:before {
content: "\e687";
}
.right-outlined:before {
content: "\e688";
}
.arrows-alt-outlined:before {
content: "\e665";
}
.shrink-outlined:before {
content: "\e68d";
}
.step-backward-outlined:before {
content: "\e8ef";
}
.step-forward-outlined:before {
content: "\e8f0";
}
.robot-outlined:before {
content: "\e897";
}
.file-word-outlined:before {
content: "\e7ba";
}
.usergroup-delete-outlined:before {
content: "\e760";
}
.field-time-outlined:before {
content: "\eb5d";
}
.setting-outlined:before {
content: "\e78e";
}
.file-search-outlined:before {
content: "\e730";
}
.team-outlined:before {
content: "\e67d";
}
.message-outlined:before {
content: "\e78a";
}
.mail-outlined:before {
content: "\e62e";
}
.send-outlined:before {
content: "\e622";
}
.appstore-add-outlined:before {
content: "\e8eb";
}
.user-outlined:before {
content: "\e641";
}
.project-outlined:before {
content: "\e746";
}
.hdd-outlined:before {
content: "\e734";
}
.tool-outlined:before {
content: "\e75b";
}
.user-switch-outlined:before {
content: "\ea3d";
}
.appstore-outlined:before {
content: "\e601";
}
.home-outlined:before {
content: "\e965";
}

File diff suppressed because it is too large Load Diff

View File

@ -1,56 +0,0 @@
// Generated by 'unplugin-auto-import'
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const hasPerm: typeof import('./utils/permission/index.js')['hasPerm']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useSlots: typeof import('vue')['useSlots']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}

View File

@ -1,7 +1,5 @@
<template>
<div class="sceditor">
<Editor v-model="contentValue" :init="init" :disabled="disabled" :placeholder="placeholder" @onClick="onClick" />
</div>
<Editor v-model="contentValue" :init="init" :disabled="disabled" :placeholder="placeholder" @onClick="onClick" />
</template>
<script>
@ -10,13 +8,15 @@
import tinymce from 'tinymce/tinymce'
import 'tinymce/themes/silver'
import 'tinymce/icons/default'
import 'tinymce/models/dom'
//
import 'tinymce/plugins/code' //
import 'tinymce/plugins/image' //
import 'tinymce/plugins/link' //
import 'tinymce/plugins/preview' //
import 'tinymce/plugins/table' //
import 'tinymce/plugins/lists' //
import 'tinymce/plugins/advlist' //
export default {
components: {
@ -41,12 +41,12 @@
},
plugins: {
type: [String, Array],
default: 'code image link preview table'
default: 'code image link preview table lists advlist'
},
toolbar: {
type: [String, Array],
default:
'undo redo | forecolor backcolor bold italic underline strikethrough link | formatselect fontselect fontsizeselect | \
'undo redo | forecolor backcolor bold italic underline strikethrough link | blocks fontfamily fontsize | \
alignleft aligncenter alignright alignjustify outdent indent lineheight | bullist numlist | \
image table preview | code selectall'
}
@ -69,15 +69,16 @@
resize: true,
elementpath: true,
content_style: '',
images_upload_handler: async (blobInfo, success, failure) => {
const data = new FormData()
data.append('file', blobInfo.blob(), blobInfo.filename())
try {
const res = await fileApi.fileUploadDynamicReturnUrl(data)
success(res)
} catch (error) {
failure('Image upload failed')
}
images_upload_handler(blobInfo, progress) {
return new Promise((resolve, reject) => {
const data = new FormData()
data.append('file', blobInfo.blob(), blobInfo.filename())
fileApi.fileUploadDynamicReturnUrl(data).then((res) => {
return resolve(res)
}).catch((err) => {
return reject('err:' + err)
})
})
},
setup: (editor) => {
editor.on('init', function () {
@ -106,5 +107,3 @@
}
}
</script>
<style></style>

View File

@ -0,0 +1,143 @@
<template>
<a-modal
v-model:visible="visible"
title="移动端图标选择"
:mask-closable="false"
:width="800"
:destroy-on-close="true"
:footer="null"
@cancel="onCancel"
>
<a-tabs v-model:activeKey="activeKey" tab-position="left" size="small" @change="paneChange">
<a-tab-pane v-for="item in iconData" :key="item.key" :tab="item.name">
<div v-if="item.iconItem.length > 1" class="xn-icon-select-radio">
<a-radio-group v-model:value="iconItemDefault" @change="radioGroupChange">
<a-radio-button v-for="iconItem in item.iconItem" :key="iconItem.key" :value="iconItem.key">{{
iconItem.name
}}</a-radio-button>
</a-radio-group>
</div>
<div :key="iconItemIns" v-for="iconItemIns in item.iconItem">
<div v-if="iconItemIns.key === iconItemDefault" class="xn-icon-select-list">
<ul>
<li
v-for="icon in iconItemIns.item"
:key="icon"
:class="icon === modelValue ? 'active' : ''"
@click="selectIcon(icon.font_class)"
>
<span class="snowy xn-icons" :class="icon.font_class" ></span>
</li>
</ul>
</div>
</div>
</a-tab-pane>
</a-tabs>
</a-modal>
</template>
<script>
import config from '@/assets/icons/mobile'
export default {
data() {
return {
visible: false,
iconData: [],
modelValue: '',
activeKey: 'default',
iconItemDefault: 'default',
}
},
mounted() {
this.iconData.push(...config.icons)
},
methods: {
//
showIconModal(value) {
this.visible = true
this.defaultSetting(value)
},
//
defaultSetting(value) {
if (value) {
this.modelValue = value
//
if (value.indexOf('-outlined') > -1 || value.indexOf('-filled') > -1 || value.indexOf('-two-tone') > -1) {
this.activeKey = 'default'
if (value.indexOf('-two-tone') > -1) {
this.iconItemDefault = 'twotone'
} else if (value.indexOf('-filled') > -1) {
this.iconItemDefault = 'filled'
}
} else if (value.indexOf('-extend') > -1) {
//
this.activeKey = 'extend'
// ,
// this.iconItemDefault = 'json'
}
}
},
//
paneChange(e) {
if (e.indexOf('default') === -1) {
this.iconItemDefault = 'default'
}
},
// icon
radioGroupChange(e) {
this.iconItemDefault = e.target.value
},
//
selectIcon(value) {
this.defaultValue = value
this.visible = false
// eslint-disable-next-line vue/require-explicit-emits
this.$emit('iconCallBack', this.defaultValue)
},
onCancel() {
this.visible = false
}
}
}
</script>
<style lang="less" scoped>
.xn-icon-select-radio {
padding-left: 5px;
padding-bottom: 10px;
}
.xn-icons {
font-size: 26px;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.xn-icon-select-list {
height: 360px;
overflow: auto;
}
.xn-icon-select-list ul {
li {
display: inline-block;
width: 60px;
height: 60px;
padding: 18px;
margin: 5px;
border-radius: 2px;
vertical-align: top;
box-shadow: 0 0 0 1px var(--border-color-split);
transition: all 0.1s;
position: relative;
&:hover,
&.active {
cursor: pointer;
color: #ffffff;
background-color: var(--primary-color);
}
}
}
</style>

View File

@ -60,7 +60,7 @@
},
//
defaultSetting(value) {
if ((value !== undefined) & (value !== '') & (value !== 'undefined')) {
if (value) {
this.modelValue = value
//
if (value.indexOf('-outlined') > -1 || value.indexOf('-filled') > -1 || value.indexOf('-two-tone') > -1) {

View File

@ -6,6 +6,7 @@
import './index.less'
export default {
name: 'STable',
components: {
draggable,
columnSetting
@ -13,10 +14,8 @@
data() {
return {
needTotalList: [],
selectedRows: [],
selectedRowKeys: [],
localLoading: false,
localDataSource: [],
localPagination: Object.assign({}, this.pagination),
@ -44,8 +43,8 @@
default: 1
},
size: {
// type: Number,
default: '10'
type: Number,
default: 10
},
showSizeChanger: {
type: Boolean,
@ -72,6 +71,14 @@
type: [String, Boolean],
default: 'auto'
},
defaultPageSize: {
type: Number,
default: 10
},
pageSizeOptions: {
type: Array,
default: () => ['10', '20', '50', '100']
},
/**
* enable page URI mode
*
@ -137,10 +144,12 @@
(['auto', true].includes(this.showPagination) &&
Object.assign({}, this.localPagination, {
current: localPageNum,
size: this.size, //this.compSize, size//
pageSize: this.size, //this.compSize, size//
showSizeChanger: this.showSizeChanger,
defaultPageSize: this.defaultPageSize,
pageSizeOptions: this.pageSizeOptions,
showTotal: (total, range) => {
return `${range[0]}-${range[1]}${total}`
return `${range[0]}-${range[1]} ${total} `
}
})) ||
false
@ -160,7 +169,7 @@
{},
{
current: 1,
size: this.size
pageSize: this.localPagination.pageSize
}
))
this.loadData()
@ -179,7 +188,12 @@
(pagination && pagination.current) ||
(this.showPagination && this.localPagination.current) ||
this.pageNum,
size: (pagination && pagination.pageSize) || (this.showPagination && this.localPagination.size) || this.size
// 使size
size:
(pagination && pagination.pageSize) ||
(this.showPagination && this.localPagination.pageSize) ||
this.pageSize ||
this.localPagination.pageSize
},
(sorter &&
sorter.field && {
@ -196,7 +210,6 @@
}
)
const result = this.data(parameter)
// r.current, r.totalCount, r.data
// eslint-disable-next-line
if (
(typeof result === 'object' || typeof result === 'function') &&
@ -213,7 +226,10 @@
current: r.current, // pageNo, //
total: r.total, // totalRows, //
showSizeChanger: this.showSizeChanger,
size: (pagination && pagination.size) || this.localPagination.size
showTotal: (total, range) => {
return `${range[0]}-${range[1]}${total}`
},
pageSize: (pagination && pagination.pageSize) || this.localPagination.pageSize
})) ||
false
// recordsnull
@ -226,11 +242,14 @@
this.loadData()
return
}
// r.totalCount(total) this.showPagination = true current size totalCount current * size
// table
try {
if (['auto', true].includes(this.showPagination) && r.total <= r.pages * this.localPagination.size) {
/*
if ((['auto', true].includes(this.showPagination) && r.total <= (r.pages * this.localPagination.size))) {
this.localPagination.hideOnSinglePage = true
}
*/
if (!this.showPagination) {
this.localPagination.hideOnSinglePage = true
}
} catch (e) {
@ -238,8 +257,11 @@
}
//
if (this.showPagination === false) {
// datadata
this.localDataSource = r
//
this.localDataSource = []
if (r instanceof Array) {
this.localDataSource = r
}
} else {
this.localDataSource = r.records
}
@ -321,21 +343,19 @@
const needTotalItems = this.needTotalList.map((item) => {
return (
<span className="mr-3">
{item.title}总计{' '}
{item.title} 总计{' '}
<a className="font-6">{!item.customRender ? item.total : item.customRender(item.total)}</a>
</span>
)
})
//
// eslint-disable-next-line no-unused-vars
const clearItem =
typeof this.alert.clear === 'boolean' && this.alert.clear
typeof this.alert === 'boolean' && this.alert
? this.renderClear(this.clearSelected)
: typeof this.alert.clear === 'function'
? this.renderClear(this.alert.clear)
: null
// alert
if (alert) {
const message = (
@ -347,7 +367,6 @@
{clearItem}
</div>
)
return <a-alert showIcon class="mb-4" message={message} />
}
},
@ -400,24 +419,21 @@
}
//
const changeRowClass = (val) => {
const changeRowClass = (value) => {
const val = value.target.checked
this.localSettings.rowClassNameSwitch = val
const evenClass = val ? (_record, index) => (index % 2 === 1 ? 'table-striped' : null) : this.rowClassName
this.localSettings.rowClassName = evenClass
}
return (
<div className="s-table-tool">
<div className="s-table-tool-left">{this.$slots.operator && this.$slots.operator()}</div>
<div className="layout-items-center s-table-tool-right">
{this.toolConfig.striped ? (
<div className="layout-items-center ml-4">
<span>斑马线</span>
<a-switch
checked={this.localSettings.rowClassNameSwitch}
onChange={changeRowClass}
className="ml-2"
/>
<a-checkbox checked={this.localSettings.rowClassNameSwitch} onChange={changeRowClass}>
斑马纹
</a-checkbox>
</div>
) : null}
@ -430,7 +446,6 @@
{tool.icon}
</a-tooltip>
)
if (tool.isPopover) {
return (
<a-popover

View File

@ -0,0 +1,67 @@
<template>
<a-popconfirm
title="批量处理此信息?"
:visible="batchVisible"
@visibleChange="batchVisibleChange"
@confirm="deleteBatch"
>
<a-button :type="props.buttonType" :danger="props.buttonDanger">
<template #icon v-if="props.icon">
<component :is="props.icon" />
</template>
{{ props.buttonName }}
</a-button>
</a-popconfirm>
</template>
<script setup name="commonBatchButton">
import { message } from 'ant-design-vue'
const batchVisible = ref(false)
const emit = defineEmits({ batchCallBack: null })
const props = defineProps({
buttonName: {
type: String,
default: () => '批量操作'
},
buttonDanger: {
type: Boolean,
default: () => false
},
buttonType: {
type: String,
default: () => ''
},
icon: {
type: String,
default: () => ''
},
selectedRowKeys: {
type: Array,
default: () => []
}
})
//
const batchVisibleChange = () => {
if (batchVisible.value) {
batchVisible.value = false
return false
}
if (props.selectedRowKeys.length < 1) {
message.warning('请选择一条或多条数据')
batchVisible.value = false
return false
} else {
batchVisible.value = true
}
}
//
const deleteBatch = () => {
const params = props.selectedRowKeys.map((m) => {
return {
id: m
}
})
//
emit('batchCallBack', params)
}
</script>

View File

@ -0,0 +1,53 @@
<template>
<a-popconfirm
title="删除此信息?"
:visible="deleteVisible"
@visibleChange="deleteVisibleChange"
@confirm="deleteBatch"
>
<a-button danger>
<template #icon><delete-outlined /></template>
{{ props.buttonName }}
</a-button>
</a-popconfirm>
</template>
<script setup name="commonBatchDelete">
import { message } from 'ant-design-vue'
const deleteVisible = ref(false)
const emit = defineEmits({ batchDelete: null })
const props = defineProps({
buttonName: {
type: String,
default: () => '批量删除'
},
selectedRowKeys: {
type: Array,
default: () => []
}
})
//
const deleteVisibleChange = () => {
if (deleteVisible.value) {
deleteVisible.value = false
return false
}
if (props.selectedRowKeys.length < 1) {
message.warning('请选择一条或多条数据')
deleteVisible.value = false
return false
} else {
deleteVisible.value = true
}
}
//
const deleteBatch = () => {
const params = props.selectedRowKeys.map((m) => {
return {
id: m
}
})
//
emit('batchDelete', params)
}
</script>

View File

@ -0,0 +1,88 @@
<template>
<div :style="style" v-show="show" @mousedown.stop @contextmenu.prevent>
<slot></slot>
</div>
</template>
<script>
export default {
name: 'XnContextMenu',
props: {
target: null,
show: Boolean
},
data() {
return {
triggerShowFn: () => {},
triggerHideFn: () => {},
x: null,
y: null,
style: {},
binded: false
}
},
watch: {
show(show) {
if (show) {
this.bindHideEvents()
} else {
this.unbindHideEvents()
}
},
target(target) {
this.bindEvents()
}
},
mounted() {
this.bindEvents()
},
methods: {
//
bindEvents() {
this.$nextTick(() => {
if (!this.target || this.binded) return
this.triggerShowFn = this.contextMenuHandler.bind(this)
this.target.addEventListener('contextmenu', this.triggerShowFn)
this.binded = true
})
},
//
unbindEvents() {
if (!this.target) return
this.target.removeEventListener('contextmenu', this.triggerShowFn)
},
//
bindHideEvents() {
this.triggerHideFn = this.clickDocumentHandler.bind(this)
document.addEventListener('mousedown', this.triggerHideFn)
document.addEventListener('mousewheel', this.triggerHideFn)
},
//
unbindHideEvents() {
document.removeEventListener('mousedown', this.triggerHideFn)
document.removeEventListener('mousewheel', this.triggerHideFn)
},
//
clickDocumentHandler(e) {
this.$emit('update:show', false)
},
//
contextMenuHandler(e) {
this.x = e.clientX
this.y = e.clientY
this.layout()
this.$emit('update:show', true)
this.$emit('get-context-menu', e)
e.preventDefault()
},
//
layout() {
this.style = {
left: this.x + 'px',
top: this.y + 'px',
display: 'block'
}
}
}
}
</script>

View File

@ -0,0 +1,47 @@
<template>
<a-modal v-if="isModal" :visible="visible" @cancel="cancel" v-bind="$attrs">
<template v-for="slotKey in slotKeys" #[slotKey]>
<slot :name="slotKey" />
</template>
</a-modal>
<a-drawer v-else :visible="visible" v-bind="$attrs" :footer-style="{ textAlign: 'right' }">
<template v-for="slotKey in slotKeys" #[slotKey]>
<slot :name="slotKey" />
</template>
</a-drawer>
</template>
<script>
import { mapState } from 'pinia'
import { globalStore } from '@/store'
const FormContainerTypeEnum = {
DRAWER: 'drawer',
MODAL: 'modal'
}
export default {
name: 'XnFormContainer',
inheritAttrs: false,
props: {
visible: {
type: Boolean,
default: false,
required: true
}
},
computed: {
...mapState(globalStore, ['formStyle']),
slotKeys() {
return Object.keys(this.$slots)
},
isModal() {
return FormContainerTypeEnum.MODAL === this.formStyle
}
},
methods: {
cancel() {
this.$emit('close')
}
}
}
</script>

View File

@ -1,7 +1,7 @@
<template>
<!-- 本组件这兄弟写的很好 请参照https://blog.csdn.net/weixin_41897680/article/details/124925222-->
<div class="hljs-container" :codetype="props.language">
<highlightjs :language="props.language" :autodetect="false" :code="props.code"></highlightjs>
<highlightjs :language="props.language" :autodetect="!props.language" :code="props.code"></highlightjs>
</div>
</template>
@ -13,7 +13,7 @@
const props = defineProps({
language: {
type: String,
default: () => 'JavaScript'
default: () => undefined
},
code: {
type: String,
@ -54,7 +54,7 @@
}*/
/** 滚动条 */
/*:deep(.hljs,.hljs-container) {
:deep(.hljs,.hljs-container) {
max-height: 300px!important;
overflow-x: auto;
}
@ -87,5 +87,5 @@
::-webkit-scrollbar-button {
display: none;
}*/
}
</style>

View File

@ -1,5 +1,12 @@
<template>
<a-modal ref="signModel" v-model:visible="visible" :width="600" title="电子签名" @cancel="handleClear" @ok="handleOk">
<xn-form-container
ref="signModel"
v-model:visible="visible"
:width="700"
title="电子签名"
@close="handleClear"
@ok="handleOk"
>
<a-row :gutter="5">
<a-col :span="15">
<div style="border: 1px solid rgb(236 236 236)">
@ -40,7 +47,11 @@
<a-button @click="handleReset">清屏</a-button>
</a-space>
</div>
</a-modal>
<template #footer>
<a-button style="margin-right: 8px" @click="handleClear">取消</a-button>
<a-button type="primary" @click="handleOk">确定</a-button>
</template>
</xn-form-container>
</template>
<script setup>

View File

@ -36,6 +36,7 @@
import tool from '@/utils/tool'
import sysConfig from '@/config/index'
const fileList = ref([])
const emit = defineEmits({ uploadDone: null })
const headers = ref({
token: tool.data.get('TOKEN')
})
@ -45,12 +46,6 @@
default: '/dev/file/uploadDynamicReturnUrl',
required: false
},
//
allowMultiple: {
type: Boolean,
default: false,
required: false
},
// defaults || drag
uploadMode: {
type: String,
@ -66,22 +61,20 @@
})
const action = sysConfig.API_URL + props.action
const handleChange = () => {}
//
const getUploadData = () => {
return fileList.value.map((item) => {
return {
uid: item.uid,
name: item.name,
status: item.status,
url: item.response.data
const handleChange = () => {
let result = []
for (let a = 0; a < props.uploadMumber; a++) {
const file = fileList.value[a]
if (file.status === 'done' && file.response && file.response.code === 200) {
const resultObj = {
name: file.name,
url: file.response.data
}
result.push(resultObj)
}
})
}
if (result.length > 0) {
emit('uploadDone', result)
}
}
defineExpose({
getUploadData
})
</script>
<style scoped></style>

View File

@ -27,19 +27,6 @@ body {
margin: 24px 0 0;
}
}
/**
* ant-table-wrapper
* 覆盖的表格手机模式样式,如果想修改在手机上表格最低宽度,可以在这里改动
*/
.ant-table-wrapper {
.ant-table-content {
overflow-y: auto;
}
.ant-table-body {
min-width: 800px;
}
}
.topmenu {
/* 必须为 topmenu 才能启用流式布局 */
&.content-width-Fluid {

View File

@ -16,7 +16,7 @@ const DEFAULT_CONFIG = {
API_URL: import.meta.env.VITE_API_BASEURL,
// 请求超时
TIMEOUT: 10000,
TIMEOUT: 60000,
// TokenName // Authorization
TOKEN_NAME: 'token',
@ -36,7 +36,7 @@ const DEFAULT_CONFIG = {
// 菜单是否折叠
SNOWY_MENU_COLLAPSE: false,
// 目录
// 模块
SNOWY_MODULE_UNFOLD_OPEN: true,
// 是否开启多标签
@ -63,10 +63,15 @@ const DEFAULT_CONFIG = {
// 默认整体主题
SNOWY_THEME: 'dark',
// 整体表单风格
SNOWY_FORM_STYLE: 'drawer',
// 成功色
success: '#52c41a',
// 警告色
warning: '#faad14',
// 错误色
error: '#f5222f',

View File

@ -1,18 +1,8 @@
/* eslint-disable eqeqeq */
<!--
* @Descripttion: 处理iframe持久化涉及store(VUEX)
* @version: 1.0
* @Author: sakuya
* @Date: 2021年6月30日13:20:41
* @LastEditors:
* @LastEditTime:
-->
<template>
<div v-show="$route.meta.type == 'iframe'" class="iframe-pages">
<div v-show="$route.meta.type === 'iframe'" class="iframe-pages">
<iframe
v-for="item in iframeList"
v-show="$route.meta.url == item.meta.url"
v-show="$route.meta.url === item.meta.url"
:key="item.meta.url"
:src="item.meta.url"
frameborder="0"
@ -21,20 +11,16 @@
</template>
<script>
import { mapState, mapActions } from 'pinia'
import { iframeStore, globalStore } from '@/store'
export default {
data() {
return {}
},
computed: {
iframeList() {
return this.$store.state.iframe.iframeList
},
ismobile() {
return this.$store.state.global.ismobile
},
layoutTags() {
return this.$store.state.global.layoutTags
}
...mapState(iframeStore, ['iframeList']),
...mapState(globalStore, ['ismobile', 'layoutTags'])
},
watch: {
$route(e) {
@ -46,16 +32,16 @@
},
mounted() {},
methods: {
...mapActions(iframeStore, ['setIframeList', 'pushIframeList', 'clearIframeList']),
push(route) {
// eslint-disable-next-line eqeqeq
if (route.meta.type == 'iframe') {
if (route.meta.type === 'iframe') {
if (this.ismobile || !this.layoutTags) {
this.$store.commit('setIframeList', route)
this.setIframeList(route)
} else {
this.$store.commit('pushIframeList', route)
this.pushIframeList(route)
}
} else if (this.ismobile || !this.layoutTags) {
this.$store.commit('clearIframeList')
this.clearIframeList()
}
}
}

View File

@ -0,0 +1,58 @@
import { mapState, mapActions } from 'pinia'
import hotkeys from 'hotkeys-js'
import { searchStore } from '@/store'
export default {
mounted() {
// 绑定搜索功能快捷键 [ 打开 ]
hotkeys(this.searchHotkey.open, (event) => {
event.preventDefault()
this.searchPanelOpen()
})
// 绑定搜索功能快捷键 [ 关闭 ]
hotkeys(this.searchHotkey.close, (event) => {
event.preventDefault()
this.searchPanelClose()
})
},
beforeDestroy() {
hotkeys.unbind(this.searchHotkey.open)
hotkeys.unbind(this.searchHotkey.close)
},
computed: {
...mapState(searchStore, {
searchActive: (state) => state.active,
searchHotkey: (state) => state.hotkey
})
},
methods: {
...mapActions(searchStore, ['toggleActive', 'setActive']),
// 接收点击搜索按钮
handleSearchClick() {
this.toggleActive()
if (this.searchActive) {
setTimeout(() => {
if (this.$refs.panelSearch) {
this.$refs.panelSearch.focus()
}
}, 300)
}
},
searchPanelOpen() {
if (!this.searchActive) {
this.setActive(true)
setTimeout(() => {
if (this.$refs.panelSearch) {
this.$refs.panelSearch.focus()
}
}, 300)
}
},
// 关闭搜索面板
searchPanelClose() {
if (this.searchActive) {
this.setActive(false)
}
}
}
}

View File

@ -1,15 +1,27 @@
<template>
<div v-if="moduleUnfoldOpen">
<a-menu v-model:selectedKeys="selectedKeys" mode="horizontal" v-if="menu && menu.length > 1" class="module-menu" id="moduleMunu">
<a-menu-item v-for="item in menu" :key="item.id" style="padding-right: 5px" @click="moduleClick(item.id)">
<div class="layout-items-center" v-if="moduleUnfoldOpen">
<a-menu
v-model:selectedKeys="selectedKeys"
mode="horizontal"
v-if="menu && menu.length > 1"
class="module-menu"
id="moduleMunu"
>
<a-menu-item
v-for="item in menu"
:key="item.id"
class="!px-3"
style="position: relative"
@click="moduleClick(item.id)"
>
<template #icon>
<component :is="item.meta.icon"/>
<component :is="item.meta.icon" />
</template>
<span style="margin-left:-5px">{{ item.meta.title }}</span>
<span style="margin-left: -5px">{{ item.meta.title }}</span>
</a-menu-item>
</a-menu>
</div>
<div v-else>
<div v-else class="panel-item hidden-sm-and-down">
<a-popover v-if="menu.length > 1" placement="bottomLeft">
<template #content>
<a-row :gutter="[0, 5]" class="module-row">
@ -23,9 +35,7 @@
</div>
</a-row>
</template>
<div class="module-comp">
<appstore-outlined />
</div>
<appstore-outlined />
</a-popover>
</div>
</template>
@ -33,18 +43,23 @@
<script setup>
import router from '@/router'
import tool from '@/utils/tool'
import store from '@/store'
import { globalStore } from '@/store'
import { watch } from 'vue'
import { storeToRefs } from 'pinia'
const store = globalStore()
const { moduleUnfoldOpen, topHanderThemeColorOpen } = storeToRefs(store)
const moduleBackColor = ref(topHanderThemeColorOpen)
//
watch(() => store.state.global.moduleUnfoldOpen, (newValue) => {
moduleUnfoldOpen.value = newValue
watch(moduleUnfoldOpen, (newValue) => {
nextTick(() => {
setModuleBackColor()
})
})
//
watch(() => store.state.global.topHanderThemeColorOpen, (newValue) => {
watch(topHanderThemeColorOpen, (newValue) => {
moduleBackColor.value = newValue
setModuleBackColor()
})
@ -60,26 +75,27 @@
})
}
const moduleUnfoldOpen = ref(store.state.global.moduleUnfoldOpen)
const moduleBackColor = ref(store.state.global.topHanderThemeColorOpen)
onMounted(() => {
setModuleBackColor()
})
//
const setModuleBackColor = () => {
if (moduleUnfoldOpen.value) {
const moduleMunu = document.getElementById('moduleMunu')
moduleBackColor.value? moduleMunu.classList.add('module-menu-color')
: moduleMunu.classList.remove('module-menu-color')
try {
const moduleMunu = document.getElementById('moduleMunu')
moduleBackColor.value
? moduleMunu.classList.add('module-menu-color')
: moduleMunu.classList.remove('module-menu-color')
} catch (err) {}
setSelectedKeys()
}
}
//
const setSelectedKeys = () => {
//
moduleBackColor.value? selectedKeys.value = new Array([])
: selectedKeys.value = [tool.data.get('SNOWY_MENU_MODULE_ID')]
moduleBackColor.value
? (selectedKeys.value = new Array([]))
: (selectedKeys.value = [tool.data.get('SNOWY_MENU_MODULE_ID')])
}
</script>
@ -99,32 +115,23 @@
.module-card-icon {
color: white;
font-size: 20px;
padding-top: 20px;
margin-top: 20px;
}
.module-card-font {
color: white;
font-size: 8px;
}
.module-comp {
display: flex;
padding: 0 15px;
height: 49px;
text-align: center;
justify-content: center;
align-items: center;
cursor: pointer;
}
.module-comp:hover {
background: var(--header-color-split);
}
.ant-menu-horizontal > .ant-menu-item::after, .ant-menu-horizontal > .ant-menu-submenu::after {
.ant-menu-horizontal > .ant-menu-item::after,
.ant-menu-horizontal > .ant-menu-submenu::after {
content: none;
}
.module-menu{
.module-menu {
line-height: 50px;
border-bottom: 0px
border-bottom: 0px;
width: 105%;
flex: 0 0 auto;
}
.module-menu-color{
.module-menu-color {
color: white;
background-color: var(--primary-color);
}

View File

@ -0,0 +1,275 @@
<template>
<div @keyup.up="handleKeyUp" @keyup.down="handleKeyDown" @keyup.enter="handleKeyEnter" @click.self="handlePanelClick">
<a-input
ref="input"
v-model="searchText"
class="search-box"
style="width: 100%"
allowClear
placeholder="搜索页面(支持拼音检索)"
@change="querySearch"
>
<template #prefix>
<search-outlined />
</template>
</a-input>
<a-card
:body-style="{ padding: '0 0' }"
hoverable
@mouseenter="onCardIn"
@mouseleave="onCardOut"
@keypress.up="handleKeyUp"
@keypress.down="handleKeyDown"
style="margin: 10px 0"
>
<div ref="cardList" class="search-card beauty-scroll">
<a-list size="small" :data-source="resultsList">
<template #renderItem="{ item, index }">
<a-list-item
@click="handleSelect(item.fullPath)"
@mouseover="onCardItemHover(index)"
:class="{ active: index === cardIndex }"
style="padding-right: 10px"
>
<template #actions>
<a>
<enter-outlined />
</a>
</template>
<a-list-item-meta :description="item.fullName">
<template #title>
<a>{{ item.name }}</a>
</template>
<template #avatar>
<a-avatar style="color: var(--text-color); background-color: transparent" :type="item.icon">
<template #icon>
<component :is="item.icon" />
</template>
</a-avatar>
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
</div>
</a-card>
<div class="search-tips">
<span class="key">S</span>
<span class="tips">打开搜索面板</span>
<span class="key">
<arrow-up-outlined />
</span>
<span class="key">
<arrow-down-outlined />
</span>
<span class="tips">选择</span>
<span class="key">
<enter-outlined />
</span>
<span class="tips">确认</span>
<span class="key left">Esc</span>
<span class="tips">关闭</span>
</div>
</div>
</template>
<script>
import Fuse from 'fuse.js'
import { mapState } from 'pinia'
import { searchStore } from '@/store'
export default {
data() {
return {
searchText: '',
cardIndex: 0,
results: []
}
},
computed: {
...mapState(searchStore, ['pool']),
//
resultsList() {
return this.results.length === 0 || this.searchText === '' ? this.pool : this.results
},
// pool fuse
fuse() {
return new Fuse(this.pool, {
shouldSort: true, //
threshold: 0.6, //
location: 0, //
distance: 100, //
minMatchCharLength: 1, //
keys: ['name', 'namePinyin', 'namePinyinFirst']
})
}
},
methods: {
//
querySearch(e) {
let queryString = e.target.value || ''
const results = queryString && this.fuse.search(queryString).map((e) => e.item)
this.searchText = queryString
this.results = results
},
//
focus() {
this.searchText = ''
setTimeout(() => {
if (this.$refs.input) {
this.$refs.input.focus()
}
//
this.searchText = ''
this.results = []
}, 300)
},
handleKeyEnter() {
let idx = this.cardIndex
if (this.resultsList[idx]) {
this.handleSelect(this.resultsList[idx].fullPath)
}
},
handleKeyUp() {
this.handleKeyUpOrDown(true)
},
handleKeyDown() {
this.handleKeyUpOrDown(false)
},
handleKeyUpOrDown(up) {
let len = this.resultsList.length - 1
let idx = this.cardIndex
if (up) {
//
if (idx > 0) {
idx--
} else {
idx = len
}
} else {
//
if (idx < len) {
idx++
} else {
idx = 0
}
}
this.cardIndex = idx
if (this.$refs.cardList.getElementsByClassName('ant-list-item')[idx]) {
this.$refs.cardList.scrollTop = this.$refs.cardList.getElementsByClassName('ant-list-item')[idx].offsetTop
} else {
this.$refs.cardList.scrollTop = 0
}
},
onCardIn() {
this.$refs.input.activated = false
this.$refs.input.blur()
},
onCardOut() {
this.cardIndex = -1
},
onCardItemHover(index) {
this.cardIndex = index
},
//
handleSelect(path) {
//
if (path === this.$route.path) {
this.handleEsc()
return
}
this.$router.push({ path })
this.handleEsc()
},
//
closeSuggestion() {
if (this.$refs.input.activated) {
this.results = []
this.$refs.input.activated = false
}
},
//
handlePanelClick(e) {
if ('INPUT' !== e.target.tagName) {
this.handleEsc()
}
},
//
async handleEsc() {
this.closeSuggestion()
await this.$nextTick()
this.$emit('close')
}
}
}
</script>
<style lang="less" scoped>
:deep(.ant-input) {
height: 35px;
}
:deep(.ant-input:not(:first-child)) {
padding-left: 10px;
}
:deep(.ant-input-prefix) {
font-size: 20px;
}
:deep(.ant-list-sm .ant-list-item) {
padding: 4px 16px;
}
:deep(.ant-list-item-meta) {
align-items: center;
}
:deep(.ant-list-item.active) {
background-color: var(--primary-1);
}
.search-box {
width: 100%;
}
.beauty-scroll {
scrollbar-color: var(--primary-color) var(--primary-2);
scrollbar-width: thin;
-ms-overflow-style: none;
position: relative;
&::-webkit-scrollbar {
width: 3px;
height: 1px;
}
&::-webkit-scrollbar-thumb {
border-radius: 3px;
background: var(--primary-color);
}
&::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 1px rgba(0, 0, 0, 0);
border-radius: 3px;
background: var(--primary-3);
}
}
.search-card {
height: 220px;
overflow: hidden;
overflow-y: scroll;
}
.search-tips {
display: flex;
border-top: 1px solid var(--component-background);
padding-top: 10px;
.tips {
margin-right: 10px;
}
.key {
width: 30px;
height: 20px;
line-height: 20px;
text-align: center;
padding-bottom: 2px;
margin: 0px 4px;
border-radius: 2px;
box-shadow: inset 0 -2px #cdcde6, inset 0 0 1px 1px #fff, 0 1px 2px 1px #1e235a66;
font-weight: bold;
}
}
</style>

View File

@ -0,0 +1,102 @@
<template>
<div class="d2-panel-search-item" :class="hoverMode ? 'can-hover' : ''" flex>
<div class="d2-panel-search-item__icon" flex-box="0">
<div class="d2-panel-search-item__icon-box" flex="main:center cross:center">
<a-icon v-if="item.icon" :type="item.icon" />
<a-icon v-else type="menu" />
</div>
</div>
<div class="d2-panel-search-item__info" flex-box="1" flex="dir:top">
<div class="d2-panel-search-item__info-title" flex-box="1" flex="cross:center">
<span>{{ item.title }}</span>
</div>
<div class="d2-panel-search-item__info-fullTitle" flex-box="0">
<span>{{ item.fullTitle }}</span>
</div>
<div class="d2-panel-search-item__info-path" flex-box="0">
<span>{{ item.path }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
item: {
default: () => ({})
},
hoverMode: {
default: false
}
}
}
</script>
<style lang="less" scoped>
.d2-panel-search-item {
height: 64px;
margin: 0px -20px;
&.can-hover {
margin: 0px;
&:hover {
background-color: #f5f7fa;
.d2-panel-search-item__icon {
.d2-panel-search-item__icon-box {
i {
font-size: 24px;
color: var(--primary-color);
}
}
}
.d2-panel-search-item__info {
.d2-panel-search-item__info-title {
//color: $color-text-main;
}
.d2-panel-search-item__info-fullTitle {
//color: $color-text-normal;
}
.d2-panel-search-item__info-path {
//color: $color-text-normal;
}
}
}
}
.d2-panel-search-item__icon {
width: 64px;
.d2-panel-search-item__icon-box {
height: 64px;
width: 64px;
border-right: 1px solid #ccc;
i {
font-size: 20px;
//color: $color-text-sub;
}
svg {
height: 20px;
width: 20px;
}
}
}
.d2-panel-search-item__info {
margin-left: 10px;
.d2-panel-search-item__info-title {
font-size: 16px;
line-height: 16px;
font-weight: bold;
//color: $color-text-normal;
}
.d2-panel-search-item__info-fullTitle {
font-size: 10px;
line-height: 14px;
color: grey;
}
.d2-panel-search-item__info-path {
margin-bottom: 4px;
font-size: 10px;
line-height: 14px;
color: grey;
}
}
}
</style>

View File

@ -4,20 +4,21 @@
<h3>整体风格设置</h3>
<div class="snowy-setting-checkbox">
<a-tooltip v-for="(a, i) in sideStyleList" :key="i" placement="top">
<template #title
><span>{{ a.tips }}</span></template
>
<template #title>
<span>{{ a.tips }}</span>
</template>
<div :class="['snowy-setting-checkbox-item', a.style]" @click="setSideStyle(a.value)">
<check-outlined v-if="sideStyle === a.value" class="snowy-setting-checkbox-item-select-icon" />
<check-outlined v-if="theme === a.value" class="snowy-setting-checkbox-item-select-icon" />
</div>
</a-tooltip>
</div>
<h3>整体界面布局</h3>
<div class="snowy-setting-checkbox">
<a-tooltip v-for="(a, i) in layoutList" :key="i" placement="top">
<template #title
><span>{{ a.tips }}</span></template
>
<template #title>
<span>{{ a.tips }}</span>
</template>
<div :class="['snowy-setting-checkbox-item', a.style]" @click="layoutStyle(a.value)">
<div class="snowy-setting-layout-menu-doublerow-inner" />
<check-outlined v-if="layout === a.value" class="snowy-setting-checkbox-item-select-icon" />
@ -25,9 +26,9 @@
</a-tooltip>
</div>
<a-divider />
<div :style="{ marginBottom: '24px' }">
<div class="mb-4">
<h3>主题色</h3>
<div style="height: 50px">
<div class="h-[50px]">
<a-tooltip v-for="(item, index) in colorList" :key="index" class="snowy-setting-theme-color-colorBlock">
<template #title>
<span>{{ item.key }}</span>
@ -38,37 +39,44 @@
</a-tooltip>
</div>
</div>
<div :style="{ marginBottom: '24px' }">
<span
><h4>顶栏应用主题色<a-switch style="float: right" v-model:checked="topHanderThemeColorOpen" /></h4
></span>
<div class="mb-4 layout-slide">
<h4 class="">顶栏应用主题色</h4>
<a-switch :checked="topHanderThemeColorOpen" @change="changeTopHanderThemeColorOpen" />
</div>
<div :style="{ marginBottom: '24px' }">
<span
><h4>
顶栏主题色通栏<a-switch
style="float: right"
v-model:checked="topHanderThemeColorSpread"
:disabled="!topHanderThemeColorOpen"
/></h4
></span>
<div class="mb-4 layout-slide">
<h4>顶栏主题色通栏</h4>
<a-switch
style="float: right"
:checked="topHanderThemeColorSpread"
:disabled="!topHanderThemeColorOpen"
@change="changeTopHanderThemeColorSpread"
/>
</div>
<a-divider />
<a-form ref="form" style="text-align: right">
<a-form-item label="目录坞">
<a-switch v-model:checked="moduleUnfoldOpen" />
<a-form ref="form" class="text-right">
<a-form-item label="模块坞">
<a-switch :checked="moduleUnfoldOpen" @change="toggleState('moduleUnfoldOpen')" />
</a-form-item>
<a-form-item label="面包屑">
<a-switch v-model:checked="breadcrumbOpen" />
<a-switch :checked="breadcrumbOpen" @change="toggleState('breadcrumbOpen')" />
</a-form-item>
<a-form-item label="多标签">
<a-switch v-model:checked="layoutTagsOpen" />
<a-switch :checked="layoutTagsOpen" @change="toggleState('layoutTagsOpen')" />
</a-form-item>
<a-form-item label="折叠菜单">
<a-switch v-model:checked="menuIsCollapse" />
<a-switch :checked="menuIsCollapse" @change="toggleState('menuIsCollapse')" />
</a-form-item>
<a-form-item label="菜单排他展开">
<a-switch v-model:checked="sideUniqueOpen" />
<a-switch :checked="sideUniqueOpen" @change="toggleState('sideUniqueOpen')" />
</a-form-item>
<a-form-item label="表单风格">
<a-select
:value="formStyle"
class="!w-[80px]"
size="small"
:options="xnFormStyleOptions"
@change="formStyleChange"
/>
</a-form-item>
</a-form>
<a-alert
@ -80,14 +88,24 @@
</template>
<script>
import { colorList } from '../../config/settingConfig'
import { ThemeModeEnum } from '../../utils/enum'
import { colorList } from '@/config/settingConfig'
import { ThemeModeEnum } from '@/utils/enum'
import { globalStore } from '@/store'
import { mapState, mapStores } from 'pinia'
import tool from '@/utils/tool'
const toolDataNameMap = {
menuIsCollapse: 'MENU_COLLAPSE',
sideUniqueOpen: 'SIDE_UNIQUE_OPEN',
layoutTagsOpen: 'LAYOUT_TAGS_OPEN',
breadcrumbOpen: 'BREADCRUMD_OPEN',
topHanderThemeColorOpen: 'TOP_HANDER_THEME_COLOR_OPEN',
topHanderThemeColorSpread: 'TOP_HANDER_THEME_COLOR_SPREAD',
moduleUnfoldOpen: 'MODULE_UNFOLD_OPEN'
}
export default defineComponent({
data() {
return {
//
sideStyle: this.$TOOL.data.get('SNOWY_THEME') || this.$store.state.global.theme,
sideStyleList: [
{
tips: '暗色主题风格',
@ -105,7 +123,6 @@
style: 'snowy-setting-checkbox-item-realdark'
}
],
layout: this.$TOOL.data.get('SNOWY_LAYOUT') || this.$store.state.global.layout,
layoutList: [
{
tips: '经典',
@ -118,100 +135,71 @@
style: 'snowy-setting-layout-menu-doublerow'
}
],
topHanderThemeColorOpen:
this.$TOOL.data.get('SNOWY_TOP_HANDER_THEME_COLOR_OPEN') || this.$store.state.global.topHanderThemeColorOpen,
topHanderThemeColorSpread:
this.$TOOL.data.get('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD') ||
this.$store.state.global.topHanderThemeColorSpread,
menuIsCollapse: this.$TOOL.data.get('SNOWY_MENU_COLLAPSE') || this.$store.state.global.menuIsCollapse,
sideUniqueOpen: this.$TOOL.data.get('SNOWY_SIDE_UNIQUE_OPEN') || this.$store.state.global.sideUniqueOpen,
layoutTagsOpen: this.$TOOL.data.get('SNOWY_LAYOUT_TAGS_OPEN') || this.$store.state.global.layoutTagsOpen,
breadcrumbOpen: this.$TOOL.data.get('SNOWY_BREADCRUMD_OPEN') || this.$store.state.global.breadcrumbOpen,
moduleUnfoldOpen: this.$TOOL.data.get('SNOWY_MODULE_UNFOLD_OPEN') || this.$store.state.global.moduleUnfoldOpen,
theme: this.$TOOL.data.get('APP_THEME') || this.$store.state.global.theme,
themeColor: this.$TOOL.data.get('SNOWY_THEME_COLOR') || this.$store.state.global.themeColor,
xnFormStyleOptions: [
{
label: '抽屉',
value: 'drawer'
},
{
label: '对话框',
value: 'modal'
}
],
colorList
}
},
watch: {
menuIsCollapse() {
this.$store.commit('TOGGLE_menuIsCollapse')
if (this.$store.state.global.menuIsCollapse) {
this.$TOOL.data.set('SNOWY_MENU_COLLAPSE', true)
} else {
this.$TOOL.data.set('SNOWY_MENU_COLLAPSE', false)
}
},
sideUniqueOpen() {
this.$store.commit('TOGGLE_sideUniqueOpen')
if (this.$store.state.global.sideUniqueOpen) {
this.$TOOL.data.set('SNOWY_SIDE_UNIQUE_OPEN', true)
} else {
this.$TOOL.data.set('SNOWY_SIDE_UNIQUE_OPEN', false)
}
},
layoutTagsOpen() {
this.$store.commit('TOGGLE_layoutTagsOpen')
if (this.$store.state.global.layoutTagsOpen) {
this.$TOOL.data.set('SNOWY_LAYOUT_TAGS_OPEN', true)
} else {
this.$TOOL.data.set('SNOWY_LAYOUT_TAGS_OPEN', false)
}
},
breadcrumbOpen() {
this.$store.commit('TOGGLE_breadcrumbOpen')
if (this.$store.state.global.breadcrumbOpen) {
this.$TOOL.data.set('SNOWY_BREADCRUMD_OPEN', true)
} else {
this.$TOOL.data.set('SNOWY_BREADCRUMD_OPEN', false)
}
},
topHanderThemeColorOpen() {
this.$store.commit('TOGGLE_topHanderThemeColorOpen')
if (this.$store.state.global.topHanderThemeColorOpen) {
this.$TOOL.data.set('SNOWY_TOP_HANDER_THEME_COLOR_OPEN', true)
} else {
//
this.$TOOL.data.set('SNOWY_TOP_HANDER_THEME_COLOR_OPEN', false)
// false
this.topHanderThemeColorSpread = false
}
},
topHanderThemeColorSpread() {
this.$store.commit('TOGGLE_topHanderThemeColorSpread')
if (this.$store.state.global.topHanderThemeColorSpread) {
this.$TOOL.data.set('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD', true)
} else {
this.$TOOL.data.set('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD', false)
}
},
moduleUnfoldOpen() {
this.$store.commit('TOGGLE_moduleUnfoldOpen')
if (this.$store.state.global.moduleUnfoldOpen) {
this.$TOOL.data.set('SNOWY_MODULE_UNFOLD_OPEN', true)
} else {
this.$TOOL.data.set('SNOWY_MODULE_UNFOLD_OPEN', false)
}
},
computed: {
...mapStores(globalStore),
...mapState(globalStore, [
'theme',
'themeColor',
'layout',
'menuIsCollapse',
'sideUniqueOpen',
'layoutTagsOpen',
'breadcrumbOpen',
'moduleUnfoldOpen',
'topHanderThemeColorOpen',
'topHanderThemeColorSpread',
'formStyle'
])
},
mounted() {},
methods: {
changeTopHanderThemeColorOpen() {
this.toggleState('topHanderThemeColorOpen')
if (!this.topHanderThemeColorOpen) {
this.globalStore.topHanderThemeColorSpread = false
tool.data.set('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD', false)
}
},
changeTopHanderThemeColorSpread() {
this.toggleState('topHanderThemeColorSpread')
},
toggleState(stateName) {
this.globalStore.toggleConfig(stateName)
const toolDataName = toolDataNameMap[stateName]
tool.data.set(`SNOWY_${toolDataName}`, this.globalStore[stateName])
},
//
setSideStyle(value) {
this.$store.commit('SET_theme', value)
this.sideStyle = value
this.$TOOL.data.set('SNOWY_THEME', value)
this.globalStore.setTheme(value)
tool.data.set('SNOWY_THEME', value)
},
//
layoutStyle(value) {
this.$store.commit('SET_layout', value)
this.$TOOL.data.set('SNOWY_LAYOUT', value)
this.layout = value
this.globalStore.setLayout(value)
tool.data.set('SNOWY_LAYOUT', value)
},
//
tagColor(value) {
this.themeColor = value
this.$TOOL.data.set('SNOWY_THEME_COLOR', value)
this.$store.commit('SET_themeColor', value)
tool.data.set('SNOWY_THEME_COLOR', value)
this.globalStore.setThemeColor(value)
},
//
formStyleChange(value) {
tool.data.set('SNOWY_FORM_STYLE', value)
this.globalStore.setFormStyle(value)
}
}
})

View File

@ -19,8 +19,8 @@
<script>
import NavMenu from './NavMenu.vue'
import tool from '@/utils/tool'
import store from '@/store'
import { globalStore } from '@/store'
import { mapState } from 'pinia'
export default {
components: {
@ -69,10 +69,12 @@
data() {
return {
visible: false,
menu: [],
sysBaseConfig: tool.data.get('SNOWY_SYS_BASE_CONFIG') || store.state.global.sysBaseConfig
menu: []
}
},
computed: {
...mapState(globalStore, ['sysBaseConfig'])
},
created() {
const menu = this.$router.getMenu()
this.menu = this.filterUrl(menu)

View File

@ -1,10 +1,42 @@
<template>
<div class="snowy-tags">
<xn-context-menu
class="right-menu"
:target="contextMenuTarget"
:show="contextMenuVisible"
@update:show="(show) => (contextMenuVisible = show)"
@get-context-menu="handleTabContextMenu"
>
<div class="right-menu-item" @click="refreshTab">
<reload-outlined class="snowy-header-tags-right" />
<div class="pl-3">刷新</div>
</div>
<div class="right-menu-item" @click="closeTabs">
<close-outlined class="snowy-header-tags-right" />
<div class="pl-3">关闭</div>
</div>
<div class="right-menu-item" @click="closeOtherTabs">
<close-outlined class="snowy-header-tags-right" />
<div class="pl-3">关闭其他标签</div>
</div>
<div class="right-menu-item" @click="maximize">
<expand-outlined class="snowy-header-tags-right" />
<div class="pl-3">最大化</div>
</div>
<div class="right-menu-item" @click="openWindow">
<select-outlined class="snowy-header-tags-right" />
<div class="pl-3">新窗口打开</div>
</div>
</xn-context-menu>
<a-tabs
v-model:activeKey="activeKey"
type="editable-card"
class="snowy-admin-tabs"
hide-add
ref="tabs"
@edit="onTabRemove"
@tabClick="onTabClick"
>
@ -17,41 +49,8 @@
<div class="snowy-admin-tabs-arrow" @click="scrollRight">
<right-outlined />
</div>
<a-dropdown>
<div class="snowy-admin-tabs-drop">
<DownOutlined />
</div>
<template #overlay>
<a-menu>
<a-menu-item>
<div class="layout-items-center" @click="refreshTab">
<reload-outlined class="snowy-header-tags-right" />
<div class="pl-3">刷新</div>
</div>
</a-menu-item>
<a-menu-item>
<div class="layout-items-center" @click="closeOtherTabs">
<close-outlined class="snowy-header-tags-right" />
<div class="pl-3">关闭其他标签</div>
</div>
</a-menu-item>
<a-menu-item>
<div class="layout-items-center" @click="maximize">
<expand-outlined class="snowy-header-tags-right" />
<div class="pl-3">最大化</div>
</div>
</a-menu-item>
<a-menu-item>
<div class="layout-items-center" @click="openWindow">
<select-outlined class="snowy-header-tags-right" />
<div class="pl-3">在新的窗口中打开</div>
</div>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
<a-tab-pane v-for="tag in tagList" :key="tag.fullPath" :tab="tag.meta.title" :closable="!tag.meta.affix">
</a-tab-pane>
</a-tabs>
@ -59,22 +58,38 @@
</template>
<script>
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue'
import Sortable from 'sortablejs'
import tool from '@/utils/tool'
import XnContextMenu from '@/components/XnContextMenu/index.vue'
import {globalStore, iframeStore, keepAliveStore, viewTagsStore} from '@/store'
import { mapState, mapActions } from 'pinia'
export default {
name: 'Tags',
components: { XnContextMenu },
props: {},
data() {
return {
tagList: this.$store.state.viewTags.viewTags,
activeKey: this.$route.fullPath
// tagList: [],
activeKey: this.$route.fullPath,
maxTabs: 20,
contextMenuTarget: null,
contextMenuVisible: false,
currentContextMenuTabIndex: 0
}
},
computed: {
...mapState(viewTagsStore, ['viewTags']),
...mapState(globalStore, ['layoutTagsOpen']),
tagList() {
return this.viewTags
}
},
watch: {
$route(e) {
this.addViewTags(e)
$route(to) {
this.addViewTags(to)
},
layoutTagsOpen() {
this.closeOtherCacheTabs()
}
},
created() {
@ -88,12 +103,30 @@
this.addViewTags(this.$route)
}
},
mounted() {
const tabNavList = document.querySelector('.ant-tabs-nav-list')
if (tabNavList) {
this.contextMenuTarget = tabNavList
}
},
methods: {
...mapActions(viewTagsStore, ['addViewTags', 'pushViewTags', 'removeViewTags']),
...mapActions(iframeStore, ['addIframe', 'removeIframeList', 'refreshIframe']),
...mapActions(keepAliveStore, ['pushKeepLive', 'removeKeepLive', 'setRouteShow']),
handleTabContextMenu(evt) {
evt.preventDefault()
let target = evt.target
if (target.classList.contains('ant-tabs-tab-btn')) {
target = target.parentNode
}
const tabList = document.querySelectorAll('.ant-tabs-nav-list .ant-tabs-tab')
this.currentContextMenuTabIndex = Array.from(tabList).findIndex((tab) => tab === target)
},
onTabClick(tab) {
this.$router.push(tab)
},
getCurrentTag() {
return this.tagList.find((tag) => tag.fullPath === this.activeKey)
return this.tagList[this.currentContextMenuTabIndex]
},
onTabRemove(tabKey, action) {
if (action === 'remove') {
@ -133,8 +166,12 @@
addViewTags(route) {
this.activeKey = route.fullPath
if (route.name && !route.meta.fullpage) {
this.$store.commit('pushViewTags', route)
this.$store.commit('pushKeepLive', route.name)
this.pushViewTags(route)
this.pushKeepLive(route.name)
}
if (this.tagList.length - 1 > this.maxTabs) {
const firstTag = this.tagList[1]
this.removeViewTags(firstTag)
}
},
// tag
@ -143,9 +180,9 @@
},
// tag
closeSelectedTag(tag, autoPushLatestView = true) {
this.$store.commit('removeViewTags', tag)
this.$store.commit('removeIframeList', tag)
this.$store.commit('removeKeepLive', tag.name)
this.removeViewTags(tag)
this.removeIframeList(tag)
this.removeKeepLive(tag.name)
if (autoPushLatestView && this.isActive(tag)) {
const latestView = this.tagList.slice(-1)[0]
if (latestView) {
@ -157,6 +194,7 @@
},
// TAB
refreshTab() {
this.contextMenuVisible = false
const nowTag = this.getCurrentTag()
//
// eslint-disable-next-line eqeqeq
@ -166,18 +204,19 @@
query: nowTag.query
})
}
this.$store.commit('refreshIframe', nowTag)
this.refreshIframe(nowTag)
setTimeout(() => {
this.$store.commit('removeKeepLive', nowTag.name)
this.$store.commit('setRouteShow', false)
this.removeKeepLive(nowTag.name)
this.setRouteShow(false)
this.$nextTick(() => {
this.$store.commit('pushKeepLive', nowTag.name)
this.$store.commit('setRouteShow', true)
this.pushKeepLive(nowTag.name)
this.setRouteShow(true)
})
}, 0)
},
// TAB
closeTabs() {
this.contextMenuVisible = false
const nowTag = this.getCurrentTag()
if (!nowTag.meta.affix) {
this.closeSelectedTag(nowTag)
@ -185,6 +224,7 @@
},
// TAB
closeOtherTabs() {
this.contextMenuVisible = false
const nowTag = this.getCurrentTag()
//
// eslint-disable-next-line eqeqeq
@ -204,8 +244,16 @@
}
})
},
//
closeOtherCacheTabs () {
const tags = [...this.tagList]
tags.forEach((tag) => {
this.closeSelectedTag(tag, false)
})
},
// TAB
maximize() {
this.contextMenuVisible = false
const nowTag = this.getCurrentTag()
//
// eslint-disable-next-line eqeqeq
@ -219,6 +267,7 @@
},
//
openWindow() {
this.contextMenuVisible = false
const nowTag = this.getCurrentTag()
const url = nowTag.href || '/'
if (!nowTag.meta.affix) {
@ -284,4 +333,25 @@
}
}
}
.right-menu {
position: fixed;
background: #fff;
z-index: 999;
border: 1px solid #eee;
box-shadow: 0 0.5em 1em 0 rgb(0 0 0 / 10%);
border-radius: 1px;
}
.snowy-tags {
.right-menu-item {
display: flex;
align-items: center;
text-align: center;
padding: 10px 20px;
color: #333;
cursor: pointer;
&:hover {
background: var(--primary-1);
}
}
}
</style>

View File

@ -1,5 +1,8 @@
<template>
<div class="user-bar">
<div v-if="!ismobile" class="search panel-item hidden-sm-and-down" @click="handleSearchClick">
<search-outlined />
</div>
<div v-if="!ismobile" class="screen panel-item hidden-sm-and-down" @click="fullscreen">
<fullscreen-outlined />
</div>
@ -40,15 +43,30 @@
</a-menu>
</template>
</a-dropdown>
<div class="setting panel-item" @click="openSetting">
<div v-if="setDeawer === 'true'" class="setting panel-item" @click="openSetting">
<layout-outlined />
</div>
</div>
<!-- 整体风格设置抽屉 -->
<a-drawer v-model:visible="settingDialog" :closable="false" width="300">
<setting></setting>
<setting />
</a-drawer>
<!-- 搜索面板 -->
<xn-form-container
title="搜索"
:visible="searchActive"
:closable="false"
:footer="null"
:width="600"
style="overflow: hidden"
destroyOnClose
dialogClass="searchModal"
:bodyStyle="{ maxHeight: '520px', overflow: 'auto', padding: '14px' }"
@close="searchPanelClose"
>
<panel-search ref="panelSearch" @close="searchPanelClose" />
</xn-form-container>
</template>
<script>
@ -61,37 +79,33 @@
import tool from '@/utils/tool'
import loginApi from '@/api/auth/loginApi'
import devUserMessage from './message.vue'
import panelSearch from './panel-search/index.vue'
import mixinSearch from './mixins/search'
import { mapState } from 'pinia'
import { globalStore } from '@/store'
export default {
components: {
setting,
devUserMessage
devUserMessage,
panelSearch
},
mixins: [mixinSearch],
data() {
return {
lang: [],
settingDialog: false,
userInfo: {},
userName: '',
userNameF: ''
userNameF: '',
setDeawer: import.meta.env.VITE_SET_DRAWER
}
},
computed: {
ismobile() {
return this.$store.state.global.ismobile
},
userInfoWatch() {
return this.$store.state.global.userInfo
}
},
watch: {
userInfoWatch(newVal, oldVal) {
this.userInfo = newVal
}
...mapState(globalStore, ['ismobile', 'userInfo'])
},
created() {
//
this.lang = new Array(this.$TOOL.data.get('APP_LANG') || this.$CONFIG.LANG)
this.userInfo = this.$TOOL.data.get('USER_INFO')
this.userName = this.userInfo?.userName || ''
this.userNameF = this.userName.substring(0, 1)
},
@ -171,29 +185,25 @@
if (screenfull.isEnabled) {
screenfull.toggle(element)
}
}
},
//
fullSearch() {}
}
}
</script>
<style scoped>
<style lang="less" scoped>
:deep(.ant-modal) {
top: 20px;
}
:deep(.ant-modal-content) {
border-radius: 10px;
}
.user-bar {
display: flex;
align-items: center;
height: 100%;
}
.user-bar .panel-item {
padding: 0 10px;
cursor: pointer;
height: 100%;
display: flex;
align-items: center;
}
.user-bar .panel-item i {
}
.user-bar .panel-item:hover {
background: var(--header-color-split);
}
.user-bar .user-avatar {
height: 49px;
display: flex;

View File

@ -4,7 +4,7 @@
<a-layout>
<a-layout-sider
v-if="!ismobile"
v-model:collapsed="$store.state.global.menuIsCollapse"
v-model:collapsed="menuIsCollapse"
:trigger="null"
collapsible
:theme="sideTheme"
@ -18,7 +18,7 @@
</div>
</div>
</header>
<div :class="$store.state.global.menuIsCollapse ? 'aminui-side isCollapse' : 'aminui-side'">
<div :class="menuIsCollapse ? 'aminui-side isCollapse' : 'aminui-side'">
<div class="adminui-side-scroll">
<a-menu
v-model:openKeys="openKeys"
@ -28,17 +28,21 @@
@select="onSelect"
@openChange="onOpenChange"
>
<NavMenu :nav-menus="menu"></NavMenu>
<NavMenu :nav-menus="menu" />
</a-menu>
</div>
</div>
</a-layout-sider>
<!-- 手机端情况下的左侧菜单 -->
<Side-m v-if="ismobile"></Side-m>
<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 @switchModule="switchModule" />
<Topbar v-if="!ismobile && breadcrumbOpen" />
</div>
@ -47,15 +51,15 @@
</div>
</div>
<!-- 多标签 -->
<Tags v-if="!ismobile && layoutTagsOpen"></Tags>
<Tags v-if="!ismobile && layoutTagsOpen" />
<a-layout-content class="main-content-wrapper">
<div id="adminui-main" class="adminui-main">
<router-view v-slot="{ Component }">
<keep-alive :include="$store.state.keepAlive.keepLiveRoute">
<component :is="Component" :key="$route.name" v-if="$store.state.keepAlive.routeShow" />
<keep-alive :include="keepLiveRoute">
<component :is="Component" :key="$route.name" v-if="routeShow" />
</keep-alive>
</router-view>
<iframe-view></iframe-view>
<iframe-view />
<div class="main-bottom-wrapper">
<a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
sysBaseConfig.SNOWY_SYS_COPYRIGHT
@ -63,13 +67,6 @@
</div>
</div>
</a-layout-content>
<!--
<a-layout-footer style="text-align: center">
<a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
sysBaseConfig.SNOWY_SYS_COPYRIGHT
}}</a>
</a-layout-footer>
-->
</a-layout>
</a-layout>
</template>
@ -122,7 +119,7 @@
<a-layout-sider
v-if="!ismobile"
v-show="layoutSiderDowbleMenu"
v-model:collapsed="$store.state.global.menuIsCollapse"
v-model:collapsed="menuIsCollapse"
:trigger="null"
width="170"
collapsible
@ -132,21 +129,25 @@
<h2 class="snowy-title">{{ pmenu.meta.title }}</h2>
</div>
<a-menu
v-model:collapsed="$store.state.global.menuIsCollapse"
v-model:collapsed="menuIsCollapse"
v-model:openKeys="openKeys"
v-model:selectedKeys="selectedKeys"
mode="inline"
:theme="secondMenuSideTheme"
@select="onSelect"
>
<NavMenu :nav-menus="nextMenu"></NavMenu>
<NavMenu :nav-menus="nextMenu" />
</a-menu>
</a-layout-sider>
<!-- 手机端情况下的左侧菜单 -->
<Side-m v-if="ismobile"></Side-m>
<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 @switchModule="switchModule" />
<Topbar v-if="!ismobile && breadcrumbOpen" />
</div>
@ -159,18 +160,18 @@
<a-layout-content class="main-content-wrapper">
<div id="adminui-main" class="adminui-main">
<router-view v-slot="{ Component }">
<keep-alive :include="$store.state.keepAlive.keepLiveRoute">
<component :is="Component" v-if="$store.state.keepAlive.routeShow" :key="$route.name" />
<keep-alive :include="keepLiveRoute">
<component :is="Component" v-if="routeShow" :key="$route.name" />
</keep-alive>
</router-view>
<iframe-view></iframe-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-footer style="text-align: center">
<a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
sysBaseConfig.SNOWY_SYS_COPYRIGHT
}}</a>
</a-layout-footer>
</a-layout>
</a-layout>
</template>
@ -190,8 +191,9 @@
import iframeView from './components/iframeView.vue'
import moduleMenu from './components/moduleMenu.vue'
import { ThemeModeEnum } from '@/utils/enum'
import { globalStore, keepAliveStore } from '@/store'
import { mapState, mapStores, mapActions } from 'pinia'
import tool from '@/utils/tool'
import store from '@/store'
export default defineComponent({
name: 'Index',
@ -215,39 +217,32 @@
onSelectTag: false,
selectedKeys: [],
openKeys: [],
openKeysOther: [],
sysBaseConfig: tool.data.get('SNOWY_SYS_BASE_CONFIG') || store.state.global.sysBaseConfig
openKeysOther: []
}
},
computed: {
...mapStores(globalStore),
...mapState(globalStore, [
'theme',
'ismobile',
'layout',
'layoutTagsOpen',
'menuIsCollapse',
'breadcrumbOpen',
'topHanderThemeColorOpen',
'topHanderThemeColorSpread',
'topHanderThemeColor',
'sideUniqueOpen',
'sysBaseConfig'
]),
...mapState(keepAliveStore, ['keepLiveRoute', 'routeShow']),
sideTheme() {
const theme = this.$store.state.global.theme
const theme = this.theme
return theme === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : theme
},
secondMenuSideTheme() {
const theme = this.$store.state.global.theme
const theme = this.theme
return theme === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : ThemeModeEnum.LIGHT
},
ismobile() {
return this.$store.state.global.ismobile
},
layout() {
return this.$store.state.global.layout
},
layoutTagsOpen() {
return this.$store.state.global.layoutTagsOpen
},
menuIsCollapse() {
return this.$store.state.global.menuIsCollapse
},
breadcrumbOpen() {
return this.$store.state.global.breadcrumbOpen
},
topHanderThemeColorOpen() {
return this.$store.state.global.topHanderThemeColorOpen
},
topHanderThemeColorSpread() {
return this.$store.state.global.topHanderThemeColorSpread
}
},
watch: {
@ -280,7 +275,7 @@
window.addEventListener('resize', this.onLayoutResize)
this.moduleMenu = this.$router.getMenu()
//
const menuModuleId = this.$TOOL.data.get('SNOWY_MENU_MODULE_ID')
const menuModuleId = tool.data.get('SNOWY_MENU_MODULE_ID')
let menu = []
if (menuModuleId) {
//
@ -301,6 +296,7 @@
this.switchoverTopHanderThemeColor()
},
methods: {
...mapActions(globalStore, ['setTheme', 'setIsmobile', 'setLayout', 'setMenuIsCollapse']),
//
switchModule(id) {
const menu = this.moduleMenu
@ -308,7 +304,7 @@
const menus = menu.filter((item) => item.id === id)[0].children
if (menus.length > 0) {
//
this.$TOOL.data.set('SNOWY_MENU_MODULE_ID', id)
tool.data.set('SNOWY_MENU_MODULE_ID', id)
//
this.menu = this.filterUrl(menus)
//
@ -342,11 +338,7 @@
},
onLayoutResize() {
const clientWidth = document.body.clientWidth
if (clientWidth < 992) {
this.$store.commit('SET_ismobile', true)
} else {
this.$store.commit('SET_ismobile', false)
}
this.setIsmobile(clientWidth < 992)
},
//
showThis() {
@ -368,7 +360,7 @@
if (!this.onSelectTag) {
const pidKey = this.getParentKeys(this.menu, active)
this.openKeys = pidKey
} else if (this.$store.state.global.sideUniqueOpen) {
} else if (this.sideUniqueOpen) {
const pidKey = this.getParentKeys(this.menu, active)
this.openKeys = pidKey
}
@ -419,7 +411,7 @@
},
// /
onOpenChange(keys) {
if (this.$store.state.global.sideUniqueOpen) {
if (this.sideUniqueOpen) {
//
const openKey = keys[keys.length - 1]
if (keys.length > 1) {
@ -471,6 +463,9 @@
})
return newMap
},
menuIsCollapseClick() {
this.globalStore.toggleConfig('menuIsCollapse')
},
// 退
exitMaximize() {
document.getElementById('app').classList.remove('main-maximize')
@ -484,17 +479,19 @@
: header.classList.remove('snowy-header-primary-color')
//
const headerLogin = document.getElementById('snowyHeaderLogo')
this.topHanderThemeColorSpread
? headerLogin.classList.add('snowy-header-logo-primary-color')
: headerLogin.classList.remove('snowy-header-logo-primary-color')
try {
this.topHanderThemeColorSpread
? headerLogin.classList.add('snowy-header-logo-primary-color')
: headerLogin.classList.remove('snowy-header-logo-primary-color')
} catch (e) {}
//
if (this.layout === 'doublerow') {
const snowyDoublerowSideTop = document.getElementById('snowyDoublerowSideTop')
try{
try {
this.topHanderThemeColorSpread
? snowyDoublerowSideTop.classList.add('snowy-doublerow-side-top-primary-color')
: snowyDoublerowSideTop.classList.remove('snowy-doublerow-side-top-primary-color')
}catch (e) { }
} catch (e) {}
}
}
}

View File

@ -14,7 +14,7 @@ import enGB from 'ant-design-vue/es/locale/en_GB'
import zh_cn from './lang/zh-cn.js'
import en from './lang/en.js'
import tool from '@/utils/tool'
import sysConfig from '@/config/index.js'
import sysConfig from '@/config/index'
export const messages = {
'zh-cn': {

View File

@ -16,7 +16,11 @@ export default {
editButton: 'edit',
removeButton: 'delete',
batchRemoveButton: 'batch Remove',
detailButton: 'detail'
detailButton: 'detail',
searchKey: 'Search Key',
imports: 'Import',
more: 'More',
export: 'Export',
},
model: {
user: 'user',
@ -50,5 +54,19 @@ export default {
emailCodePlaceholder: 'Please input a Email code',
restPhoneType: 'For phone rest',
restEmailType: 'For email rest'
},
user: {
userStatus: 'User Status',
resetPassword: 'Reset Password',
role: 'Role',
batchExportButton: 'Batch Export',
grantRole: 'Grant Role',
grantResource: 'Grant Resource',
grantPermission: 'Grant Permission',
exportUserInfo: 'Export UserInfo',
placeholderNameAndSearchKey: 'Please enter your name or keyword',
placeholderUserStatus: 'Please select status',
popconfirmDeleteUser: 'Are you sure you want to delete it',
popconfirmResatUserPwd: 'Are you sure you want to reset'
}
}

View File

@ -18,7 +18,11 @@ export default {
editButton: '编辑',
removeButton: '删除',
batchRemoveButton: '批量删除',
detailButton: '详情'
detailButton: '详情',
searchKey: '关键词',
imports: '导入',
more: '更多',
export: '导出',
},
model: {
user: '用户',
@ -52,5 +56,19 @@ export default {
emailCodePlaceholder: '请输入邮件验证码',
restPhoneType: '手机号找回',
restEmailType: '邮箱找回'
},
user: {
userStatus: '用户状态',
resetPassword: '重置密码',
role: '角色',
batchExportButton: '批量导出',
grantRole: '授权角色',
grantResource: '授权资源',
grantPermission: '授权权限',
exportUserInfo: '导出信息',
placeholderNameAndSearchKey: '请输入姓名或关键词',
placeholderUserStatus: '请选择状态',
popconfirmDeleteUser: '确定要删除吗?',
popconfirmResatUserPwd: '确定要重置吗?'
}
}

View File

@ -1,15 +1,16 @@
import { createApp } from 'vue'
import Antd from 'ant-design-vue'
import { createPinia } from 'pinia'
import './style/index.less'
import snowy from './snowy'
import i18n from './locales'
import router from './router'
import store from './store'
import App from './App.vue'
import './tailwind.css'
const app = createApp(App)
app.use(store)
app.use(createPinia())
app.use(router)
app.use(Antd)
app.use(i18n)

View File

@ -8,11 +8,8 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
/* eslint-disable eqeqeq */
/* eslint-disable camelcase */
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import { createRouter, createWebHistory } from 'vue-router'
import { notification } from 'ant-design-vue'
import config from '@/config'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import systemRouter from './systemRouter'
@ -22,34 +19,32 @@ import userRoutes from '@/config/route'
import tool from '@/utils/tool'
import { cloneDeep } from 'lodash-es'
const modules = import.meta.glob('/src/views/**/**.vue')
import store from '@/store'
const sysBaseConfig = tool.data.get('SNOWY_SYS_BASE_CONFIG') || store.state.global.sysBaseConfig
import { globalStore, searchStore } from '@/store'
// 进度条配置
NProgress.configure({ showSpinner: false, speed: 500 })
// 系统路由
const routes = [...systemRouter, ...whiteListRouters]
// 系统特殊路由
const routes_404 = {
path: '/:pathMatch(.*)*',
hidden: true,
component: () => import('@/layout/other/404.vue')
}
let routes_404_r = () => {}
const routes_404 = [
{
path: '/:pathMatch(.*)*',
hidden: true,
component: () => import('@/layout/other/404.vue')
}
]
// 系统路由
const routes = [...systemRouter, ...whiteListRouters, ...routes_404]
const router = createRouter({
// 此方式不带 # 号 // createWebHashHistory()带#号
history: createWebHistory(),
routes
})
// 设置标题
document.title = sysBaseConfig.SNOWY_SYS_NAME
// document.title = sysBaseConfig.SNOWY_SYS_NAME
// 判断是否已加载过动态/静态路由
let isGetRouter = false
const isGetRouter = ref(false)
// 白名单校验
const exportWhiteListFromRouter = (router) => {
@ -59,33 +54,11 @@ const exportWhiteListFromRouter = (router) => {
}
const whiteList = exportWhiteListFromRouter(whiteListRouters)
// 加载动态/静态路由
const handleGetRouter = (to) => {
if (!isGetRouter) {
let apiMenu = tool.data.get('MENU') || []
if (apiMenu.length === 0) {
// 创建默认模块,显示默认菜单
apiMenu[0] = cloneDeep(userRoutes.module[0])
const userMenu = userRoutes.menu
const childrenApiMenu = apiMenu[0].children
apiMenu[0].children = [...userMenu, ...childrenApiMenu]
}
let menuRouter = filterAsyncRouter(apiMenu)
menuRouter = flatAsyncRoutes(menuRouter)
menuRouter.forEach((item) => {
router.addRoute('layout', item)
})
routes_404_r = router.addRoute(routes_404)
if (to && to.matched.length === 0) {
router.push(to.fullPath)
}
isGetRouter = true
}
}
router.beforeEach(async (to, from, next) => {
NProgress.start()
const store = globalStore()
const sysBaseConfig = tool.data.get('SNOWY_SYS_BASE_CONFIG') || store.sysBaseConfig
// 动态标题
document.title = to.meta.title
? `${to.meta.title} - ${sysBaseConfig.SNOWY_SYS_NAME}`
@ -109,11 +82,12 @@ router.beforeEach(async (to, from, next) => {
}
// 删除路由(替换当前layout路由)
router.addRoute(routes[0])
// 删除路由(404)
routes_404_r()
isGetRouter = false
isGetRouter.value = false
next()
return false
} else {
// 这里需要使用 localStorage 保存登录之前要访问的页面
tool.data.set('LAST_VIEWS_PATH', to.fullPath)
}
if (!token) {
next({
@ -126,7 +100,27 @@ router.beforeEach(async (to, from, next) => {
to.matched = [to.matched[to.matched.length - 1]]
}
// 加载动态/静态路由
handleGetRouter(to)
if (!isGetRouter.value) {
const apiMenu = tool.data.get('MENU') || []
if (apiMenu.length === 0) {
// 创建默认模块,显示默认菜单
apiMenu[0] = cloneDeep(userRoutes.module[0])
const userMenu = userRoutes.menu
const childrenApiMenu = apiMenu[0].children
apiMenu[0].children = [...userMenu, ...childrenApiMenu]
}
let menuRouter = filterAsyncRouter(apiMenu)
menuRouter = flatAsyncRoutes(menuRouter)
menuRouter.forEach((item) => {
router.addRoute('layout', item)
})
const search_store = searchStore()
search_store.init(menuRouter)
isGetRouter.value = true
next({ ...to, replace: true })
return false
}
beforeEach(to, from)
next()
})

View File

@ -9,14 +9,15 @@
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
import { nextTick } from 'vue'
import store from '@/store'
import { viewTagsStore } from '@/store'
export function beforeEach(to, from) {
const adminMain = document.querySelector('#adminui-main')
if (!adminMain) {
return false
}
store.commit('updateViewTags', {
const store = viewTagsStore()
store.updateViewTags({
fullPath: from.fullPath,
scrollTop: adminMain.scrollTop
})
@ -28,7 +29,8 @@ export function afterEach(to) {
return false
}
nextTick(() => {
const beforeRoute = store.state.viewTags.viewTags.filter((v) => v.fullPath == to.fullPath)[0]
const store = viewTagsStore()
const beforeRoute = store.viewTags.filter((v) => v.fullPath == to.fullPath)[0]
if (beforeRoute) {
adminMain.scrollTop = beforeRoute.scrollTop || 0
}

View File

@ -5,7 +5,7 @@ import { hasPerm } from './utils/permission/index'
import errorHandler from './utils/errorHandler'
import customIcons from './assets/icons/index.js'
import 'highlight.js/styles/atom-one-dark.css'
import 'highlight.js/lib/common'
import hljsCommon from 'highlight.js/lib/common'
import hljsVuePlugin from '@highlightjs/vue-plugin'
import STable from './components/Table/index.vue'
import Ellipsis from './components/Ellipsis/index.vue'
@ -28,6 +28,8 @@ export default {
// 统一注册自定义全局图标
app.use(customIcons)
// 注册代码高亮组件 博客https://blog.csdn.net/weixin_41897680/article/details/124925222
// 注意解决Vue使用highlight.js build打包发布后样式消失问题原因是webpack在打包的时候没有把未被使用的代码打包进去因此在此处引用一下看似无意义实则有用
hljsCommon.highlightAuto('<h1>Highlight.js has been registered successfully!</h1>').value
app.use(hljsVuePlugin)
// 全局代码错误捕捉

View File

@ -8,7 +8,8 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
import { changeColor, getLocalSetting } from '@/utils/themeUtil'
import { defineStore } from 'pinia'
import { changeColor } from '@/utils/themeUtil'
import config from '@/config'
import { message } from 'ant-design-vue'
import tool from '@/utils/tool'
@ -25,8 +26,13 @@ const getCacheConfig = (value) => {
}
return data
}
export default {
state: {
/**
* deprecated 请使用 useGlobalStore
*/
export const globalStore = defineStore({
id: 'global',
state: () => ({
// 移动端布局
ismobile: false,
// 布局
@ -42,66 +48,55 @@ export default {
// 顶栏是否应用主题色
topHanderThemeColorOpen: getCacheConfig('SNOWY_TOP_HANDER_THEME_COLOR_OPEN'),
// 顶栏主题色通栏
topHanderThemeColorSpread:
getCacheConfig('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD'),
// 目录坞
topHanderThemeColorSpread: getCacheConfig('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD'),
// 模块坞
moduleUnfoldOpen: getCacheConfig('SNOWY_MODULE_UNFOLD_OPEN'),
// 主题
theme: getCacheConfig('SNOWY_THEME'),
// 主题颜色
themeColor: toolDataGet('SNOWY_THEME_COLOR') || config.COLOR,
// 整体表单风格
formStyle: getCacheConfig('SNOWY_FORM_STYLE'),
// 用户信息
userInfo: toolDataGet('USER_INFO') || {},
// 系统配置
sysBaseConfig: toolDataGet('SNOWY_SYS_BASE_CONFIG') || config.SYS_BASE_CONFIG
},
mutations: {
SET_ismobile(state, key) {
state.ismobile = key
}),
getters: {},
actions: {
setIsmobile(key) {
this.ismobile = key
},
SET_layout(state, key) {
state.layout = key
setLayout(key) {
this.layout = key
},
SET_theme(state, key) {
state.theme = key
setTheme(key) {
this.theme = key
const closeMessage = message.loading(`加载中...`)
changeColor(state.themeColor, key).then(closeMessage)
changeColor(this.themeColor, key).then(closeMessage)
},
SET_themeColor(state, key) {
state.themeColor = key
setThemeColor(key) {
this.themeColor = key
const closeMessage = message.loading(`加载中...`)
changeColor(key, state.theme).then(closeMessage)
changeColor(key, this.theme).then(closeMessage)
},
initTheme(state) {
initTheme() {
const closeMessage = message.loading(`加载中...`)
changeColor(state.themeColor, state.theme).then(closeMessage)
changeColor(this.themeColor, this.theme).then(closeMessage)
},
TOGGLE_menuIsCollapse(state) {
state.menuIsCollapse = !state.menuIsCollapse
toggleConfig(key) {
this[key] = !this[key]
},
TOGGLE_sideUniqueOpen(state) {
state.sideUniqueOpen = !state.sideUniqueOpen
setFormStyle(key) {
this.formStyle = key
},
TOGGLE_layoutTagsOpen(state) {
state.layoutTagsOpen = !state.layoutTagsOpen
setUserInfo(key) {
this.userInfo = key
},
TOGGLE_breadcrumbOpen(state) {
state.breadcrumbOpen = !state.breadcrumbOpen
},
TOGGLE_topHanderThemeColorOpen(state) {
state.topHanderThemeColorOpen = !state.topHanderThemeColorOpen
},
TOGGLE_topHanderThemeColorSpread(state) {
state.topHanderThemeColorSpread = !state.topHanderThemeColorSpread
},
TOGGLE_moduleUnfoldOpen(state) {
state.moduleUnfoldOpen = !state.moduleUnfoldOpen
},
SET_userInfo(state, key) {
state.userInfo = key
},
SET_sysBaseConfig(state, key) {
state.sysBaseConfig = key
setSysBaseConfig(key) {
this.sysBaseConfig = key
}
}
}
})
export const useGlobalStore = globalStore

View File

@ -8,31 +8,34 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
/* eslint-disable eqeqeq */
export default {
state: {
import { defineStore } from 'pinia'
export const iframeStore = defineStore({
id: 'iframe',
state: () => ({
iframeList: []
},
mutations: {
setIframeList(state, route) {
state.iframeList = []
state.iframeList.push(route)
}),
getters: {},
actions: {
setIframeList(route) {
this.iframeList = []
this.iframeList.push(route)
},
pushIframeList(state, route) {
const target = state.iframeList.find((item) => item.path === route.path)
pushIframeList(route) {
const target = this.iframeList.find((item) => item.path === route.path)
if (!target) {
state.iframeList.push(route)
this.iframeList.push(route)
}
},
removeIframeList(state, route) {
state.iframeList.forEach((item, index) => {
removeIframeList(route) {
this.iframeList.forEach((item, index) => {
if (item.path === route.path) {
state.iframeList.splice(index, 1)
this.iframeList.splice(index, 1)
}
})
},
refreshIframe(state, route) {
state.iframeList.forEach((item) => {
refreshIframe(route) {
this.iframeList.forEach((item) => {
if (item.path === route.path) {
const url = route.meta.url
item.meta.url = ''
@ -42,8 +45,8 @@ export default {
}
})
},
clearIframeList(state) {
state.iframeList = []
clearIframeList() {
this.iframeList = []
}
}
}
})

View File

@ -1,25 +1,5 @@
/**
* 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
*/
import { createStore } from 'vuex'
import global from './modules/global'
import iframe from './modules/iframe'
import keepAlive from './modules/keepAlive'
import viewTags from './modules/viewTags'
// 自动import导入所有 vuex 模块
export default createStore({
modules: {
global,
iframe,
keepAlive,
viewTags
}
})
export * from './global'
export * from './search'
export * from './iframe'
export * from './keepAlive'
export * from './viewTags'

View File

@ -8,37 +8,39 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
export default {
state: {
import { defineStore } from 'pinia'
export const keepAliveStore = defineStore({
id: 'keepAlive',
state: () => ({
keepLiveRoute: [],
routeKey: null,
routeShow: true
},
mutations: {
pushKeepLive(state, component) {
if (!state.keepLiveRoute.includes(component)) {
state.keepLiveRoute.push(component)
}
},
removeKeepLive(state, component) {
const index = state.keepLiveRoute.indexOf(component)
if (index !== -1) {
state.keepLiveRoute.splice(index, 1)
}
},
clearKeepLive(state) {
state.keepLiveRoute = []
},
setRouteKey(state, key) {
state.routeKey = key
},
setRouteShow(state, key) {
state.routeShow = key
}
},
}),
getters: {},
actions: {
setRouteKey({ commit }, key) {
commit('setRouteKey', key)
pushKeepLive(component) {
if (!this.keepLiveRoute.includes(component)) {
this.keepLiveRoute.push(component)
}
},
removeKeepLive(component) {
const index = this.keepLiveRoute.indexOf(component)
if (index !== -1) {
this.keepLiveRoute.splice(index, 1)
}
},
clearKeepLive() {
this.keepLiveRoute = []
},
setRouteKey(key) {
this.routeKey = key
},
setRouteShow(key) {
this.routeShow = key
},
setRouteKeyAction(key) {
this.setRouteKey(key)
}
}
}
})

View File

@ -0,0 +1,57 @@
import '@/utils/objects'
import { defineStore } from 'pinia'
export const searchStore = defineStore({
id: 'search',
state: () => ({
active: false,
hotkey: {
open: 's',
close: 'esc'
},
pool: []
}),
getters: {},
actions: {
toggleActive() {
this.active = !this.active
},
setActive(active) {
this.active = active
},
init(menu) {
const pool = []
const getFullName = function (meta) {
if (meta.breadcrumb) {
let list = []
meta.breadcrumb.forEach((item) => {
list.push(item.meta.title)
})
return list.join(' / ')
}
return meta.title
}
const push = function (menu) {
menu.forEach((m) => {
if ('menu' === m.meta.type) {
if (m.children) {
push(m.children)
} else if (m.children === null) {
pool.push({
icon: m.meta.icon,
path: m.path,
fullPath: m.path,
name: m.meta.title,
fullName: getFullName(m.meta),
namePinyin: m.meta.title.toPinyin(),
namePinyinFirst: m.meta.title.toPinyin(true)
})
}
}
})
}
push(menu)
this.pool = pool
}
}
})

View File

@ -8,43 +8,46 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
/* eslint-disable eqeqeq */
export default {
state: {
import { defineStore } from 'pinia'
export const viewTagsStore = defineStore({
id: 'viewTags',
state: () => ({
viewTags: []
},
mutations: {
pushViewTags(state, route) {
const target = state.viewTags.find((item) => item.fullPath === route.fullPath)
}),
getters: {},
actions: {
pushViewTags(route) {
const target = this.viewTags.find((item) => item.fullPath === route.fullPath)
const isName = route.name
if (!target && isName) {
state.viewTags.push(route)
this.viewTags.push(route)
}
},
removeViewTags(state, route) {
state.viewTags.forEach((item, index) => {
removeViewTags(route) {
this.viewTags.forEach((item, index) => {
if (item.fullPath === route.fullPath) {
state.viewTags.splice(index, 1)
this.viewTags.splice(index, 1)
}
})
},
updateViewTags(state, route) {
state.viewTags.forEach((item) => {
updateViewTags(route) {
this.viewTags.forEach((item) => {
if (item.fullPath == route.fullPath) {
item = Object.assign(item, route)
Object.assign(item, route)
}
})
},
updateViewTagsTitle(state, title = '') {
updateViewTagsTitle(title = '') {
const nowFullPath = location.hash.substring(1)
state.viewTags.forEach((item) => {
this.viewTags.forEach((item) => {
if (item.fullPath == nowFullPath) {
item.meta.title = title
}
})
},
clearViewTags(state) {
state.viewTags = []
clearViewTags() {
this.viewTags = []
}
}
}
})

View File

@ -7,9 +7,9 @@
/* 全局 */
/*
#app, body, html {
width: 100%;
height: 100%;
background-color: #f6f8f9;
width: 100%;
height: 100%;
background-color: #f6f8f9;
}
*/
.body, html {
@ -19,31 +19,31 @@
}
a, button, input, textarea {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
box-sizing: border-box;
outline: none !important;
-webkit-appearance: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
box-sizing: border-box;
outline: none !important;
-webkit-appearance: none;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
outline: none;
margin: 0;
padding: 0;
box-sizing: border-box;
outline: none;
}
/* 大布局样式 */
.aminui {
overflow: hidden;
height: 100%;
display: flex;
flex-flow: column;
display: flex;
flex-flow: column;
}
.aminui-wrapper {
display: flex;
flex: 1;
overflow: auto;
display: flex;
flex: 1;
overflow: auto;
}
.adminui-main {
@ -71,31 +71,31 @@ a, button, input, textarea {
/* 双排菜单布局 */
.snowy-doublerow-layout-menu {
padding-left: 5px;
padding-right: 5px;
line-height: 0;
align-items: center;
padding-left: 5px;
padding-right: 5px;
line-height: 0;
align-items: center;
}
.snowy-doublerow-layout-menu-item-fort-div {
overflow: hidden;
text-overflow: ellipsis;
opacity: 1;
display: block;
flex: auto;
overflow: hidden;
text-overflow: ellipsis;
opacity: 1;
display: block;
flex: auto;
}
.snowy-doublerow-layout-menu-item-fort-div-span {
font-size: 12px;
text-overflow: ellipsis;
font-size: 12px;
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
border-bottom: 1px solid var(--border-color-split);
height: 50px;
line-height: 50px;
padding-left: 20px;
font-size: 12px
}
// 应用主题色
@ -107,49 +107,54 @@ a, button, input, textarea {
}
.snowy-title{
color: var(--text-color);
color: var(--text-color);
}
.ant-layout-sider-collapsed{
.logo-bar>span{
display: none;
}
.logo-bar>span{
display: none;
}
}
.ant-layout-sider-dark{
.snowy-header-logo{
color: #fff;
}
.snowy-header-logo{
color: #fff;
}
}
/* 设置抽屉样式 */
.layout-setting {
position: fixed;
width: 40px;
height: 40px;
border-radius: 3px 0 0 3px;
bottom: 50%;
right: 0px;
z-index: 100;
background: @primary-color;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
position: fixed;
width: 40px;
height: 40px;
border-radius: 3px 0 0 3px;
bottom: 50%;
right: 0px;
z-index: 100;
background: @primary-color;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
}
.layout-setting i {
color: #fff;
color: #fff;
}
/* 头部 */
.snowy-header {
height: 50px;
display: flex;
justify-content: space-between;
border-bottom: 1px solid var(--border-color-split);
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
background-color: var(--body-background);
height: 50px;
display: flex;
justify-content: space-between;
border-bottom: 1px solid var(--border-color-split);
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
background-color: var(--body-background);
.ant-menu-item{
height: 48px;
line-height: 48px;
}
}
// 应用主题色
.snowy-header-primary-color {
@ -164,33 +169,38 @@ a, button, input, textarea {
.ant-breadcrumb-separator {
color: white;
}
.ant-menu-light .ant-menu-item:hover{
color: #ccc;
background-color: var(--primary-7);
}
}
.ant-layout-sider-dark {
.snowy-title{
color: #fff;
}
.snowy-title{
color: #fff;
}
}
.snowy-header-left {
display: flex;
align-items: center;
padding-left: 20px;
display: flex;
align-items: center;
padding-left: 20px;
}
.snowy-header-left .menu-unfold-outlined {
padding: 0 12px
padding: 0 12px
}
.snowy-header-right {
display: flex;
align-items: center;
display: flex;
align-items: center;
}
.snowy-header-logo {
height: 49px;
display: flex;
justify-content: space-between;
height: 50px;
display: flex;
justify-content: space-between;
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}
.snowy-header-logo-primary-color {
@ -199,101 +209,112 @@ a, button, input, textarea {
}
.snowy-header-logo .logo-bar {
font-weight: bold;
display: flex;
align-items: center;
font-size: 20px;
font-weight: bold;
display: flex;
align-items: center;
font-size: 20px;
}
.snowy-header-logo .logo-bar .logo {
margin-right: 10px;
width: 35px;
height: 35px;
margin-right: 10px;
width: 35px;
height: 35px;
}
/* 面包屑 */
.adminui-topbar {
padding-left: 15px
padding-left: 15px
}
.adminui-topbar .left-panel {
display: flex;
align-items: center;
display: flex;
align-items: center;
}
.adminui-topbar .right-panel {
display: flex;
align-items: center;
display: flex;
align-items: center;
}
.panel-item {
padding: 0 10px;
cursor: pointer;
height: 100%;
display: flex;
align-items: center;
}
.panel-item:hover {
background: var(--header-color-split);
}
/* 多标签 */
.snowy-tags {
height: 40px;
background: var(--component-background);
height: 40px;
background: var(--component-background);
}
.snowy-tags ul {
display: flex;
overflow: hidden;
padding-left: 0;
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;
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);
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;
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;
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;
background: rgba(0, 0, 0, .2);
color: @body-background;
}
.snowy-tags li:hover {
background: @body-background;
background: @body-background;
}
.snowy-tags li.active {
background: @primary-color;
background: @primary-color;
}
.snowy-tags li.active a {
color: #fff;
color: #fff;
}
.snowy-tags li.sortable-ghost {
opacity: 0;
opacity: 0;
}
.snowy-header-tags-right {
@ -343,38 +364,37 @@ a, button, input, textarea {
/*页面最大化*/
.aminui.main-maximize {
.main-maximize-exit {
display: block;
}
.ant-layout-sider, .ant-layout-sider-dark, .layout-setting, .snowy-header {
display: none;
}
.main-maximize-exit {
display: block;
}
.ant-layout-sider, .ant-layout-sider-dark, .layout-setting, .snowy-header {
display: none;
}
}
/* 最大化后的退出按钮 */
.main-maximize-exit {
display: none;
position: fixed;
z-index: 3000;
top: -20px;
padding-top: 18px;
left: 50%;
margin-left: -20px;
border-radius: 50%;
width: 40px;
height: 40px;
cursor: pointer;
background: rgba(0, 0, 0, 0.2);
text-align: center;
display: none;
position: fixed;
z-index: 3000;
top: -20px;
padding-top: 18px;
left: 50%;
margin-left: -20px;
border-radius: 50%;
width: 40px;
height: 40px;
cursor: pointer;
background: rgba(0, 0, 0, 0.2);
text-align: center;
}
.main-maximize-exit:hover {
background: rgba(0, 0, 0, 0.4);
background: rgba(0, 0, 0, 0.4);
}
.ant-layout-sider{
overflow: auto;
overflow: auto;
}
/* 重写antdv的一些样式定义到全局 */
@ -388,6 +408,24 @@ a, button, input, textarea {
padding: 12px 0!important;
}
/* 重写antdv的表格滚动条 */
.ant-table-body {
&::-webkit-scrollbar {
height: 10px;
width: 10px;
}
&::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.1);
background: @border-color-split;
}
&::-webkit-scrollbar-track {
-webkit-box-shadow: 0;
border-radius: 10px;
background: @background-color-base;
}
}
// 滚动条需要哪里加哪个class
body,
.ant-drawer-wrapper-body,
@ -407,46 +445,47 @@ body,
.org-table,
.pos-table,
.poi-list,
.ant-table-body,
.snowy-orgpos-vis,
.index-message-list,
.ant-picker-time-panel-column,
.timeline-div,
.gen-preview-content,
.ant-menu,
.adminui-main{
&::-webkit-scrollbar {
/*滚动条整体样式*/
width : 0px; /*高宽分别对应横竖滚动条的尺寸*/
height: 0px;
}
&::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius : 10px;
background-color: @component-background; // skyblue
background-image: -webkit-linear-gradient(
45deg,
rgba(255, 255, 255, 0.2) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0.2) 50%,
rgba(255, 255, 255, 0.2) 75%,
transparent 75%,
transparent
);
}
&::-webkit-scrollbar-track {
/*滚动条里面轨道*/
box-shadow : inset 0 0 2px rgba(0, 0, 0, 0.2);
background : @component-background;
border-radius: 5px;
opacity: 0;
display: none;
}
&::-webkit-scrollbar {
/*滚动条整体样式*/
width : 0px; /*高宽分别对应横竖滚动条的尺寸*/
height: 0px;
}
&::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius : 10px;
background-color: @component-background; // skyblue
background-image: -webkit-linear-gradient(
45deg,
rgba(255, 255, 255, 0.2) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0.2) 50%,
rgba(255, 255, 255, 0.2) 75%,
transparent 75%,
transparent
);
}
&::-webkit-scrollbar-track {
/*滚动条里面轨道*/
box-shadow : inset 0 0 2px rgba(0, 0, 0, 0.2);
background : @component-background;
border-radius: 5px;
opacity: 0;
display: none;
}
}
.json-box-9136076486841527{
overflow: hidden!important;;
.CodeMirror-scrollbar-filler{
display: none!important;
}
overflow: hidden!important;;
.CodeMirror-scrollbar-filler{
display: none!important;
}
}

View File

@ -0,0 +1,37 @@
/**
* 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
*/
import { message } from 'ant-design-vue'
export default {
// 对下载的流进行处理,直接从浏览器下载下来
resultDownload (res) {
if (res.data.type === 'application/json') {
// 错误以及无权限
const reader = new FileReader(res.data)
reader.readAsText(res.data)
reader.onload = () => {
const result = JSON.parse(reader.result)
message.error(result.msg)
}
} else {
const blob = new Blob([res.data], { type: 'application/octet-stream;charset=UTF-8' })
const contentDisposition = res.headers['content-disposition']
const patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
const $link = document.createElement('a')
$link.href = URL.createObjectURL(blob)
$link.download = decodeURIComponent(patt.exec(contentDisposition)[1])
$link.click()
document.body.appendChild($link)
document.body.removeChild($link) // 下载完成移除元素
window.URL.revokeObjectURL($link.href) // 释放掉blob对象
}
}
}

View File

@ -8,10 +8,10 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
export const required = (text, method = ['blur', 'change']) => ({
export const required = (message, trigger = ['blur', 'change']) => ({
required: true,
message: text,
trigger: method
message,
trigger
})
// 常用正则规则大全https://any86.github.io/any-rule/
@ -42,5 +42,10 @@ export const rules = {
pattern: /^\d{1,}$/,
message: '填写内容必须是纯数字',
trigger: 'blur'
},
price: {
pattern: /(?:^[1-9]([0-9]+)?(?:\.[0-9]{1,2})?$)|(?:^(?:0)$)|(?:^[0-9]\.[0-9](?:[0-9])?$)/,
message: '只支持正数金额',
trigger: 'blur'
}
}

View File

@ -1,85 +0,0 @@
/**
* 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
*/
import { mapState } from 'vuex'
import { DEVICE_TYPE, deviceEnquire } from '@/utils/device'
// const mixinsComputed = Vue.config.optionMergeStrategies.computed
// const mixinsMethods = Vue.config.optionMergeStrategies.methods
const mixin = {
computed: {
...mapState({
layoutMode: (state) => state.app.layout,
navTheme: (state) => state.app.theme,
primaryColor: (state) => state.app.color,
colorWeak: (state) => state.app.weak,
fixedHeader: (state) => state.app.fixedHeader,
fixSiderbar: (state) => state.app.fixSiderbar,
fixSidebar: (state) => state.app.fixSiderbar,
contentWidth: (state) => state.app.contentWidth,
autoHideHeader: (state) => state.app.autoHideHeader,
sidebarOpened: (state) => state.app.sidebar,
multiTab: (state) => state.app.multiTab
})
},
methods: {
isTopMenu() {
return this.layoutMode === 'topmenu'
},
isSideMenu() {
return !this.isTopMenu()
}
}
}
const mixinDevice = {
computed: {
...mapState({
device: (state) => state.app.device
})
},
methods: {
isMobile() {
return this.device === DEVICE_TYPE.MOBILE
},
isDesktop() {
return this.device === DEVICE_TYPE.DESKTOP
},
isTablet() {
return this.device === DEVICE_TYPE.TABLET
}
}
}
const AppDeviceEnquire = {
mounted() {
const { $store } = this
deviceEnquire((deviceType) => {
switch (deviceType) {
case DEVICE_TYPE.DESKTOP:
$store.commit('TOGGLE_DEVICE', 'desktop')
$store.dispatch('setSidebar', true)
break
case DEVICE_TYPE.TABLET:
$store.commit('TOGGLE_DEVICE', 'tablet')
$store.dispatch('setSidebar', false)
break
case DEVICE_TYPE.MOBILE:
default:
$store.commit('TOGGLE_DEVICE', 'mobile')
$store.dispatch('setSidebar', true)
break
}
})
}
}
export { mixin, AppDeviceEnquire, mixinDevice }

View File

@ -0,0 +1,29 @@
import pinyin from 'js-pinyin'
// 中文转拼音 传入仅首字母
Object.defineProperty(String.prototype, 'toPinyin', {
writable: false,
enumerable: false,
configurable: true,
value: function (first) {
let str = this
if (first) {
return pinyin.getCamelChars(str).replace(/\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/g, '')
}
return pinyin.getFullChars(str).replace(/\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/g, '')
}
})
// 字符检索 传入检索值
Object.defineProperty(String.prototype, 'filter', {
writable: false,
enumerable: false,
configurable: true,
value: function (input) {
let str = this
let en = str.toLowerCase().includes(input.toLowerCase())
let zhFull = str.toPinyin().toLowerCase().includes(input.toLowerCase())
let zhFirst = str.toPinyin(true).toLowerCase().includes(input.toLowerCase())
return en || zhFull || zhFirst
}
})

View File

@ -1,156 +0,0 @@
/**
* 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
*/
/* eslint-disable */
// 打印类属性、方法定义
const Print = function(dom, options) {
if (!(this instanceof Print)) return new Print(dom, options)
this.options = this.extend({
noPrint: '.no-print',
}, options)
if ((typeof dom) === 'string') {
try {
this.dom = document.querySelector(dom)
}
catch {
const createDom = document.createElement('div')
createDom.innerHTML = dom
this.dom = createDom
}
}
else {
this.isDOM(dom)
this.dom = this.isDOM(dom) ? dom : dom.$el
}
this.init()
}
Print.prototype = {
init() {
const content = this.getStyle() + this.getHtml()
this.writeIframe(content)
},
extend(obj, obj2) {
for (const k in obj2) {
obj[k] = obj2[k]
}
return obj
},
getStyle() {
let str = ''
const styles = document.querySelectorAll('style,link')
for (let i = 0; i < styles.length; i++) {
str += styles[i].outerHTML
}
str += `<style>${ this.options.noPrint ? this.options.noPrint : '.no-print'
}{display:none;}</style>`
str += '<style>html,body{background-color:#fff;}</style>'
return str
},
getHtml() {
const inputs = document.querySelectorAll('input')
const textareas = document.querySelectorAll('textarea')
const selects = document.querySelectorAll('select')
for (let k = 0; k < inputs.length; k++) {
if (inputs[k].type == 'checkbox' || inputs[k].type == 'radio') {
if (inputs[k].checked == true) {
inputs[k].setAttribute('checked', 'checked')
}
else {
inputs[k].removeAttribute('checked')
}
}
else if (inputs[k].type == 'text') {
inputs[k].setAttribute('value', inputs[k].value)
}
else {
inputs[k].setAttribute('value', inputs[k].value)
}
}
for (let k2 = 0; k2 < textareas.length; k2++) {
if (textareas[k2].type == 'textarea') {
textareas[k2].innerHTML = textareas[k2].value
}
}
for (let k3 = 0; k3 < selects.length; k3++) {
if (selects[k3].type == 'select-one') {
const child = selects[k3].children
for (const i in child) {
if (child[i].tagName == 'OPTION') {
if (child[i].selected == true) {
child[i].setAttribute('selected', 'selected')
}
else {
child[i].removeAttribute('selected')
}
}
}
}
}
return this.dom.outerHTML
},
writeIframe(content) {
let w; let doc; const iframe = document.createElement('iframe')
const f = document.body.appendChild(iframe)
iframe.id = 'myIframe'
// iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
iframe.setAttribute('style', 'position:absolute;width:0;height:0;top:-10px;left:-10px;')
w = f.contentWindow || f.contentDocument
doc = f.contentDocument || f.contentWindow.document
doc.open()
doc.write(content)
doc.close()
const _this = this
iframe.onload = function() {
_this.toPrint(w)
setTimeout(() => {
document.body.removeChild(iframe)
}, 100)
}
},
toPrint(frameWindow) {
try {
setTimeout(() => {
frameWindow.focus()
try {
if (!frameWindow.document.execCommand('print', false, null)) {
frameWindow.print()
}
}
catch (e) {
frameWindow.print()
}
frameWindow.close()
}, 10)
}
catch (err) {
console.log('err', err)
}
},
isDOM: (typeof HTMLElement === 'object')
? function(obj) {
return obj instanceof HTMLElement
}
: function(obj) {
return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string'
},
}
export default Print

View File

@ -10,6 +10,7 @@
*/
// 统一的请求发送
import axios from 'axios'
import qs from 'qs'
import { Modal, message, notification } from 'ant-design-vue'
import sysConfig from '@/config/index'
import tool from '@/utils/tool'
@ -108,8 +109,25 @@ service.interceptors.response.use(
} else {
// 统一成功提示
const responseUrl = response.config.url
const apiNameArray = ['add', 'edit', 'delete', 'update', 'grant', 'reset', 'start', 'stop',
'pass', 'disable', 'enable', 'revoke', 'suspend', 'active', 'turn', 'adjust', 'reject']
const apiNameArray = [
'add',
'edit',
'delete',
'update',
'grant',
'reset',
'start',
'stop',
'pass',
'disable',
'enable',
'revoke',
'suspend',
'active',
'turn',
'adjust',
'reject'
]
apiNameArray.forEach((apiName) => {
if (responseUrl.includes(apiName)) {
message.success(data.msg)
@ -131,37 +149,37 @@ service.interceptors.response.use(
}
)
// 适配器, 用于适配不同的请求方式
export const baseRequest = (url, value = {}, method = 'post', options = {}) => {
url = sysConfig.API_URL + url
if (method === 'post') {
return service.post(url, value, options)
} else if (method === 'get') {
return service.get(url, {
params: value,
...options
})
return service.get(url, { params: value, ...options })
} else if (method === 'formdata') {
return service({
method: 'post',
url,
data: value,
// 转换数据的方法
transformRequest: [
function (data) {
let ret = ''
for (const it in data) {
ret += `${encodeURIComponent(it)}=${encodeURIComponent(data[it])}&`
}
ret = ret.substring(0, ret.length - 1)
return ret
}
],
// 设置请求头
// form-data表单提交的方式
return service.post(url, qs.stringify(value), {
headers: {
'Content-Type': 'multipart/form-data'
}
},
...options
})
} else {
// 其他请求方式例如put、delete
return service({
method: method,
url: url,
data: value,
...options
})
}
}
// 模块内的请求, 会自动加上模块的前缀
export const moduleRequest =
(moduleUrl) =>
(url, ...arg) => {
return baseRequest(moduleUrl + url, ...arg)
}
export default service

View File

@ -17,13 +17,9 @@
import smCrypto from 'sm-crypto'
const sm2 = smCrypto.sm2
const sm3 = smCrypto.sm3
const sm4 = smCrypto.sm4
const cipherMode = 1 // 1 - C1C3C20 - C1C2C3默认为1
const publicKey =
'04298364ec840088475eae92a591e01284d1abefcda348b47eb324bb521bb03b0b2a5bc393f6b71dabb8f15c99a0050818b56b23f31743b93df9cf8948f15ddb54'
const privateKey = '3037723d47292171677ec8bd7dc9af696c7472bc5f251b2cec07e65fdef22e25'
const key = '0123456789abcdeffedcba9876543210'
/**
* 国密加解密工具类
@ -33,36 +29,8 @@ export default {
doSm2Encrypt(msgString) {
return sm2.doEncrypt(msgString, publicKey, cipherMode)
},
// SM2解密
doSm2Decrypt(encryptData) {
return sm2.doDecrypt(encryptData, privateKey, cipherMode)
},
// SM2数组加密
doSm2ArrayEncrypt(msgString) {
return sm2.doEncrypt(msgString, publicKey, cipherMode)
},
// SM2数组解密
doSm2ArrayDecrypt(encryptData) {
return sm2.doDecrypt(encryptData, privateKey, cipherMode, { output: 'array' })
},
// SM3哈希
doSm3Hash(msgString) {
return sm3(msgString)
},
// SM4 CBC加密
doSm4Encrypt(msgString) {
return sm4.encrypt(msgString, key)
},
// SM4 CBC加密
doSm4CbcEncrypt(msgString) {
return sm4.encrypt(msgString, key, { mode: 'cbc', iv: 'fedcba98765432100123456789abcdef' })
},
// SM4 解密
doSm4Decrypt(encryptData) {
return sm4.decrypt(encryptData, key)
},
// SM4 CBC解密
doSm4CbcDecrypt(encryptData) {
return sm4.decrypt(encryptData, key, { mode: 'cbc', iv: 'fedcba98765432100123456789abcdef' })
}
}

View File

@ -8,7 +8,7 @@
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
import generate from '@ant-design/colors/lib/generate'
import { generate } from '@ant-design/colors';
import tool from '../utils/tool'
import config from '../config'
import { ThemeModeEnum } from './enum'

View File

@ -14,15 +14,9 @@
* @LastEditors: yubaoshan
* @LastEditTime: 2022年4月19日10:58:41
*/
const tool = {}
/**
* localStorage
*
* @author yubaoshan
* @date 2022-05-18 22:59
*/
// localStorage
tool.data = {
set(table, settings) {
const _set = JSON.stringify(settings)
@ -46,12 +40,7 @@ tool.data = {
}
}
/**
* sessionStorage
*
* @author yubaoshan
* @date 2022-05-18 22:59
*/
// sessionStorage
tool.session = {
set(table, settings) {
const _set = JSON.stringify(settings)
@ -74,12 +63,7 @@ tool.session = {
}
}
/**
* 千分符
*
* @author yubaoshan
* @date 2022-05-18 22:59
*/
// 千分符
tool.groupSeparator = (num) => {
num = `${num}`
if (!num.includes('.')) num += '.'
@ -91,24 +75,12 @@ tool.groupSeparator = (num) => {
.replace(/\.$/, '')
}
/**
* 获取所有字典数组
*
* @author yubaoshan
* @date 2022-04-08 01:11
*/
// 获取所有字典数组
tool.dictDataAll = () => {
return tool.data.get('DICT_TYPE_TREE_DATA')
}
/**
* 字典翻译方法
* 界面插槽使用方法 {{ $TOOL.dictType('sex', record.sex) }}
*
* @author yubaoshan
* @date 2022-04-08 01:11
*/
// todo 每次都从localStorage获取并重新解析会有性能问题应该在内存中做一层缓存后面需要优化掉
// 字典翻译方法,界面插槽使用方法 {{ $TOOL.dictType('sex', record.sex) }}
tool.dictTypeData = (dictValue, value) => {
const dictTypeTree = tool.dictDataAll()
if (!dictTypeTree) {
@ -120,15 +92,10 @@ tool.dictTypeData = (dictValue, value) => {
}
const children = tree.children
const dict = children.find((item) => item.dictValue === value)
return dict?.name || '无此字典'
return dict ? dict.dictLabel : '无此字典项'
}
/**
* 获取某个code下字典的列表多用于字典下拉框
*
* @author yubaoshan
* @date 2022-04-08 01:11
*/
// 获取某个code下字典的列表多用于字典下拉框
tool.dictTypeList = (dictValue) => {
const dictTypeTree = tool.dictDataAll()
if (!dictTypeTree) {
@ -141,12 +108,25 @@ tool.dictTypeList = (dictValue) => {
return []
}
/**
* 生成UUID
*
* @author yubaoshan
* @date 2022-05-18 22:59
*/
// 获取某个code下字典的列表基于dictTypeList 改进,保留老的,逐步替换
tool.dictList = (dictValue) => {
const dictTypeTree = tool.dictDataAll()
if (!dictTypeTree) {
return []
}
const tree = dictTypeTree.find((item) => item.dictValue === dictValue)
if (tree) {
return tree.children.map((item) => {
return {
value: item['dictValue'],
label: item['name']
}
})
}
return []
}
// 生成UUID
tool.snowyUuid = () => {
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
let r = (Math.random() * 16) | 0,

View File

@ -12,28 +12,29 @@ import { nextTick } from 'vue'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import router from '@/router'
import store from '@/store'
import { iframeStore, keepAliveStore, viewTagsStore } from '@/store'
export default {
// 刷新标签
refresh() {
NProgress.start()
const keepAlive = keepAliveStore()
const route = router.currentRoute.value
store.commit('removeKeepLive', route.name)
store.commit('setRouteShow', false)
keepAlive.removeKeepLive(route.name)
keepAlive.setRouteShow(false)
nextTick(() => {
store.commit('pushKeepLive', route.name)
store.commit('setRouteShow', true)
keepAlive.pushKeepLive(route.name)
keepAlive.setRouteShow(true)
NProgress.done()
})
},
// 关闭标签
close(tag) {
const route = tag || router.currentRoute.value
store.commit('removeViewTags', route)
store.commit('removeIframeList', route)
store.commit('removeKeepLive', route.name)
const tagList = store.state.viewTags.viewTags
const store = viewTagsStore()
store.removeViewTags(route)
iframeStore().removeIframeList(route)
keepAliveStore().removeKeepLive(route.name)
const tagList = store.viewTags
const latestView = tagList.slice(-1)[0]
if (latestView) {
router.push(latestView)
@ -44,21 +45,23 @@ export default {
// 关闭标签后处理
closeNext(next) {
const route = router.currentRoute.value
store.commit('removeViewTags', route)
store.commit('removeIframeList', route)
store.commit('removeKeepLive', route.name)
const store = viewTagsStore()
store.removeViewTags(route)
iframeStore().removeIframeList(route)
keepAliveStore().removeKeepLive(route.name)
if (next) {
const tagList = store.state.viewTags.viewTags
const tagList = store.viewTags
next(tagList)
}
},
// 关闭其他
closeOther() {
const route = router.currentRoute.value
const tagList = [...store.state.viewTags.viewTags]
const store = viewTagsStore()
const tagList = [...store.viewTags]
tagList.forEach((tag) => {
// eslint-disable-next-line prettier/prettier
if (tag.meta && tag.meta.affix || route.fullPath == tag.fullPath) {
if ((tag.meta && tag.meta.affix) || route.fullPath == tag.fullPath) {
return true
} else {
this.close(tag)
@ -67,6 +70,6 @@ export default {
},
// 设置标题
setTitle(title) {
store.commit('updateViewTagsTitle', title)
viewTagsStore().updateViewTagsTitle(title)
}
}

View File

@ -92,6 +92,7 @@
import router from '@/router'
import { required, rules } from '@/utils/formRules'
import userCenterApi from '@/api/sys/userCenterApi'
import smCrypto from '@/utils/smCrypto'
const emailResetFormRef = ref()
const emailFormData = ref({})
const islogin = ref(false)
@ -102,7 +103,7 @@
let formRules = ref({})
const emailValidCodeReqNo = ref('')
//
//
const getEmailValidCode = () => {
formRules.value.email = [required(), rules.email]
delete formRules.value.emailValidCode
@ -122,8 +123,8 @@
emailResetFormRef.value.validate().then(() => {
emailFormData.value.validCode = emailFormData.value.emailValidCode
// delete emailFormData.value.emailValidCode
emailFormData.value.validCodeReqNo = emailValidCodeReqNo.value
emailFormData.value.newPassword = smCrypto.doSm2Encrypt(emailFormData.value.newPassword)
islogin.value = true
userCenterApi
.userFindPasswordByEmail(emailFormData.value)
@ -144,7 +145,6 @@
const emailLoginFormModalRef = ref()
const emailFormModalData = ref({})
const validCodeBase64 = ref('')
const validCodeReqNo = ref('')
const formModalRules = {
validCode: [required(), rules.lettersNum]
}
@ -158,10 +158,10 @@
visible.value = false
}
const handleOk = () => {
//
//
emailLoginFormModalRef.value.validate().then(() => {
visible.value = false
//
//
emailFormModalData.value.email = emailFormData.value.email
//
state.value.smsSendBtn = true
@ -180,13 +180,15 @@
emailValidCodeReqNo.value = data
visible.value = false
setTimeout(hide, 500)
emailFormModalData.value.validCode = ''
})
.catch(() => {
setTimeout(hide, 100)
clearInterval(interval)
state.value.smsSendBtn = false
})
.finally(() => {
emailFormModalData.value.validCode = ''
})
})
}
</script>

View File

@ -93,6 +93,7 @@
import router from '@/router'
import { required, rules } from '@/utils/formRules'
import userCenterApi from '@/api/sys/userCenterApi'
import smCrypto from '@/utils/smCrypto'
const phoneLoginFormRef = ref()
const phoneFormData = ref({})
const islogin = ref(false)
@ -123,8 +124,8 @@
phoneLoginFormRef.value.validate().then(() => {
phoneFormData.value.validCode = phoneFormData.value.phoneValidCode
// delete phoneFormData.value.phoneValidCode
phoneFormData.value.validCodeReqNo = phoneValidCodeReqNo.value
phoneFormData.value.newPassword = smCrypto.doSm2Encrypt(phoneFormData.value.newPassword)
islogin.value = true
userCenterApi
.userFindPasswordByPhone(phoneFormData.value)
@ -145,7 +146,6 @@
const phoneLoginFormModalRef = ref()
const phoneFormModalData = ref({})
const validCodeBase64 = ref('')
const validCodeReqNo = ref('')
const formModalRules = {
validCode: [required(), rules.lettersNum]
}
@ -181,13 +181,15 @@
phoneValidCodeReqNo.value = data
visible.value = false
setTimeout(hide, 500)
phoneFormModalData.value.validCode = ''
})
.catch(() => {
setTimeout(hide, 100)
clearInterval(interval)
state.value.smsSendBtn = false
})
.finally(() => {
phoneFormModalData.value.validCode = ''
})
})
}
</script>

View File

@ -8,7 +8,7 @@
<h2>三方登录</h2>
</div>
<a-spin tip="正在登录中...">
<div style="height: 300px">
<div class="h-[300px]">
<a-skeleton />
</div>
</a-spin>
@ -20,7 +20,6 @@
<script setup name="loginCallback">
import { message } from 'ant-design-vue'
import { nextTick } from 'vue'
import tool from '@/utils/tool'
import router from '@/router'
import thirdApi from '@/api/auth/thirdApi'
@ -31,24 +30,21 @@
onMounted(() => {
// url
const url = window.location.href
let parameter = url.split('?')[1]
if (!parameter) {
// 访
window.location.href = '/login'
}
const parameterArray = parameter.split('&')
const url = new URL(window.location.href)
let argLength = 0
const params = {}
url.searchParams.forEach((value, key) => {
argLength += 1
params[key] = value
})
//
if (!parameterArray) {
if (argLength < 2) {
window.location.href = '/login'
return
}
const parameterObject = {}
// json
for (let i = 0; i < parameterArray.length; i++) {
parameterObject[parameterArray[i].split('=')[0]] = parameterArray[i].split('=')[1]
}
thirdApi
.thirdCallback(parameterObject)
.thirdCallback(params)
.then((data) => {
tool.data.set('TOKEN', data)
//
@ -64,11 +60,9 @@
path: indexMenu
})
message.success('登录成功')
nextTick(() => {
dictApi.dictTree().then((dictData) => {
// store
tool.data.set('DICT_TYPE_TREE_DATA', dictData)
})
dictApi.dictTree().then((dictData) => {
// store
tool.data.set('DICT_TYPE_TREE_DATA', dictData)
})
})
})
@ -79,155 +73,5 @@
</script>
<style lang="less" scoped>
.login_background {
width: 100%;
height: 100%;
overflow: hidden;
background-size: cover;
background-position: center;
background-image: url(/img/login_background.png);
}
.login_background_front {
width: 450px;
height: 450px;
margin-left: 100px;
margin-top: 15%;
overflow: hidden;
/*position: relative;*/
background-size: cover;
background-position: center;
background-image: url(/img/login_background_front.png);
animation-name: myfirst;
animation-duration: 5s;
animation-timing-function: linear;
animation-delay: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-play-state: running;
/* Safari and Chrome: */
-webkit-animation-name: myfirst;
-webkit-animation-duration: 5s;
-webkit-animation-timing-function: linear;
-webkit-animation-delay: 1s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: alternate;
-webkit-animation-play-state: running;
}
@keyframes myfirst {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
@-webkit-keyframes myfirst /* Safari and Chrome */ {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
.login_adv__title h2 {
font-size: 40px;
}
.login_adv__title h4 {
font-size: 18px;
margin-top: 10px;
font-weight: normal;
}
.login_adv__title p {
font-size: 14px;
margin-top: 10px;
line-height: 1.8;
color: rgba(255, 255, 255, 0.6);
}
.login_adv__title div {
margin-top: 10px;
display: flex;
align-items: center;
}
.login_adv__title div span {
margin-right: 15px;
}
.login_adv__title div i {
font-size: 40px;
}
.login_adv__title div i.add {
font-size: 20px;
color: rgba(255, 255, 255, 0.6);
}
/*background-image:linear-gradient(transparent, #000);*/
.login_main {
flex: 1;
overflow: auto;
display: flex;
}
.login-form {
top: 15%;
right: 15%;
position: absolute;
width: 450px;
margin-left: 10%;
margin-top: 20px;
padding: 10px 0;
}
.login-header {
margin-bottom: 20px;
}
.login-header .logo {
display: flex;
align-items: center;
}
.login-header .logo img {
width: 35px;
height: 35px;
vertical-align: bottom;
margin-right: 10px;
}
.login-header .logo label {
font-size: 24px;
}
.login-header h2 {
font-size: 24px;
font-weight: bold;
margin-top: 40px;
}
.login_config {
position: absolute;
top: 20px;
right: 20px;
}
@media (max-width: 1200px) {
.login-form {
width: 340px;
}
}
@media (max-width: 1000px) {
.login_main {
display: block;
}
.login_background_front {
display: none;
}
.login-form {
width: 100%;
padding: 20px 40px;
right: 0 !important;
top: 0 !important;
}
}
@import 'login';
</style>

View File

@ -0,0 +1,152 @@
.login-icon-gray {
color: rgba(0, 0, 0, 0.25);
}
.login-validCode-img {
border: 1px solid var(--border-color-split);
cursor: pointer;
width: 100%;
height: 40px;
}
.login_background {
width: 100%;
height: 100%;
overflow: hidden;
background-size: cover;
background-position: center;
background-image: url(/img/login_background.png);
}
.login_background_front {
width: 450px;
height: 450px;
margin-left: 100px;
margin-top: 15%;
overflow: hidden;
/*position: relative;*/
background-size: cover;
background-position: center;
background-image: url(/img/login_background_front.png);
animation-name: myfirst;
animation-duration: 5s;
animation-timing-function: linear;
animation-delay: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-play-state: running;
}
@keyframes myfirst {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
@-webkit-keyframes myfirst /* Safari and Chrome */ {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
.login_adv__title h2 {
font-size: 40px;
}
.login_adv__title h4 {
font-size: 18px;
margin-top: 10px;
font-weight: normal;
}
.login_adv__title p {
font-size: 14px;
margin-top: 10px;
line-height: 1.8;
color: rgba(255, 255, 255, 0.6);
}
.login_adv__title div {
margin-top: 10px;
display: flex;
align-items: center;
}
.login_adv__title div span {
margin-right: 15px;
}
.login_adv__title div i {
font-size: 40px;
}
.login_adv__title div i.add {
font-size: 20px;
color: rgba(255, 255, 255, 0.6);
}
/*background-image:linear-gradient(transparent, #000);*/
.login_main {
flex: 1;
overflow: auto;
display: flex;
}
.login-form {
top: 15%;
right: 15%;
position: absolute;
width: 450px;
margin-left: 10%;
margin-top: 20px;
padding: 10px 0;
}
.login-header {
margin-bottom: 20px;
}
.login-header .logo {
display: flex;
align-items: center;
}
.login-header .logo img {
width: 35px;
height: 35px;
vertical-align: bottom;
margin-right: 10px;
}
.login-header .logo label {
font-size: 24px;
}
.login-header h2 {
font-size: 24px;
font-weight: bold;
margin-top: 40px;
}
.login_config {
position: absolute;
top: 20px;
right: 20px;
}
@media (max-width: 1200px) {
.login-form {
width: 340px;
}
}
@media (max-width: 1000px) {
.login_main {
display: block;
}
.login_background_front {
display: none;
}
.login-form {
width: 100%;
padding: 20px 40px;
right: 0 !important;
top: 0 !important;
}
}

View File

@ -33,9 +33,14 @@
<a-tab-pane key="userAccount" :tab="$t('login.accountPassword')">
<a-form ref="loginForm" :model="ruleForm" :rules="rules">
<a-form-item name="account">
<a-input v-model:value="ruleForm.account" :placeholder="$t('login.accountPlaceholder')" size="large">
<a-input
v-model:value="ruleForm.account"
:placeholder="$t('login.accountPlaceholder')"
size="large"
@keyup.enter="login"
>
<template #prefix>
<UserOutlined style="color: rgba(0, 0, 0, 0.25)" />
<UserOutlined class="login-icon-gray" />
</template>
</a-input>
</a-form-item>
@ -45,31 +50,29 @@
:placeholder="$t('login.PWPlaceholder')"
size="large"
autocomplete="off"
@keyup.enter="login"
>
<template #prefix>
<LockOutlined style="color: rgba(0, 0, 0, 0.25)" />
<LockOutlined class="login-icon-gray" />
</template>
</a-input-password>
</a-form-item>
<a-form-item name="validCode" v-if="sysBaseConfig.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN === 'true'">
<a-form-item name="validCode" v-if="captchaOpen === 'true'">
<a-row :gutter="8">
<a-col :span="17">
<a-input
v-model:value="ruleForm.validCode"
:placeholder="$t('login.validLaceholder')"
size="large"
@keyup.enter="login"
>
<template #prefix>
<verified-outlined style="color: rgba(0, 0, 0, 0.25)" />
<verified-outlined class="login-icon-gray" />
</template>
</a-input>
</a-col>
<a-col :span="7">
<img
:src="validCodeBase64"
style="border: 1px solid var(--border-color-split); cursor: pointer; width: 100%; height: 40px"
@click="loginCaptcha"
/>
<img :src="validCodeBase64" class="login-validCode-img" @click="loginCaptcha" />
</a-col>
</a-row>
</a-form-item>
@ -78,7 +81,7 @@
<a href="/findpwd" style="color: #0d84ff">{{ $t('login.forgetPassword') }}</a>
</a-form-item>
<a-form-item>
<a-button type="primary" style="width: 100%" :loading="islogin" round size="large" @click="login"
<a-button type="primary" class="w-full" :loading="loading" round size="large" @click="login"
>{{ $t('login.signIn') }}
</a-button>
</a-form-item>
@ -97,13 +100,19 @@
<script>
import loginApi from '@/api/auth/loginApi'
import userCenterApi from '@/api/sys/userCenterApi'
import dictApi from '@/api/dev/dictApi'
import phoneLoginForm from './phoneLoginForm.vue'
import threeLogin from './threeLogin.vue'
import smCrypto from '@/utils/smCrypto'
import { required } from '@/utils/formRules'
import { afterLogin } from './util'
import config from '@/config'
import configApi from '@/api/dev/configApi'
import tool from '@/utils/tool'
import { globalStore, iframeStore, keepAliveStore, viewTagsStore } from '@/store'
import { mapActions, mapState } from 'pinia'
export default {
name: 'Login',
components: {
phoneLoginForm,
threeLogin
@ -111,7 +120,7 @@
data() {
return {
activeKey: 'userAccount',
sysBaseConfig: this.$TOOL.data.get('SNOWY_SYS_BASE_CONFIG') || this.$store.state.global.sysBaseConfig,
captchaOpen: config.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN,
validCodeBase64: '',
ruleForm: {
account: 'superAdmin',
@ -121,13 +130,13 @@
autologin: false
},
rules: {
account: [{ required: true, message: this.$t('login.accountError'), trigger: 'blur' }],
password: [{ required: true, message: this.$t('login.PWError'), trigger: 'blur' }]
account: [required(this.$t('login.accountError'), 'blur')],
password: [required(this.$t('login.PWError'), 'blur')]
},
islogin: false,
loading: false,
config: {
lang: this.$TOOL.data.get('APP_LANG') || this.$CONFIG.LANG,
theme: this.$TOOL.data.get('APP_THEME') || 'default'
lang: tool.data.get('APP_LANG') || this.$CONFIG.LANG,
theme: tool.data.get('APP_THEME') || 'default'
},
lang: [
{
@ -142,9 +151,7 @@
}
},
computed: {
sysBaseConfigWatch() {
return this.$store.state.global.sysBaseConfig
}
...mapState(globalStore, ['sysBaseConfig']),
},
watch: {
'config.theme': function (val) {
@ -152,41 +159,41 @@
},
'config.lang': function (val) {
this.$i18n.locale = val
this.$TOOL.data.set('APP_LANG', val)
},
sysBaseConfigWatch(val) {
this.sysBaseConfig = val
this.refreshSwitch()
tool.data.set('APP_LANG', val)
}
},
created() {
this.$store.commit('clearViewTags')
this.$store.commit('clearKeepLive')
this.$store.commit('clearIframeList')
this.clearViewTags()
this.clearKeepLive()
this.clearIframeList()
},
mounted() {
this.refreshSwitch()
//
document.onkeydown = (e) => {
if (e.defaultPrevented) {
return;
let formData = ref(config.SYS_BASE_CONFIG)
configApi.configSysBaseList().then((data) => {
if (data) {
data.forEach((item) => {
formData.value[item.configKey] = item.configValue
})
this.captchaOpen = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN
tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
this.setSysBaseConfig(formData.value)
this.refreshSwitch()
}
const body = document.getElementsByTagName('body')[0];
// match(httpshttpwww)
if (e.keyCode === 13 && e.target.baseURI.match("/login") && e.target === body) {
this.login()
}
}
})
},
methods: {
...mapActions(keepAliveStore, ['clearKeepLive']),
...mapActions(viewTagsStore, ['clearViewTags']),
...mapActions(iframeStore, ['clearIframeList']),
...mapActions(globalStore, ['setSysBaseConfig']),
//
refreshSwitch() {
//
if (this.sysBaseConfig.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN === 'true') {
if (this.captchaOpen === 'true') {
//
this.loginCaptcha()
//
this.rules.validCode = [{ required: true, message: this.$t('login.validError'), trigger: 'blur' }]
this.rules.validCode = [required(this.$t('login.validError'), 'blur')]
}
},
//
@ -198,45 +205,23 @@
},
//
async login() {
const validate = await this.$refs.loginForm.validate().catch(() => {})
if (!validate) return false
this.islogin = true
const loginData = {
account: this.ruleForm.account,
// SM2使hash
password: smCrypto.doSm2Encrypt(this.ruleForm.password),
validCode: this.ruleForm.validCode,
validCodeReqNo: this.ruleForm.validCodeReqNo
}
// token
const login = await loginApi.login(loginData).finally(() => {
this.islogin = false
})
this.$TOOL.data.set('TOKEN', login)
//
const loginUser = await loginApi.getLoginUser()
this.$TOOL.data.set('USER_INFO', loginUser)
//
const menu = await userCenterApi.userLoginMenu().catch(() => {
this.islogin = false
return
})
this.islogin = false
const indexMenu = menu[0].children[0].path
this.$TOOL.data.set('MENU', menu)
//
this.$TOOL.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
this.$router.replace({
path: indexMenu
})
this.$message.success('登录成功')
this.$nextTick(() => {
dictApi.dictTree().then((data) => {
// store
this.$TOOL.data.set('DICT_TYPE_TREE_DATA', data)
})
this.$refs.loginForm.validate().then(async () => {
this.loading = true
const loginData = {
account: this.ruleForm.account,
// SM2使hash
password: smCrypto.doSm2Encrypt(this.ruleForm.password),
validCode: this.ruleForm.validCode,
validCodeReqNo: this.ruleForm.validCodeReqNo
}
// token
try {
const loginToken = await loginApi.login(loginData)
afterLogin(loginToken)
} catch (err) {
this.loading = false
this.loginCaptcha()
}
})
},
configLang(key) {
@ -246,156 +231,6 @@
}
</script>
<style lang="less" scoped>
.login_background {
width: 100%;
height: 100%;
overflow: hidden;
background-size: cover;
background-position: center;
background-image: url(/img/login_background.png);
}
.login_background_front {
width: 450px;
height: 450px;
margin-left: 100px;
margin-top: 15%;
overflow: hidden;
/*position: relative;*/
background-size: cover;
background-position: center;
background-image: url(/img/login_background_front.png);
animation-name: myfirst;
animation-duration: 5s;
animation-timing-function: linear;
animation-delay: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-play-state: running;
/* Safari and Chrome: */
-webkit-animation-name: myfirst;
-webkit-animation-duration: 5s;
-webkit-animation-timing-function: linear;
-webkit-animation-delay: 1s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: alternate;
-webkit-animation-play-state: running;
}
@keyframes myfirst {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
@-webkit-keyframes myfirst /* Safari and Chrome */ {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
.login_adv__title h2 {
font-size: 40px;
}
.login_adv__title h4 {
font-size: 18px;
margin-top: 10px;
font-weight: normal;
}
.login_adv__title p {
font-size: 14px;
margin-top: 10px;
line-height: 1.8;
color: rgba(255, 255, 255, 0.6);
}
.login_adv__title div {
margin-top: 10px;
display: flex;
align-items: center;
}
.login_adv__title div span {
margin-right: 15px;
}
.login_adv__title div i {
font-size: 40px;
}
.login_adv__title div i.add {
font-size: 20px;
color: rgba(255, 255, 255, 0.6);
}
/*background-image:linear-gradient(transparent, #000);*/
.login_main {
flex: 1;
overflow: auto;
display: flex;
}
.login-form {
top: 15%;
right: 15%;
position: absolute;
width: 450px;
margin-left: 10%;
margin-top: 20px;
padding: 10px 0;
}
.login-header {
margin-bottom: 20px;
}
.login-header .logo {
display: flex;
align-items: center;
}
.login-header .logo img {
width: 35px;
height: 35px;
vertical-align: bottom;
margin-right: 10px;
}
.login-header .logo label {
font-size: 24px;
}
.login-header h2 {
font-size: 24px;
font-weight: bold;
margin-top: 40px;
}
.login_config {
position: absolute;
top: 20px;
right: 20px;
}
@media (max-width: 1200px) {
.login-form {
width: 340px;
}
}
@media (max-width: 1000px) {
.login_main {
display: block;
}
.login_background_front {
display: none;
}
.login-form {
width: 100%;
padding: 20px 40px;
right: 0 !important;
top: 0 !important;
}
}
<style lang="less">
@import 'login';
</style>

View File

@ -3,7 +3,7 @@
<a-form-item name="phone">
<a-input v-model:value="phoneFormData.phone" :placeholder="$t('login.phonePlaceholder')" size="large">
<template #prefix>
<mobile-outlined style="color: rgba(0, 0, 0, 0.25)" />
<mobile-outlined class="text-black text-opacity-25" />
</template>
</a-input>
</a-form-item>
@ -16,21 +16,21 @@
size="large"
>
<template #prefix>
<mail-outlined style="color: rgba(0, 0, 0, 0.25)" />
<mail-outlined class="text-black text-opacity-25" />
</template>
</a-input>
</a-col>
<a-col :span="7">
<a-button size="large" style="width: 100%" @click="getPhoneValidCode" :disabled="state.smsSendBtn">{{
(!state.smsSendBtn && $t('login.getSmsCode')) || state.time + ' s'
}}</a-button>
<a-button size="large" style="width: 100%" @click="getPhoneValidCode" :disabled="state.smsSendBtn">
{{ (!state.smsSendBtn && $t('login.getSmsCode')) || state.time + ' s' }}
</a-button>
</a-col>
</a-row>
</a-form-item>
<a-form-item>
<a-button type="primary" style="width: 100%" :loading="islogin" round size="large" @click="submitLogin">{{
$t('login.signIn')
}}</a-button>
<a-button type="primary" style="width: 100%" :loading="loading" round size="large" @click="submitLogin">
{{ $t('login.signIn') }}
</a-button>
</a-form-item>
</a-form>
<a-modal
@ -50,7 +50,7 @@
size="large"
>
<template #prefix>
<verified-outlined style="color: rgba(0, 0, 0, 0.25)" />
<verified-outlined class="text-black text-opacity-25" />
</template>
</a-input>
</a-col>
@ -69,16 +69,13 @@
<script setup name="smsLoginForm">
import { message } from 'ant-design-vue'
import { nextTick } from 'vue'
import tool from '@/utils/tool'
import router from '@/router'
import { required, rules } from '@/utils/formRules'
import loginApi from '@/api/auth/loginApi'
import userCenterApi from '@/api/sys/userCenterApi'
import dictApi from '@/api/dev/dictApi'
import { afterLogin } from './util'
const phoneLoginFormRef = ref()
const phoneFormData = ref({})
const islogin = ref(false)
const loading = ref(false)
let state = ref({
time: 60,
smsSendBtn: false
@ -109,36 +106,13 @@
// delete phoneFormData.value.phoneValidCode
phoneFormData.value.validCodeReqNo = phoneValidCodeReqNo.value
islogin.value = true
const token = await loginApi.loginByPhone(phoneFormData.value).finally(() => {
islogin.value = false
})
tool.data.set('TOKEN', token)
//
const loginUser = await loginApi.getLoginUser()
tool.data.set('USER_INFO', loginUser)
//
const menu = await userCenterApi.userLoginMenu().catch(() => {
islogin.value = false
return
})
islogin.value = false
const indexMenu = menu[0].children[0].path
tool.data.set('MENU', menu)
//
tool.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
router.replace({
path: indexMenu
})
message.success('登录成功')
nextTick(() => {
dictApi.dictTree().then((data) => {
// store
tool.data.set('DICT_TYPE_TREE_DATA', data)
})
})
loading.value = true
try {
const token = await loginApi.loginByPhone(phoneFormData.value)
afterLogin(token)
} catch (err) {
loading.value = false
}
}
//

View File

@ -1,6 +1,6 @@
<template>
<a-divider>{{ $t('login.signInOther') }}</a-divider>
<div class="login-oauth">
<div class="login-oauth layout-center">
<a-space align="start">
<a @click="getLoginRenderUrl('gitee')"><GiteeIcon /></a>
<a-button type="primary" shape="circle">
@ -23,9 +23,4 @@
}
</script>
<style scoped>
.login-oauth {
display: flex;
justify-content: center;
}
</style>
<style scoped></style>

View File

@ -0,0 +1,35 @@
import loginApi from '@/api/auth/loginApi'
import userCenterApi from '@/api/sys/userCenterApi'
import dictApi from '@/api/dev/dictApi'
import router from '@/router'
import tool from '@/utils/tool'
import { message } from 'ant-design-vue'
import { useGlobalStore } from '@/store'
export const afterLogin = async (loginToken) => {
tool.data.set('TOKEN', loginToken)
// 获取登录的用户信息
const loginUser = await loginApi.getLoginUser()
const globalStore = useGlobalStore()
globalStore.setUserInfo(loginUser)
tool.data.set('USER_INFO', loginUser)
// 获取用户的菜单
const menu = await userCenterApi.userLoginMenu()
let indexMenu = menu[0].children[0].path
tool.data.set('MENU', menu)
// 重置系统默认应用
tool.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
message.success('登录成功')
if (!!tool.data.get('LAST_VIEWS_PATH')) {
// 如果有缓存,将其登录跳转到最后访问的路由
indexMenu = tool.data.get('LAST_VIEWS_PATH')
}
await router.replace({
path: indexMenu
})
dictApi.dictTree().then((data) => {
// 设置字典到store中
tool.data.set('DICT_TYPE_TREE_DATA', data)
})
}

View File

@ -1,11 +1,9 @@
<template>
<a-drawer
<xn-form-container
title="令牌列表"
:width="650"
:visible="visible"
:destroy-on-close="true"
:body-style="{ paddingBottom: '80px' }"
:footer-style="{ textAlign: 'right' }"
@close="onClose"
>
<a-button
@ -66,12 +64,12 @@
</template>
<template v-if="column.dataIndex === 'action'">
<a-popconfirm title="确定要强退此令牌吗?" @confirm="exitToken(record)">
<a-button type="link" danger size="small" :loading="exitLoading" >强退</a-button>
<a-button type="link" danger size="small" :loading="exitLoading">强退</a-button>
</a-popconfirm>
</template>
</template>
</a-table>
</a-drawer>
</xn-form-container>
</template>
<script setup>

View File

@ -1,6 +1,6 @@
<template>
<a-card :bordered="false" :body-style="{ 'padding-bottom': '0px' }" class="mb-2">
<a-form ref="formRef" 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-col :span="8">
<a-form-item label="关键字" name="searchKey">
@ -15,7 +15,7 @@
</a-col>
<a-col :span="6">
<a-button type="primary" @click="table.refresh(true)">查询</a-button>
<a-button style="margin: 0 8px" @click="() => formRef.resetFields()">重置</a-button>
<a-button style="margin: 0 8px" @click="reset">重置</a-button>
</a-col>
</a-row>
</a-form>
@ -46,7 +46,7 @@
import thirdApi from '@/api/auth/thirdApi'
import tool from '@/utils/tool'
let searchFormState = reactive({})
const formRef = ref()
const searchFormRef = ref()
const table = ref()
const toolConfig = { refresh: true, height: true, columnSetting: false, striped: false }
const columns = [
@ -87,11 +87,11 @@
return res
})
}
//
const reset = () => {
searchFormRef.value.resetFields();
table.value.refresh(true)
}
//
const categoryOptions = tool.dictTypeList('THIRD_CATEGORY').map((item) => {
return {
value: item['dictValue'],
label: item['name']
}
})
const categoryOptions = tool.dictList('THIRD_CATEGORY')
</script>

View File

@ -1,11 +1,9 @@
<template>
<a-drawer
<xn-form-container
:title="formData.id ? '编辑机构' : '增加机构'"
:width="500"
:width="550"
:visible="visible"
:destroy-on-close="true"
:body-style="{ paddingBottom: '80px' }"
:footer-style="{ textAlign: 'right' }"
@close="onClose"
>
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
@ -25,7 +23,7 @@
}"
selectable="false"
tree-line
></a-tree-select>
/>
</a-form-item>
<a-form-item label="机构名称:" name="name">
<a-input v-model:value="formData.name" placeholder="请输入机构名称" allow-clear />
@ -36,11 +34,10 @@
:options="orgCategoryOptions"
style="width: 100%"
placeholder="请选择机构分类"
>
</a-select>
/>
</a-form-item>
<a-form-item label="排序:" name="sortCode">
<a-slider v-model:value="formData.sortCode" :max="100" />
<a-input-number style="width: 100%" v-model:value="formData.sortCode" :max="100" />
</a-form-item>
<a-form-item label="指定主管:" name="directorId">
<a-button type="link" style="padding-left: 0px" @click="openSelector(formData.directorId)">选择</a-button>
@ -61,19 +58,17 @@
:radio-model="true"
@onBack="userBack"
/>
</a-drawer>
</xn-form-container>
</template>
<script setup name="bizOrgForm">
import { required, rules } from '@/utils/formRules'
import { message } from 'ant-design-vue'
import { required } from '@/utils/formRules'
import bizOrgApi from '@/api/biz/bizOrgApi'
import { getCurrentInstance } from 'vue'
import userSelectorPlus from '@/components/Selector/userSelectorPlus.vue'
import tool from '@/utils/tool'
// emit
const emit = defineEmits({ successful: null })
const { proxy } = getCurrentInstance()
//
let visible = $ref(false)
let UserSelectorPlus = ref()
@ -86,12 +81,15 @@
const submitLoading = ref(false)
//
const onOpen = (record) => {
const onOpen = (record, parentId) => {
visible = true
extJson.value = ref([])
formData.value = {
sortCode: 99
}
if (parentId) {
formData.value.parentId = parentId
}
if (record) {
const param = {
id: record.id
@ -124,12 +122,7 @@
sortCode: [required('请选择排序')]
}
//
let orgCategoryOptions = proxy.$TOOL.dictTypeList('ORG_CATEGORY').map((item) => {
return {
value: item['dictValue'],
label: item['name']
}
})
const orgCategoryOptions = tool.dictList('ORG_CATEGORY')
//
const openSelector = (id) => {
let checkedUserIds = []
@ -157,11 +150,15 @@
.then(() => {
submitLoading.value = true
formData.value.extJson = JSON.stringify(extJson.value)
bizOrgApi.submitForm(formData.value, !formData.value.id).then(() => {
submitLoading.value = false
visible = false
emit('successful')
})
bizOrgApi
.submitForm(formData.value, !formData.value.id)
.then(() => {
visible = false
emit('successful')
})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
}
@ -170,5 +167,3 @@
onOpen
})
</script>
<style scoped></style>

View File

@ -19,7 +19,7 @@
<a-row :gutter="24">
<a-col :span="8">
<a-form-item name="searchKey" label="名称关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入机构名称关键词"></a-input>
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入机构名称关键词" />
</a-form-item>
</a-col>
<a-col :span="8">
@ -27,7 +27,7 @@
<template #icon><SearchOutlined /></template>
查询
</a-button>
<a-button class="snowy-buttom-left" @click="() => searchFormRef.resetFields()">
<a-button class="snowy-buttom-left" @click="reset">
<template #icon><redo-outlined /></template>
重置
</a-button>
@ -39,20 +39,29 @@
<s-table
ref="table"
:columns="columns"
:data="loadDate"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:row-key="(record) => record.id"
:tool-config="toolConfig"
:row-selection="options.rowSelection"
>
<template #operator class="table-operator">
<a-space>
<a-button type="primary" @click="form.onOpen()" v-if="hasPerm('bizOrgAdd')">
<a-button
type="primary"
@click="form.onOpen(undefined, searchFormState.parentId)"
v-if="hasPerm('bizOrgAdd')"
>
<template #icon><plus-outlined /></template>
新增
</a-button>
<a-button danger @click="deleteBatchOrg()" v-if="hasPerm('bizOrgBatchDelete')">删除</a-button>
<xn-batch-delete
v-if="hasPerm('bizOrgBatchDelete')"
:selectedRowKeys="selectedRowKeys"
@batchDelete="deleteBatchOrg"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
@ -75,7 +84,7 @@
</template>
<script setup name="bizOrg">
import { message, Empty } from 'ant-design-vue'
import { Empty } from 'ant-design-vue'
import bizOrgApi from '@/api/biz/bizOrgApi'
import Form from './form.vue'
@ -116,6 +125,7 @@
}
}
}
const toolConfig = { refresh: true, height: true, columnSetting: true }
// tableDOM
const table = ref(null)
const form = ref()
@ -129,33 +139,43 @@
const cardLoading = ref(true)
// Promise
const loadDate = (parameter) => {
const loadData = (parameter) => {
loadTreeData()
return bizOrgApi.orgPage(Object.assign(parameter, searchFormState)).then((res) => {
return res
})
}
//
const reset = () => {
searchFormRef.value.resetFields()
table.value.refresh(true)
}
//
const loadTreeData = () => {
bizOrgApi.orgTree().then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
// 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)
})
bizOrgApi
.orgTree()
.then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
// 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
})
}
//
const treeSelect = (selectedKeys) => {
@ -178,16 +198,7 @@
})
}
//
const deleteBatchOrg = () => {
if (selectedRowKeys.value.length < 1) {
message.warning('请选择一条或多条数据')
return false
}
const params = selectedRowKeys.value.map((m) => {
return {
id: m
}
})
const deleteBatchOrg = (params) => {
bizOrgApi.orgDelete(params).then(() => {
table.value.clearRefreshSelected()
})

View File

@ -1,11 +1,9 @@
<template>
<a-drawer
<xn-form-container
:title="formData.id ? '编辑岗位' : '增加岗位'"
:width="500"
:width="550"
:visible="visible"
:destroy-on-close="true"
:body-style="{ paddingBottom: '80px' }"
:footer-style="{ textAlign: 'right' }"
@close="onClose"
>
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
@ -40,26 +38,24 @@
</a-select>
</a-form-item>
<a-form-item label="排序:" name="sortCode">
<a-slider v-model:value="formData.sortCode" :max="100" />
<a-input-number style="width: 100%" v-model:value="formData.sortCode" :max="100" />
</a-form-item>
</a-form>
<template #footer>
<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
<a-button type="primary" :loading="submitLoading" @click="onSubmit">保存</a-button>
</template>
</a-drawer>
</xn-form-container>
</template>
<script setup name="bizPositionForm">
import { required } from '@/utils/formRules'
import { getCurrentInstance } from 'vue'
import { message } from 'ant-design-vue'
import bizOrgApi from '@/api/biz/bizOrgApi'
import bizPositionApi from '@/api/biz/bizPositionApi'
import tool from '@/utils/tool'
// emit
const emit = defineEmits({ successful: null })
const { proxy } = getCurrentInstance()
//
let visible = $ref(false)
const formRef = ref()
@ -70,11 +66,14 @@
const submitLoading = ref(false)
//
const onOpen = (record) => {
const onOpen = (record, orgId) => {
visible = true
formData.value = {
sortCode: 99
}
if (orgId) {
formData.value.orgId = orgId
}
if (record) {
formData.value = Object.assign({}, record)
}
@ -101,23 +100,22 @@
category: [required('请选择岗位分类')],
sortCode: [required('请选择排序')]
}
let positionCategoryOptions = proxy.$TOOL.dictTypeList('POSITION_CATEGORY').map((item) => {
return {
value: item['dictValue'],
label: item['name']
}
})
const positionCategoryOptions = tool.dictList('POSITION_CATEGORY')
//
const onSubmit = () => {
formRef.value
.validate()
.then(() => {
submitLoading.value = true
bizPositionApi.submitForm(formData.value, !formData.value.id).then(() => {
visible = false
submitLoading.value = false
emit('successful')
})
bizPositionApi
.submitForm(formData.value, !formData.value.id)
.then(() => {
visible = false
emit('successful')
})
.finally(() => {
submitLoading.value = false
})
})
.catch(() => {})
}

View File

@ -19,7 +19,7 @@
<a-row :gutter="24">
<a-col :span="8">
<a-form-item name="searchKey" label="名称关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入岗位名称关键词"></a-input>
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入岗位名称关键词" />
</a-form-item>
</a-col>
<a-col :span="8">
@ -27,7 +27,7 @@
<template #icon><SearchOutlined /></template>
查询
</a-button>
<a-button class="snowy-buttom-left" @click="() => searchFormRef.resetFields()">
<a-button class="snowy-buttom-left" @click="reset">
<template #icon><redo-outlined /></template>
重置
</a-button>
@ -39,20 +39,29 @@
<s-table
ref="table"
:columns="columns"
:data="loadDate"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:tool-config="toolConfig"
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
>
<template #operator class="table-operator">
<a-space>
<a-button type="primary" @click="form.onOpen()" v-if="hasPerm('bizPositionAdd')">
<a-button
type="primary"
@click="form.onOpen(undefined, searchFormState.orgId)"
v-if="hasPerm('bizPositionAdd')"
>
<template #icon><plus-outlined /></template>
新增
</a-button>
<a-button danger @click="deleteBatchPosition()" v-if="hasPerm('bizPositionBatchDelete')">删除</a-button>
<xn-batch-delete
v-if="hasPerm('bizPositionBatchDelete')"
:selectedRowKeys="selectedRowKeys"
@batchDelete="deleteBatchPosition"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
@ -75,7 +84,7 @@
</template>
<script setup name="bizPosition">
import { message, Empty } from 'ant-design-vue'
import { Empty } from 'ant-design-vue'
import bizPositionApi from '@/api/biz/bizPositionApi'
import bizOrgApi from '@/api/biz/bizOrgApi'
import Form from './form.vue'
@ -117,6 +126,7 @@
}
}
}
const toolConfig = { refresh: true, height: true, columnSetting: true }
// tableDOM
const table = ref(null)
const form = ref()
@ -130,31 +140,41 @@
const cardLoading = ref(true)
// Promise
const loadDate = (parameter) => {
const loadData = (parameter) => {
return bizPositionApi.positionPage(Object.assign(parameter, searchFormState)).then((res) => {
return res
})
}
//
const reset = () => {
searchFormRef.value.resetFields()
table.value.refresh(true)
}
//
bizOrgApi.orgTree().then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
// 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)
})
bizOrgApi
.orgTree()
.then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
// 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
})
//
const treeSelect = (selectedKeys) => {
if (selectedKeys.length > 0) {
@ -176,16 +196,7 @@
})
}
//
const deleteBatchPosition = () => {
if (selectedRowKeys.value.length < 1) {
message.warning('请选择一条或多条数据')
return false
}
const params = selectedRowKeys.value.map((m) => {
return {
id: m
}
})
const deleteBatchPosition = (params) => {
bizPositionApi.positionDelete(params).then(() => {
table.value.clearRefreshSelected()
})

View File

@ -1,11 +1,10 @@
<template>
<a-drawer
<xn-form-container
:title="formData.id ? '编辑人员' : '增加人员'"
:width="620"
:width="800"
:visible="visible"
:destroy-on-close="true"
:body-style="{ paddingBottom: '80px', 'padding-top': '0px' }"
:footer-style="{ textAlign: 'right' }"
:body-style="{ 'padding-top': '0px' }"
@close="onClose"
>
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
@ -232,8 +231,8 @@
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="证号码:" name="idCardNumber">
<a-input v-model:value="formData.idCardNumber" placeholder="请输入通信地址" allow-clear />
<a-form-item label="证号码:" name="idCardNumber">
<a-input v-model:value="formData.idCardNumber" placeholder="请输入证件号码" allow-clear />
</a-form-item>
</a-col>
</a-row>
@ -325,17 +324,17 @@
<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
<a-button type="primary" :loading="formLoading" @click="onSubmit">保存</a-button>
</template>
</a-drawer>
</xn-form-container>
</template>
<script setup>
import bizUserApi from '@/api/biz/bizUserApi'
import { required, rules } from '@/utils/formRules'
import { required } from '@/utils/formRules'
import tool from '@/utils/tool'
//
let visible = $ref(false)
const formRef = ref()
const activeTabsKey = ref('1')
const { proxy } = getCurrentInstance()
const emit = defineEmits({ successful: null })
const formLoading = ref(false)
const treeData = ref([])
@ -351,33 +350,42 @@
let formData = ref({})
//
const onOpen = (record) => {
const onOpen = (record, orgId) => {
visible = true
formData.value = {
gender: '男',
positionJson: []
}
if (orgId) {
formData.value.orgId = orgId
//
nextTick(() => {
selePositionData(orgId)
})
}
if (record) {
convertFormData(record)
}
//
bizUserApi.userOrgTreeSelector().then((res) => {
if (res !== null) {
treeData.value = res
// 2
treeData.value.forEach((item) => {
// 0
if (item.parentId === '0') {
treeDefaultExpandedKeys.value.push(item.id)
// ID
if (item.children) {
item.children.forEach((items) => {
treeDefaultExpandedKeys.value.push(items.id)
})
nextTick(() => {
//
bizUserApi.userOrgTreeSelector().then((res) => {
if (res !== null) {
treeData.value = res
// 2
treeData.value.forEach((item) => {
// 0
if (item.parentId === '0') {
treeDefaultExpandedKeys.value.push(item.id)
// ID
if (item.children) {
item.children.forEach((items) => {
treeDefaultExpandedKeys.value.push(items.id)
})
}
}
}
})
}
})
}
})
})
}
//
@ -496,7 +504,11 @@
formRef.value.validate().then(() => {
//
let formDatas = JSON.parse(JSON.stringify(formData.value))
formDatas.positionJson = JSON.stringify(formDatas.positionJson)
if (formDatas.positionJson && formDatas.positionJson.length > 0) {
formDatas.positionJson = JSON.stringify(formDatas.positionJson)
} else {
delete formDatas.positionJson
}
formLoading.value = true
bizUserApi
.submitForm(formDatas, !formDatas.id)
@ -510,33 +522,13 @@
})
}
//
const genderOptions = proxy.$TOOL.dictTypeList('GENDER').map((item) => {
return {
value: item['dictValue'],
label: item['name']
}
})
const genderOptions = tool.dictList('GENDER')
//
const nationOptions = proxy.$TOOL.dictTypeList('NATION').map((item) => {
return {
value: item['dictValue'],
label: item['name']
}
})
const nationOptions = tool.dictList('NATION')
//
const idcardTypeOptions = proxy.$TOOL.dictTypeList('IDCARD_TYPE').map((item) => {
return {
value: item['dictValue'],
label: item['name']
}
})
const idcardTypeOptions = tool.dictList('IDCARD_TYPE')
//
const cultureLevelOptions = proxy.$TOOL.dictTypeList('CULTURE_LEVEL').map((item) => {
return {
value: item['dictValue'],
label: item['name']
}
})
const cultureLevelOptions = tool.dictList('CULTURE_LEVEL')
//
defineExpose({

View File

@ -14,55 +14,72 @@
</a-card>
</a-col>
<a-col :span="19">
<a-card :bordered="false" style="margin-bottom: 10px">
<a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
<a-row :gutter="24">
<a-col :span="8">
<a-form-item name="searchKey" :label="$t('common.searchKey')">
<a-input
v-model:value="searchFormState.searchKey"
:placeholder="$t('user.placeholderNameAndSearchKey')"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item name="userStatus" :label="$t('user.userStatus')">
<a-select v-model:value="searchFormState.userStatus" :placeholder="$t('user.placeholderUserStatus')">
<a-select-option v-for="item in statusData" :key="item.value" :value="item.value">{{
item.label
}}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-button type="primary" @click="table.refresh(true)">
<template #icon><SearchOutlined /></template>
{{ $t('common.searchButton') }}
</a-button>
<a-button class="snowy-buttom-left" @click="reset">
<template #icon><redo-outlined /></template>
{{ $t('common.resetButton') }}
</a-button>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="table"
:columns="columns"
:data="loadDate"
:data="loadData"
:expand-row-by-click="true"
bordered
:alert="options.alert.show"
:tool-config="toolConfig"
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
>
<template #operator class="table-operator">
<a-form
ref="searchFormRef"
name="advanced_search"
class="ant-advanced-search-form"
:model="searchFormState"
>
<a-row :gutter="24">
<a-col :span="6">
<a-form-item name="searchKey">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入姓名或账号"></a-input>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="userStatus">
<a-select v-model:value="searchFormState.userStatus" placeholder="请选择状态">
<a-select-option v-for="item in statusData" :key="item.dictValue" :value="item.dictValue">{{
item.name
}}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-button type="primary" @click="table.refresh(true)">{{ $t('common.searchButton') }}</a-button>
<a-button class="snowy-buttom-left" @click="() => searchFormRef.resetFields()">{{
$t('common.resetButton')
}}</a-button>
</a-col>
<a-col :span="6">
<a-button type="primary" class="primaryAdd" @click="form.onOpen()" v-if="hasPerm('bizUserAdd')">
<span>{{ $t('common.addButton') }}{{ $t('model.bizUser') }}</span>
</a-button>
<a-button danger @click="removeBatchUser()" v-if="hasPerm('bizUserBatchDelete')">{{
$t('common.batchRemoveButton')
}}</a-button>
</a-col>
</a-row>
</a-form>
<a-space>
<a-button
type="primary"
@click="form.onOpen(undefined, searchFormState.orgId)"
v-if="hasPerm('bizUserAdd')"
>
<template #icon><plus-outlined /></template>
<span>{{ $t('common.addButton') }}{{ $t('model.user') }}</span>
</a-button>
<a-button @click="exportBatchUserVerify" v-if="hasPerm('bizUserBatchExport')">
<template #icon><export-outlined /></template>
{{ $t('user.batchExportButton') }}
</a-button>
<xn-batch-delete
v-if="hasPerm('bizUserBatchDelete')"
:buttonName="$t('common.batchRemoveButton')"
:selectedRowKeys="selectedRowKeys"
@batchDelete="deleteBatchUser"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'avatar'">
@ -82,18 +99,41 @@
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="form.onOpen(record)" v-if="hasPerm('bizUserEdit')">{{ $t('common.editButton') }}</a>
<a-divider type="vertical" v-if="hasPerm(['bizUserEdit', 'bizUserGrantRole'], 'and')" />
<a @click="selectRole(record)" v-if="hasPerm('bizUserGrantRole')">角色</a>
<a-divider type="vertical" v-if="hasPerm(['bizUserGrantRole', 'bizUserPwdReset'], 'and')" />
<a-popconfirm title="确定重置此人员密码?" @confirm="resetPassword(record)">
<a v-if="hasPerm('bizUserPwdReset')">重置密码</a>
</a-popconfirm>
<a-divider type="vertical" v-if="hasPerm(['bizUserPwdReset', 'bizUserDelete'], 'and')" />
<a-popconfirm title="确定要删除此人员吗?" @confirm="removeUser(record)">
<a-divider type="vertical" v-if="hasPerm(['bizUserEdit', 'bizUserDelete'], 'and')" />
<a-popconfirm :title="$t('user.popconfirmDeleteUser')" @confirm="removeUser(record)">
<a-button type="link" danger size="small" v-if="hasPerm('bizUserDelete')">{{
$t('common.removeButton')
}}</a-button>
</a-popconfirm>
<a-divider
type="vertical"
v-if="hasPerm(['bizUserGrantRole', 'bizUserPwdReset', 'bizUserExportUserInfo'], 'and')"
/>
<a-dropdown v-if="hasPerm(['bizUserGrantRole', 'bizUserPwdReset', 'bizUserExportUserInfo'], 'and')">
<a class="ant-dropdown-link">
{{ $t('common.more') }}
<DownOutlined />
</a>
<template #overlay>
<a-menu>
<a-menu-item v-if="hasPerm('bizUserPwdReset')">
<a-popconfirm
:title="$t('user.popconfirmResatUserPwd')"
placement="topRight"
@confirm="resetPassword(record)"
>
<a>{{ $t('user.resetPassword') }}</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item v-if="hasPerm('bizUserGrantRole')">
<a @click="selectRole(record)">{{ $t('user.grantRole') }}</a>
</a-menu-item>
<a-menu-item v-if="hasPerm('bizUserExportUserInfo')">
<a @click="exportUserInfo(record)">{{ $t('user.exportUserInfo') }}</a>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
</template>
</s-table>
@ -111,7 +151,8 @@
</template>
<script setup name="bizUser">
import { message, Empty } from 'ant-design-vue'
import { getCurrentInstance } from 'vue'
import tool from '@/utils/tool'
import downloadUtil from '@/utils/downloadUtil'
import bizUserApi from '@/api/biz/bizUserApi'
import roleSelectorPlus from '@/components/Selector/roleSelectorPlus.vue'
import Form from './form.vue'
@ -158,16 +199,16 @@
width: '80px'
}
]
if (hasPerm(['bizUserEdit', 'bizUserGrantRole', 'bizUserPwdReset', 'bizUserDelete'])) {
if (hasPerm(['bizUserEdit', 'bizUserGrantRole', 'bizUserPwdReset', 'bizUserExportUserInfo', 'bizUserDelete'])) {
columns.push({
title: '操作',
dataIndex: 'action',
align: 'center',
width: '240px'
width: '220px'
})
}
const { proxy } = getCurrentInstance()
const statusData = proxy.$TOOL.dictTypeList('COMMON_STATUS')
const toolConfig = { refresh: true, height: true, columnSetting: true }
const statusData = tool.dictList('COMMON_STATUS')
const searchFormRef = ref()
let defaultExpandedKeys = ref([])
let searchFormState = reactive({})
@ -181,33 +222,43 @@
const selectedRecord = ref({})
const loading = ref(false)
const cardLoading = ref(true)
const ImpExpRef = ref()
// Promise
const loadDate = (parameter) => {
const loadData = (parameter) => {
return bizUserApi.userPage(Object.assign(parameter, searchFormState)).then((res) => {
return res
})
}
//
const reset = () => {
searchFormRef.value.resetFields()
table.value.refresh(true)
}
//
bizUserApi.userOrgTreeSelector().then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
// 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)
})
bizUserApi
.userOrgTreeSelector()
.then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
// 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
})
//
const options = {
alert: {
@ -235,15 +286,23 @@
const editStatus = (record) => {
loading.value = true
if (record.userStatus === 'ENABLE') {
bizUserApi.userDisableUser(record).then(() => {
loading.value = false
table.value.refresh()
})
bizUserApi
.userDisableUser(record)
.then(() => {
table.value.refresh()
})
.finally(() => {
loading.value = false
})
} else {
bizUserApi.userEnableUser(record).then(() => {
loading.value = false
table.value.refresh()
})
bizUserApi
.userEnableUser(record)
.then(() => {
table.value.refresh()
})
.finally(() => {
loading.value = false
})
}
}
//
@ -257,17 +316,39 @@
table.value.refresh()
})
}
//
const removeBatchUser = () => {
if (selectedRowKeys.value.length < 1) {
message.warning('请选择一条或多条数据')
//
const exportBatchUserVerify = () => {
if ((selectedRowKeys.value.length < 1) & !searchFormState.searchKey & !searchFormState.userStatus) {
message.warning('请输入查询条件或勾选要导出的信息')
}
if (selectedRowKeys.value.length > 0) {
const params = {
userIds: selectedRowKeys.value
.map((m) => {
return m
})
.join()
}
exportBatchUser(params)
return
}
const params = selectedRowKeys.value.map((m) => {
return {
id: m
if (searchFormState.searchKey || searchFormState.userStatus) {
const params = {
searchKey: searchFormState.searchKey,
userStatus: searchFormState.userStatus
}
exportBatchUser(params)
}
}
//
const exportBatchUser = (params) => {
bizUserApi.userExport(params).then((res) => {
downloadUtil.resultDownload(res)
table.value.clearSelected()
})
}
//
const deleteBatchUser = (params) => {
bizUserApi.userDelete(params).then(() => {
table.value.clearRefreshSelected()
})
@ -300,6 +381,15 @@
const resetPassword = (record) => {
bizUserApi.userResetPassword(record).then(() => {})
}
//
const exportUserInfo = (record) => {
const params = {
id: record.id
}
bizUserApi.userExportUserInfo(params).then((res) => {
downloadUtil.resultDownload(res)
})
}
</script>
<style scoped>

View File

@ -59,24 +59,22 @@
}
//
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
})
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
})
})
}
const layout = {
labelCol: {

View File

@ -55,24 +55,22 @@
}
//
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
})
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
})
})
}
const layout = {
labelCol: {

View File

@ -63,24 +63,22 @@
}
//
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
})
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
})
})
}
const layout = {
labelCol: {

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