项目初始化

This commit is contained in:
hxd 2025-08-06 18:44:13 +08:00
parent 012025080d
commit 575c278572
40 changed files with 5286 additions and 6273 deletions

View File

@ -37,7 +37,7 @@ module.exports = {
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-redeclare': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
'@typescript-eslint/no-unused-vars': [2],
'@typescript-eslint/no-unused-vars': 'warning',
'vue/custom-event-name-casing': 'off',
'vue/attributes-order': 'off',
'vue/one-component-per-file': 'off',

View File

@ -1,6 +1,6 @@
module.exports = {
// 一行最多多少个字符
printWidth: 150,
printWidth: 100,
// 指定每个缩进级别的空格数
tabWidth: 2,
// 使用制表符而不是空格缩进行

View File

@ -1,367 +0,0 @@
# <a href="https://gitee.com/lyt-top/vue-next-admin" target="_blank">vue-next-admin 更新日志</a>
🎉🎉🔥 `vue-next-admin` 基于 vue3.x 、Typescript、vite、Element plus 等适配手机、平板、pc 的后台开源免费模板库vue2.x 请切换 vue-prev-admin 分支)
## 2.2.0
`2022.07.10`
⚡⚡⚡ [/sec/stores/userInfo.ts](https://gitee.com/lyt-top/vue-next-admin/blob/master/src/stores/userInfo.ts) 下添加了 `getApiUserInfo` 接口模拟数据 `setTimeout` 为 3 秒
- 🌟 更新 依赖更新最新版本
- 🐞 修复 [主界面重新授权按钮点击卡死不跳转登录界面#I5C3JS](https://gitee.com/lyt-top/vue-next-admin/issues/I5C3JS),感谢[@Hero-Typ](https://gitee.com/tian_yu_peng)
- 🐞 修复 编译警告[#I5CVSB](https://gitee.com/lyt-top/vue-next-admin/issues/I5CVSB),全局替换成 `:deep(attr)`,感谢[@Linvas](https://gitee.com/linvas)。参考文档:[vue3 sfc-style](https://v3.cn.vuejs.org/api/sfc-style.html#style-scoped)。`node_modules\print-js\dist\print.js``print-js` 作者适配或去除 `package.json` 中的 `"print-js": "^1.6.0"`
- 🐞 修复 [vue-next-admin-template-js 版本前端控制路由userInfo.js 请求用户信息接口报错,加载不到路由 可以写个定时器模拟一下接口 一样的报错#I5F1HP](https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP),感谢[@白开水](https://gitee.com/libin951223)
## 2.1.1
`2022.05.27`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 深色模式下,`<el-button text></el-button>` 时,`:active` 样式
- 🎯 优化 [页面缓存在刷新之后失效 #I58U75](https://gitee.com/lyt-top/vue-next-admin/issues/I58U75)),感谢[@ls0428](https://gitee.com/ls0428)
- 🎯 优化 [SvgIcon 对下载的 Svg 图像设置颜色无效 #I59ND0](https://gitee.com/lyt-top/vue-next-admin/issues/I59ND0)),感谢[@elus_z](https://gitee.com/elus_z)
- 🎯 优化 `/src/utils/toolsValidate.ts` 工具类
- 🐞 修复 [布局切换TagsView 显示的 tab 会多一个出来 #I58WGM](https://gitee.com/lyt-top/vue-next-admin/issues/I58WGM),感谢[@lg_boy](https://gitee.com/lg_boy)
- 🐞 修复 [如果设置顶部面包屑导航开启图标 isBreadcrumbIcon=true 后,样式有点问题 如果不开启就是正常的 #I58VB8](https://gitee.com/lyt-top/vue-next-admin/issues/I58VB8)
- 🐞 修复 地址栏路由地址输入错误时,返回首页后,再次输入路由地址错误时,不跳转 404 问题
- 🐞 修复 [2.1.0 版本的图标选择组件多次点击后功能失效 #I590TH](https://gitee.com/lyt-top/vue-next-admin/issues/I590TH),感谢[@quber](https://gitee.com/quber)
## 2.1.0
`2022.04.18`
⚡⚡⚡ 此版本为破环性更新,优化内容如下:(谨慎更新!谨慎更新!!谨慎更新!!!)。因为 `vuex` 替换成 `pinia`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 部分界面图片不显示问题(更换 gitee 在线图片地址源)
- 🎯 优化 各界面方法引入与逻辑之间添加一行空行,方便区分内容
- 🎯 优化 图标选择器 [#I4YAHB](https://gitee.com/lyt-top/vue-next-admin/issues/I4YAHB),感谢[@真有你的](https://gitee.com/sunliusen)
- 🎯 优化 图标选择器 icon type 类型为 all 时,类型 ali、ele、awe 回显问题
- 🎯 优化 去掉开发环境 i18n 控制台警告,页面代码:[i18n/index.ts](https://gitee.com/lyt-top/vue-next-admin/blob/master/src/i18n/index.ts)
- 🎯 优化 `NextLoading.start()` 方法,防止第一次进入界面时出现短暂空白
- 🎯 优化 地址栏有参数退出登录,再次登录不跳之前界面问题 `src/layout/navBars/breadcrumb/user.vue`
- 🎯 优化 `SvgIcon` 组件,防止 `开启 Tagsview 图标` 时,`tagsView 右键菜单关闭` 报错问题,工作流不可连线、全屏时关闭按钮消失问题
- 🎯 优化 [如果 url 中有中文等特殊字符,第一次切换该 tab 时 keep-alive 失效#I55JS7](https://gitee.com/lyt-top/vue-next-admin/issues/I55JS7),感谢[yuyong1566](https://gitee.com/yuyong1566)
- 🎯 优化 [wangEditor](https://www.wangeditor.com/) 更新到 v5[vue3 版本线上示例中 wangeditor 富文本编辑器 demo 实例,无法换行#I5565B](https://gitee.com/lyt-top/vue-next-admin/issues/I5565B),感谢@[jenchih](https://gitee.com/jenchih)
- 🎯 优化 [在关闭 tagview 时,高度刷新时会会变化,出现滚动条](https://gitee.com/lyt-top/vue-next-admin/issues/I55FHM),感谢[张松](https://gitee.com/zs310071113)
- 🎯 优化 [路由参数](https://lyt-top.gitee.io/vue-next-admin-preview/#/params/common)演示
- 🎉 新增 [vuex](https://vuex.vuejs.org/) 替换成 [pinia](https://pinia.vuejs.org/getting-started.html)
- 🎉 新增 tagsView 支持自定义 tagsView 名称(文章详情时有用),前往体验:[路由参数/普通路由](https://lyt-top.gitee.io/vue-next-admin-preview/#/params/common)。新增 tagsView 支持自定义名称国际化,感谢[@q7but](https://gitee.com/q7but)、[!22 add 添加自定义 tagVIewName 拓展,支持国际化](https://gitee.com/lyt-top/vue-next-admin/pulls/22/files)、感谢[@tony_tong_xin](https://gitee.com/tony_tong_xin)
- 🐞 修复 适配 `"element-plus": "^2.1.9"2.2.0` 版本
- 🐞 修复 [导航栏横向布局后,一级菜单显示问题#I4Z3M3](https://gitee.com/lyt-top/vue-next-admin/issues/I4Z3M3)
- 🐞 修复 横向布局三级及以上导航菜单高亮、导航高度不统一问题
- 🐞 修复 分栏模式下,选中的菜单是 primary 样式,鼠标移入字也变成 primary 色了,感谢群友@孤夜-流殇
- 🐞 修复 [vuex 里面改了颜色 但是不生效 #I4WFMA](https://gitee.com/lyt-top/vue-next-admin/issues/I4WFMA)
- 🐞 修复 全局主题 primary 清空颜色后报错,[#I4X0LG](https://gitee.com/lyt-top/vue-next-admin/issues/I4X0LG),感谢[面向 BUG 编程](https://gitee.com/fhtfy)
- 🐞 修复 [.eslintrc.js 文件 rules 标签名错误 #I53IPK](https://gitee.com/lyt-top/vue-next-admin/issues/I53IPK),感谢[yuyong1566](https://gitee.com/yuyong1566)
- 🐞 修复 `开启 Tagsview 图标` 时,`tagsView 右键菜单关闭` 报错问题
- 🐞 修复 `router.push` 路径找不到时报错问题,`404、401 界面` 已移入到 `main` 主布局里(之前全屏)
- 🐞 修复 [全局修改组件大小失效了](https://gitee.com/lyt-top/vue-next-admin/issues/I551RP),感谢[lg_boy](https://gitee.com/lg_boy)
- 🐞 修复 [修改一下配置时,需要每次都清理 `window.localStorage` 浏览器永久缓存,配置才会生效,问题解决#I567R1](https://gitee.com/lyt-top/vue-next-admin/issues/I567R1),感谢[@lanbao123](https://gitee.com/lanbao123)
- 🐞 修复 [标记为需要缓存的 tab 页后,再次从左侧菜单打开,还是显示被缓存的页面内容#I4UY3G](https://gitee.com/lyt-top/vue-next-admin/issues/I4UY3G),感谢@axcc1234、特别感谢群友@华仔
- 🌈 重构 路由(`/src/router/index.ts`)解决 No match found for location with path "xxx"(前端控制,后端控制未解决) 问题
## 2.0.2
`2022.03.04`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 Alert 提示添加边框
- 🎯 优化 功能 / 数字滚动 演示界面
- 🐞 修复 全局主题按钮颜色 :active 问题
- 🐞 修复 Dropdown 下拉菜单样式问题
- 🐞 修复 SvgIcon 图标组件动态切换时报警告问题,[SvgIcon 改变 name 时可能导致图像不显示](https://gitee.com/lyt-top/vue-next-admin/issues/I4VGE0),感谢@axcc1234
## 2.0.1
`2022.02.25`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 svgIcon 图标组件
- 🎯 优化 vite.config.ts 打包,感谢群友@YourObjec
- 🐞 修复 tagViews 开启图标不显示问题(风格 5感谢群友@坏人
- 🐞 修复 [Element Plus 1.2.0-beta.6 以后的版本 el-table 在移动端无法左右滑动](https://gitee.com/lyt-top/vue-next-admin/issues/I4UPTP),感谢@YGDada
## 2.0.0
`2022.02.21`
⚡⚡⚡ 此版本为破环性更新,优化内容如下:(谨慎更新!谨慎更新!!谨慎更新!!!)。演示界面建议直接覆盖文件。如需使用之前版本,请前往[gitee 发行版](https://gitee.com/lyt-top/vue-next-admin/releases) 进行对应版本下载。基础版会基于 `master` 分支进行修改
- 🌟 更新 依赖更新最新版本
- 🌟 更新 登录页、首页
- 💔 移除 vue-web-screen-shot
- 💔 移除 城市多级联动,完整 json 数据请去 [vue-next-admin-images/menu](https://gitee.com/lyt-top/vue-next-admin-images/tree/master/menu) 仓库查看
- 💔 移除 功能/echartsTree 树图
- 💔 移除 其它设置/Tagsview 风格 2、Tagsview 风格 3
- 💔 移除 功能/验证器
- 🚧 调整 src/api 编写方式
- 🚧 调整 自定义封装公用组件演示,更好的维护
- 🎉 新增 Volar 支持vs code 配置参考 [Vue Language Features (Volar)](https://lyt-top.gitee.io/vue-next-admin-doc-preview/home/vscode/)
- 🎉 新增 `SvgIcon` 支持本地 svg 图标使用
- 🎉 新增 表单表格验证演示
- 🎯 优化 全局主题(移除 success、info、warning、danger
- 🎯 优化 工作流(开源)
- 🎯 优化 element plus svg 图标,`elementXXX` 改成 `ele-XXX`
- 🌈 重构 深色模式
- 🌹 合并 [处理 parent 的 h100 由于外层有 min-height 导致失效的问题](https://gitee.com/lyt-top/vue-next-admin/pulls/20),感谢@MaxNull@21030442-mao
- 🐞 修复 element plus 升级 `^1.3.0-beta.5` 后 组件 size 大小问题(大改:涉及布局、演示界面)
- 🐞 修复 vs code 使用 Vue Language Features (Volar) 插件 代码报红问题(可以把公用的 ts 类型定义封装起来公用)
## 1.2.2
`2021.12.21`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 iframes 滚动条问题
- 🎯 优化 部署后每次都要强制刷新清浏览器缓存问题
- 🎉 新增 工具类百分比验证演示
- 🐞 修复 [tag-view 标签右键会超出浏览器 #I4KN78](https://gitee.com/lyt-top/vue-next-admin/issues/I4KN78)
## 1.2.1
`2021.12.12`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 cropper 裁剪时卡顿问题 [#I4M2VQ](https://gitee.com/lyt-top/vue-next-admin/issues/I4M2VQ)
- 🎯 优化 Wangeditor 富文本编辑器的问题 [#I4LPC1](https://gitee.com/lyt-top/vue-next-admin/issues/I4LPC1)、[#I4LM7I](https://gitee.com/lyt-top/vue-next-admin/issues/I4LM7I)
- 🐞 修复 浏览器标题问题
- 🐞 修复 element plus svg 图标引入
- 🐞 修复 工作流不可以拖线连接问题
## 1.2.0
`2021.11.28`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 深色模式
- 🎯 优化 `/@/utils` 文件夹,合并删除单一内容
- 🎯 优化 系统设置:菜单管理(新增、修改)、角色管理(新增菜单权限)、用户管理、部门管理、字典管理
- 🎯 优化 登录界面逻辑、权限管理逻辑
- 🎯 优化 同步 [vue-next-admin-images](https://gitee.com/lyt-top/vue-next-admin-images/tree/master/menu) 后端控制菜单模拟数据
- 🎉 新增 适配 Font Icon 向 SVG Icon 迁移(改动大,"element-plus": "^1.2.0-beta.4" 谨慎更新)
- 🐞 修复 热更新问题,感谢@甜蜜蜜
- 🐞 修复 页面/element 字体图标演示
- 🐞 修复 功能/图标选择器演示,新增高级功能 [issues #I4GJXQ](https://gitee.com/lyt-top/vue-next-admin/issues/I4GJXQ)
## 1.1.2
`2021.10.17`
- 🌟 更新 依赖更新最新版本
- 🐞 修复 开启全屏时,刷新界面被还原成未全屏的状态
- 🎯 优化 tagsView 右键菜单关闭逻辑
- 🎯 优化 wangeditor 富文本编辑器(增加双向绑定)
- 🎉 新增 工作流(暂不开源)
- 🎉 新增 基础版 ts不带国际化切换 `vue-next-admin-template` 分支
## 1.1.1
`2021.09.25`
- 🌟 更新 依赖更新最新版本(`"element-plus": "^1.1.0-beta.13"` 版本运行错误,`^1.1.0-beta.16`修复横向菜单卡死问题)
- 🐞 修复 Dialog 弹窗位置错误、Drawer 抽屉内边距、el-menu 菜单收起时背景色问题
- 🎯 优化 锁屏界面自动锁屏(s/秒)必须设置至少 1 秒
- 🎉 新增 分栏布局,鼠标移入当前项时,显示当前项菜单内容
- 🎉 新增 工作流(未完成)
## 1.1.0
`2021.09.10`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 小屏模式下登录页二维码遮挡标题问题
- 🎉 新增 图片验证器
- 🎉 新增 动态复杂表单
- 🎉 新增 工作流(未完成)
- 🎉 新增 深色主题(伪深色,样式变动大,谨慎更新)
## 1.0.18
`2021.08.29`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 权限组件去掉顶级 div`/src/components/auth`
- 🎉 新增 布局配置添加恢复默认按钮
- 🐞 修复 升级 <a href="https://element-plus.gitee.io/#/zh-CN/component/changelog" target="_blank">element plus 1.1.0-beta.7</a>后项目无法启动、el-menu 菜单
- 🐞 修复 表格固定列时的层级、设置了相对定位时,遮挡左侧导航菜单问题
## 1.0.17
`2021.08.22`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 去除设置布局切换重置主题样式initSetLayoutChange切换布局需手动设置样式设置的样式自动同步各布局
- 🎯 优化 Dropdown 下拉菜单用户账号靠边时换行问题
- 🎯 优化 左侧导航菜单,共用菜单树,防止 `布局配置` 设置 `菜单 / 顶栏` 时,样式丢失等问题
- 🐞 修复 固定 header 后没有回到顶部的 bug拉取项目后运行不起来的 bug。<a href="https://gitee.com/lyt-top/vue-next-admin/pulls/14" target="_blank">!14</a>,感谢<a href="https://gitee.com/wjs0509" target="_blank">@wjs0509</a>
- 🐞 修复 tagView 右键全屏后,浏览器窗口大小发生任何变化都会导致左边菜单显示出来,并且可点击打开对应页面。<a href="https://gitee.com/lyt-top/vue-next-admin/issues/I46E6T" target="_blank">I46E6T</a>
- 🐞 修复 默认设置 `菜单 / 顶栏` 样式不生效问题(/@/src/store/modules/themeConfig.ts
## 1.0.16
`2021.08.14`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 菜单高亮(详情且详情设置了 meta.isHide 时,顶级菜单高亮),感谢群友@YourObject
- 🎯 优化 详情路径写法:如父级(/pages/filtering那么详情为/pages/filtering/details?id=1。这样写可实现详情时父级菜单高亮否则写成/pages/filteringDetails?id=1顶级菜单将不会高亮。可参考`页面/过滤筛选组件`,点击当前图片进行测试
- 🎯 优化 tagsView 右键菜单全屏时,打开的界面高度问题
- 🎯 优化 图表批量 resize 问题
- 🐞 修复 菜单收起时设置全局主题primary 且有二级菜单时),文字高亮颜色不对
- 🐞 修复 国际化 <a href="https://gitee.com/lyt-top/vue-next-admin/issues/I43NPE" target="_blank">#I43NPE</a>。可参考:`页面/过滤筛选组件`,点击顶部语言切换,进行底部分页国际化查看
## 1.0.15
`2021.08.06`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 tagsView 右键菜单点击时的字段名id 已修改成 contextMenuClickId与路由中返回的 id 名冲突问题,感谢群友@伯牙已遇钟子期
- 🎉 新增 多个 form 表单验证界面演示
## 1.0.14
`2021.07.29`
- 🌟 更新 依赖更新最新版本vue、vuex、vue-router,出现问题,请手动降级。版本查看:<a href="https://www.npmjs.com/" target="_blank">vnpm</a>
- 🎯 优化 数据可视化图表演示加载卡顿问题、优化有图表的演示界面
- 🎯 优化 路由参数演示界面
- 🎯 优化 tagsView 操作演示界面由于存在相同路由多标签必须要传全部参数值query 或者 params
- 🎉 新增 开启 TagsView 共用开启时多个路由菜单共用一个详情组件参数为后点击的覆盖前面点击的tagsView 中只会出现一个(不支持同时出现多个 tagsView 标签))。关闭时:(多个路由菜单共用一个详情组件,参数不同,会同时出现多个 tagsView 标签)
- 🐞 修复 tagsView 共用(单标签)时,右键菜单功能点击,参数不对的问题(第 2n+个参数未覆盖第一个参数值)
- 🐞 修复 多 tagsView 标签(参数不同)、单个 tagsView 标签公用(参数不同)所带来的刷新功能、横向自动滚动等问题
- 🐞 修复 处理全屏若干问题,<a href="https://gitee.com/lyt-top/vue-next-admin/pulls/12" target="_blank">pr!12</a>,感谢群友@另一个前端
## 1.0.13
`2021.07.25`
- 🌟 更新 依赖更新最新版本
- 🎉 新增 数据可视化演示界面(/visualizingDemo1、/visualizingDemo2
- 🎉 新增 登录页扫码登录
## 1.0.12
`2021.07.16`
- 🌟 更新 依赖更新最新版本
- 🎉 新增 数据可视化演示空界面(待完善)
- 🎯 优化 tagsView 动态路由xxx/:id/:name时的右键菜单刷新、关闭其它时参数丢失问题2021.07.15 优化)
- 🐞 修复 路由带参数时,复制路径到登录页,跳转后参数消失的问题
- 🐞 修复 设置多个外链,点击后,页面内容停留在上一个内容(内容未改变)、国际化处理、打开新窗口 sessionStorage 共享等
## 1.0.11
`2021.07.14`
- 🌟 更新 依赖更新最新版本
- 🎉 新增 路由参数、图片懒加载界面演示
- ⚠️ 警告 Form 表单 `binding value must be a string or number`,解决:加上 `label-position="top"` 不报警告(等待官方修复)
- 🎯 优化 锁屏界面动画效果、首页图表显示
- 🎯 优化 tagsView 右键菜单 `关闭` 功能逻辑
- 🐞 修复 开启 TagsView 拖拽报错及小于 `1000px` 时自动设置禁止拖拽(<a href="https://gitee.com/lyt-top/vue-next-admin/issues/I3ZRRI" target="_blank">#I3ZRRI</a>
- 🐞 修复 `iframe 内嵌、外链` 高度问题,使用 computed 进行计算
- 🐞 修复 默认布局开启 `侧边栏 Logo` 与关闭 `菜单水平折叠`,切换到横向布局时,菜单看不见的问题
- 🐞 修复 切换不同布局时,再去开启 `经典布局分割菜单` 功能不生效问题
- 🐞 修复 浏览器窗口标题中/英文切换不实时生效的问题
- 🐞 修复 切换布局时,某些功能不可以使用。部分界面不需要取消事件监听(proxy.mittBus.off('xxx'))
- 🐞 修复 动态路由带参数router-link 跳转问题(<a href="hhttps://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G" target="_blank">#I3YX6G</a>
- 🐞 修复 横向菜单有二级菜单时,点击子级菜单不高亮问题
- 🐞 修复 功能 tagsView 操作演示不生效
## 1.0.10
`2021.07.07`
- 🌟 更新 依赖更新最新版本(字体图标无问题)
- 🎯 优化 内嵌 iframe、外链解决 tagsView 刷新问题
## 1.0.9
`2021.07.02`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 图标选择器设置宽度、v-model 等问题
- 🎯 优化 滚动通知栏在手机上的体验
- 🎯 优化 系统管理/新增菜单(编辑菜单),使用 `图标选择器` 进行模拟
- 🎯 优化 字体图标(自动载入) 逻辑
- 🐞 修复 screenfull 全屏时,按键盘 esc 键图标不改变问题,感谢群友@伯牙已遇钟子期
## 1.0.8
`2021.06.29`
- 🌟 更新 依赖更新最新版本
- 🎉 新增 表单中英文切换演示
- 🎯 优化 登录页查看密码 icon 图标
- 🎯 优化 图标选择器
- 🎯 优化 拖动指令
- 🐞 修复 form 表单在页面小于 576px 时的排版问题
## 1.0.7
`2021.06.24`
- 🌟 更新 依赖更新最新版本
- 🎉 新增 拖动指令及其演示界面
- 🎯 优化 锁屏界面,解锁提示
- 🎯 优化 登录页在手机上显示的效果
## 1.0.6
`2021.06.23`
- 🎯 优化 去掉内嵌 iframe 内边距padding
- 🎯 优化 城市多级联动组件
- 🎯 优化 Tree 树形控件改成表格组件
- 🐞 修复 Cascader 级联选择器高度问题
## 1.0.5
`2021.06.22`
- 🌟 更新 vite 降级为@vite2.3.7,降级方法 `cnpm install vite@2.3.7`,防止 element plus 字体图标消失
- 🐞 修复 开启后端控制路由isRequestRoutes = true内嵌 iframe、外链不可使用的问题
## 1.0.4
`2021.06.19`
- 🌟 更新 依赖更新最新版本("vite": "^2.3.7")热更新无问题
- 🎉 新增 深克隆工具,方便开发,感谢<a href="https://gitee.com/kangert" target="_blank">@kangert</a>(<a href="https://gitee.com/lyt-top/vue-next-admin/pulls/6" target="_blank">#6</a>)
- 🎯 优化 vuex 模块自动导入。感谢<a href="https://gitee.com/kangert" target="_blank">@kangert</a>(<a href="https://gitee.com/lyt-top/vue-next-admin/pulls/4" target="_blank">#4</a>),感谢群友@web 小学生-第五君
- 🎯 优化 类型定义提高编码体验修复不能将类型“string | undefined”分配给类型“string”的问题。感谢<a href="https://gitee.com/kangert" target="_blank">@kangert</a>(<a href="https://gitee.com/lyt-top/vue-next-admin/pulls/5" target="_blank">#5</a>)
- 🎯 优化 `layout` 文件夹移动到与 `views` 文件夹同级(改动较大,`/@/views/layout` 变成 `/@/layout`
- 🎯 优化 页面有 `console.log``eslint` 不生效问题
- 🎯 优化 页面、ts 中 `any` 类型问题(改动较大)
- 🎯 优化 登录页在手机上显示的效果
- 🎯 优化 多行注释信息,鼠标放到方法名即可查看,更加直观的知道方法参数等。引入方法时需去掉以 `.ts` 结尾的后缀(改动较大)
- 🎯 优化 移除 `utils/storage.ts` 下的旧写法(改动较大)
- 🎯 优化 拆分 `router` 下内容,路由、前端、后端控制分开写,方便理解
- 🐞 修复 鼠标移入顶部用户信息栏 `开/关全屏` 文字反向问题
- 🐞 修复 热更新时NextLoading界面 loading 不消失问题 `window.nextLoading === undefined`
- 🐞 修复 vuex 中不可以使用 `/@/api/xxx` 下的接口调用问题
## 1.0.3
`2021.06.02`
- ❄️ 删除 G6 思维导图界面
- 🌟 更新 手动更新 vue、vue-router、vuex 到最近最多人使用的版本,出现不可预测的问题请降低版本。版本查看:<a href="https://www.npmjs.com/package/vue" target="_blank">vue 版本查看</a>
- 🐞 修复 开启后端控制路由 `isRequestRoutes` 在非首页刷新页面后,回到首页的问题,感谢群友@伯牙已遇钟子期
## 1.0.2
`2021.06.01`
- 🌟 更新 依赖更新最新版本
- 🐞 修复 菜单搜索中文不可以搜索的问题,感谢群友@逍遥天意
## 1.0.1
`2021.05.31`
- 🎉 新增 更新日志文件 `CHANGELOG.md`,以后每次更新都会在这里显示对应内容
- 🌟 更新 依赖更新最新版本
- 🐞 修复 分栏、经典布局路由设置 `meta.isHide``true` 时报错问题,感谢群友@29@芭芭拉
- 🐞 修复 经典布局点击 `tagsView` 左侧菜单数据不变问题

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2021 lyt-Top
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,57 +0,0 @@
<div align="center">
<img src="https://yxh-1301841944.cos.ap-chongqing.myqcloud.com/gfast/2022-04-19/gfastlogo.png">
<p align="center">
<a href="https://v3.vuejs.org/" target="_blank">
<img src="https://img.shields.io/badge/vue.js-vue3.x-green" alt="vue">
</a>
<a href="https://element-plus.gitee.io/#/zh-CN/component/changelog" target="_blank">
<img src="https://img.shields.io/badge/element--plus-%3E1.0.0-blue" alt="element plus">
</a>
<a href="https://www.tslang.cn/" target="_blank">
<img src="https://img.shields.io/badge/typescript-%3E4.0.0-blue" alt="typescript">
</a>
<a href="https://vitejs.dev/" target="_blank">
<img src="https://img.shields.io/badge/vite-%3E2.0.0-yellow" alt="vite">
</a>
<a href="https://gitee.com/lyt-top/vue-next-admin/blob/master/LICENSE" target="_blank">
<img src="https://img.shields.io/badge/license-MIT-success" alt="license">
</a>
</p>
<p>&nbsp;</p>
</div>
#### 🌈 介绍
基于 vue3.x + CompositionAPI + typescript + vite + element plus + vue-router-next + next.vuex适配手机、平板、pc 的后台开源免费模板,希望减少工作量,帮助大家实现快速开发。
#### 🚧 安装 cnpm、yarn
- 复制代码(桌面 cmd 运行) `npm install -g cnpm --registry=https://registry.npm.taobao.org`
- 复制代码(桌面 cmd 运行) `npm install -g yarn`
#### 🏭 环境支持
| Edge | last 2 versions | last 2 versions | last 2 versions |
| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ |
| ![Edge](https://cdn.jsdelivr.net/npm/@browser-logos/edge/edge_32x32.png) | ![Firefox](https://cdn.jsdelivr.net/npm/@browser-logos/firefox/firefox_32x32.png) | ![Chrome](https://cdn.jsdelivr.net/npm/@browser-logos/chrome/chrome_32x32.png) | ![Safari](https://cdn.jsdelivr.net/npm/@browser-logos/safari/safari_32x32.png) |
> 由于 Vue3 不再支持 IE11故而 ElementPlus 也不支持 IE11 及之前版本。
#### ⚡ 使用说明
建议使用 cnpm因为 yarn 有时会报错。<a href="http://nodejs.cn/" target="_blank">node 版本[v16.x ~ v20.x)</a>
```bash
# 克隆项目
git clone -b v3.2 https://gitee.com/tiger1103/gfast-ui.git
# 进入项目
cd gfast-ui
# 安装依赖
npm install --registry=https://registry.npmmirror.com
# 运行项目
npm run dev
# 打包发布
npm run build
```
## ❤特别鸣谢
* 感谢[VUE-NEXT-ADMIN](https://github.com/lyt-Top/vue-next-admin)

1500
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@
"@codemirror/lang-javascript": "^6.1.1",
"@codemirror/theme-one-dark": "^6.1.0",
"@element-plus/icons-vue": "^2.3.1",
"@vue/reactivity": "^3.5.18",
"axios": "1.8.2",
"codemirror": "^6.0.1",
"countup.js": "^2.8.0",
@ -46,6 +47,7 @@
"vue-ueditor-wrap": "^3.0.8"
},
"devDependencies": {
"@types/js-cookie": "^3.0.6",
"@types/node": "^20.11.28",
"@types/nprogress": "^0.2.3",
"@types/sortablejs": "^1.15.8",
@ -61,7 +63,7 @@
"sass-loader": "^16.0.3",
"typescript": "^5.4.2",
"vite": "6.3.4",
"vite-plugin-cdn-import": "^0.3.5",
"vite-plugin-cdn-import": "^1.0.1",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-vue-setup-extend-plus": "^0.1.0",
"vue-eslint-parser": "^9.4.1"

3516
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

4
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,4 @@
onlyBuiltDependencies:
- '@parcel/watcher'
- esbuild
- vue-demi

View File

@ -0,0 +1,163 @@
<template>
<div>
<el-table
ref="tableRef"
:data="data"
:row-key="rowKey"
:border="border"
:stripe="stripe"
:loading="loading"
:height="tableHeight"
:size="size"
:highlight-current-row="highlightCurrentRow"
@row-dblclick="onRowDblClick"
@selection-change="onSelectionChange"
@sort-change="onSortChange"
v-bind="tableProps"
>
<!-- 选择框 -->
<el-table-column v-if="showSelection" type="selection" width="55" align="center" />
<!-- 序号 -->
<el-table-column v-if="showIndex" type="index" width="55" align="center" label="#" />
<template v-for="col in columns" :key="col.prop">
<!-- <el-table-column
v-if="col.isFormater"
:prop="col.prop"
:label="col.label"
:width="col.width"
:min-width="col.minWidth"
:align="col.align || 'center'"
:sortable="col.sortable || false"
:fixed="col.fixed || false"
:show-overflow-tooltip="col.showOverflowTooltip || true"
:formatter="(row:any,col:any)=>col.formater(row,col)"
/> -->
<div >{{col}}</div>
<!-- <el-table-column
v-else
:prop="col.prop"
:label="col.label"
:width="col.width"
:min-width="col.minWidth"
:align="col.align || 'center'"
:sortable="col.sortable || false"
:fixed="col.fixed || false"
:show-overflow-tooltip="col.showOverflowTooltip || true"
>
<template #default="scope">
<slot v-if="$slots[col.prop]" :name="col.prop" v-bind="scope" />
<component
v-else-if="col.render"
:is="col.render"
v-bind="{ row: scope.row, col, index: scope.$index }"
/>
<span v-else>{{ scope.row[col.prop] }}</span>
</template>
</el-table-column> -->
</template>
<!-- 操作列 -->
<el-table-column
v-if="$slots.actions"
label="操作"
:fixed="actionFixed"
:width="actionWidth"
align="center"
>
<template #default="scope">
<slot name="actions" v-bind="scope" />
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
import { formatter, type TableColumnCtx } from 'element-plus';
import { TableColumn } from '../type';
interface Props {
columns: TableColumn[];
data: Record<string, any>[];
loading?: boolean;
rowKey?: string;
border?: boolean;
stripe?: boolean;
size?: 'small' | 'default' | 'large';
showIndex?: boolean;
showSelection?: boolean;
highlightCurrentRow?: boolean;
actionWidth?: string | number;
actionFixed?: 'left' | 'right' | boolean;
tableProps?: Record<string, any>; // Element Plus Table props
autoHeight?: boolean;
heightOffset?: number; //
}
const props = withDefaults(defineProps<Props>(), {
columns: () => [],
data: () => [],
loading: false,
rowKey: 'id',
border: false,
stripe: true,
size: 'default',
showIndex: false,
showSelection: false,
highlightCurrentRow: false,
actionWidth: 180,
actionFixed: 'right',
tableProps: () => ({}),
autoHeight: true,
heightOffset: 360,
});
defineOptions({ name: 'ProTable' });
const emit = defineEmits<{
(e: 'row-dblclick', row: any): void;
(e: 'selection-change', selection: any[]): void;
(e: 'sort-change', col: TableColumnCtx<any>): void;
}>();
//
const tableHeight = ref<string | number>('auto');
const calcHeight = () => {
if (props.autoHeight) {
tableHeight.value = window.innerHeight - props.heightOffset;
}
};
//
onMounted(() => {
calcHeight();
window.addEventListener('resize', calcHeight);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', calcHeight);
});
//
const onRowDblClick = (row: any) => emit('row-dblclick', row);
const onSelectionChange = (selection: any[]) => emit('selection-change', selection);
const onSortChange = (col: TableColumnCtx<any>) => emit('sort-change', col);
// Element Plus Table API
const tableRef = ref();
const clearSelection = () => tableRef.value?.clearSelection();
const toggleRowSelection = (row: any, selected?: boolean) =>
tableRef.value?.toggleRowSelection(row, selected);
const getSelectionRows = () => tableRef.value?.getSelectionRows();
defineExpose({
clearSelection,
toggleRowSelection,
getSelectionRows,
tableRef,
});
</script>

View File

@ -0,0 +1,199 @@
<template>
<div class="query-form">
<el-form ref="formRef" :model="modelValue" :label-width="labelWidth" :inline="inline">
<el-row :gutter="gutter">
<template v-for="(item, index) in fields" :key="item.prop">
<div class="form-item-wrapper" v-show="showAll || index < defaultFieldCount">
<el-form-item :label="item.label" :prop="item.prop" :rules="item.rules">
<!-- 插槽优先 -->
<slot :name="item.prop" :item="item" :form="modelValue">
<!-- 动态组件渲染 -->
<component
:is="getComponent(item.type)"
v-model="modelValue[item.prop]"
v-bind="getProps(item)"
@keyup.enter="item.type === 'input' && handleSearch()"
>
<!-- 下拉选项 -->
<template v-if="item.type === 'select'" #default>
<el-option
v-for="opt in item.options || []"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</template>
</component>
</slot>
</el-form-item>
</div>
</template>
<!-- 操作按钮 -->
<div class="form-item-wrapper actions">
<el-form-item>
<slot name="actions">
<el-button type="primary" :icon="Search" size="default" @click="handleSearch">
搜索
</el-button>
<el-button :icon="Refresh" size="default" @click="handleReset">重置</el-button>
<el-button link v-if="fields.length > defaultFieldCount" @click="toggleSearch">
{{ word }}
<el-icon>
<ele-ArrowUp v-if="showAll" />
<ele-ArrowDown v-else />
</el-icon>
</el-button>
</slot>
</el-form-item>
</div>
</el-row>
</el-form>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';
import { Search, Refresh } from '@element-plus/icons-vue';
import type { FormInstance } from 'element-plus';
import { QueryFormField } from '../type';
interface Props {
fields: QueryFormField[];
modelValue: Record<string, any>; //
defaultFieldCount?: number;
labelWidth?: string;
inline?: boolean;
gutter?: number;
}
const props = withDefaults(defineProps<Props>(), {
fields: () => [] as QueryFormField[],
modelValue: () => ({}),
defaultFieldCount: 3,
labelWidth: '100px',
inline: true,
gutter: 20,
});
defineOptions({ name: 'QueryForm' });
const emit = defineEmits<{
(e: 'update:modelValue', val: Record<string, any>): void;
(e: 'search', val: Record<string, any>): void;
(e: 'reset'): void;
}>();
const formRef = ref<FormInstance>();
const showAll = ref(false);
const toggleSearch = () => (showAll.value = !showAll.value);
const word = computed(() => (showAll.value ? '收起搜索' : '展开搜索'));
const dates = ['daterange', 'datetimerange'];
/**
* 初始化表单
*/
const initForm = () => {
const form: Record<string, any> = {};
props.fields.forEach((item) => {
form[item.prop] = item.defaultValue ?? '';
});
return form;
};
/**
* 更新父组件的值
*/
const updateModel = (val: Record<string, any>) => {
emit('update:modelValue', val);
};
/**
* 动态组件映射
*/
const componentMap: Record<string, any> = {
input: 'el-input',
select: 'el-select',
daterange: 'el-date-picker',
datetimerange: 'el-date-picker',
};
const getComponent = (type: string) => componentMap[type] || 'el-input';
/**
* 获取组件属性
*/
const getProps = (item: QueryFormField) => {
const commonProps = {
size: item.size || 'default',
placeholder: item.placeholder || '请输入',
};
if (item.type === 'select') {
return { ...commonProps, filterable: true };
}
if (dates.includes(item.type)) {
return {
...commonProps,
type: item.type,
'value-format': item.valueFormat || 'YYYY-MM-DD',
'range-separator': '至',
'start-placeholder': item.staerPlaceholder || '开始日期',
'end-placeholder': item.endPlaceholder || '结束日期',
style: { width: '220px' },
};
}
return commonProps;
};
const loadOptions = async () => {
let oldFetchOptions:any = [];
for (const field of props.fields) {
if (field.fetchOptions) {
if (!oldFetchOptions.includes(field.fetchOptions)) {
field.options = await field.fetchOptions();
oldFetchOptions.push(field.fetchOptions);
}
}
}
};
onMounted(() => {
loadOptions();
});
/**
* 搜索事件防抖
*/
const handleSearch = () => emit('search', props.modelValue);
/**
* 重置事件
*/
const handleReset = () => {
const newForm = initForm();
updateModel(newForm);
emit('reset');
};
/**
* 监听字段变化保持双向绑定
*/
watch(
() => props.modelValue,
(val) => updateModel(val),
{ deep: true }
);
</script>
<style scoped>
.form-item-wrapper {
display: block;
}
.query-form {
padding-bottom: 10px;
}
.actions {
display: flex;
align-items: center;
}
</style>

View File

@ -0,0 +1,34 @@
export interface OptionItem {
label: string;
value: string | number;
}
export interface QueryFormField {
label: string; // 显示的 label
prop: string; // 绑定的字段
type: 'input' | 'select' | 'date' | 'daterange' | 'datetimerange' | 'monthrange';
placeholder?: string;
size?: 'small' | 'default' | 'large';
defaultValue?: any;
options?: OptionItem[];
fetchOptions?: () => Promise<OptionItem[]>; // 异步加载 options
valueFormat?:string;
rules?: any[]; // 校验规则
staerPlaceholder?: string;
endPlaceholder?: string;
}
export interface TableColumn {
label: string;
prop: string;
width?: string | number;
minWidth?: string | number;
align?: 'left' | 'center' | 'right';
sortable?: boolean;
fixed?: 'left' | 'right' | boolean;
render?: any;
showOverflowTooltip?: boolean;
formater?: (row: any, column: any) => any;
isFormater?: boolean;
}

View File

@ -24,18 +24,18 @@
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="layout-navbars-breadcrumb-user-icon" @click="onSearchClick">
<!-- <div class="layout-navbars-breadcrumb-user-icon" @click="onSearchClick">
<el-icon :title="$t('message.user.title2')">
<ele-Search />
</el-icon>
</div>
<div class="layout-navbars-breadcrumb-user-icon" @click="onLayoutSetingClick">
</div> -->
<!-- <div class="layout-navbars-breadcrumb-user-icon" @click="onLayoutSetingClick">
<i class="icon-skin iconfont" :title="$t('message.user.title3')"></i>
</div>
</div> -->
<div class="layout-navbars-breadcrumb-user-icon" @click="removeCacheClick">
<i class="fa-trash fa" title="清除缓存"></i>
</div>
<div class="layout-navbars-breadcrumb-user-icon">
<!-- <div class="layout-navbars-breadcrumb-user-icon">
<el-popover ref="newPopoverRef" placement="bottom" trigger="click" transition="el-zoom-in-top" :width="500" :persistent="false">
<template #reference>
<el-badge :is-dot="true">
@ -48,7 +48,7 @@
<UserNews @hideNews="hideNews" />
</template>
</el-popover>
</div>
</div> -->
<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onScreenfullClick">
<i
class="iconfont"
@ -67,10 +67,10 @@
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="/home">{{ $t('message.user.dropdown1') }}</el-dropdown-item>
<el-dropdown-item command="wareHouse">{{ $t('message.user.dropdown6') }}</el-dropdown-item>
<!-- <el-dropdown-item command="wareHouse">{{ $t('message.user.dropdown6') }}</el-dropdown-item> -->
<el-dropdown-item command="/personal">{{ $t('message.user.dropdown2') }}</el-dropdown-item>
<el-dropdown-item command="/404">{{ $t('message.user.dropdown3') }}</el-dropdown-item>
<el-dropdown-item command="/401">{{ $t('message.user.dropdown4') }}</el-dropdown-item>
<!-- <el-dropdown-item command="/404">{{ $t('message.user.dropdown3') }}</el-dropdown-item> -->
<!-- <el-dropdown-item command="/401">{{ $t('message.user.dropdown4') }}</el-dropdown-item> -->
<el-dropdown-item divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item>
</el-dropdown-menu>
</template>
@ -80,7 +80,7 @@
</template>
<script setup lang="ts">
import {ref, getCurrentInstance, computed, reactive, toRefs, onMounted, defineComponent, watch} from 'vue';
import {ref, getCurrentInstance, computed, reactive, toRefs, onMounted, watch} from 'vue';
import { useRoute,useRouter } from 'vue-router';
import {ElMessageBox, ElMessage, ElNotification} from 'element-plus';
import screenfull from 'screenfull';
@ -90,7 +90,6 @@ import { useUserInfo } from '/@/stores/userInfo';
import { useThemeConfig } from '/@/stores/themeConfig';
import other from '/@/utils/other';
import { Session, Local } from '/@/utils/storage';
import UserNews from '/@/layout/navBars/breadcrumb/userNews.vue';
import Search from '/@/layout/navBars/breadcrumb/search.vue';
import {logout} from "/@/api/login";
import {removeCache} from "/@/api/system/cache";
@ -197,7 +196,6 @@ const onSearchClick = () => {
searchRef.value.openSearch();
};
const hideNews=()=>{
debugger
newPopoverRef.value.hide()
}
//
@ -263,7 +261,7 @@ const noticeStoreAct = noticeStore()
const getMessages = computed(() => {
return noticeStoreAct.message;
});
watch(getMessages,(nv,ov)=>{
watch(getMessages,(nv)=>{
if (!nv || !nv.id) {
return;
}

View File

@ -11,9 +11,7 @@ import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import '/@/theme/index.scss';
import mitt from 'mitt';
import VueGridLayout from 'vue-grid-layout';
import {findChildrenByPid, flattenTree, getUpFileUrl, handleTree, parseTime, selectDictLabel} from '/@/utils/gfast';
import Websocket from '/@/utils/websocket';
import {useDict} from '/@/api/system/dict/data';
import {getItems, setItems, getOptionValue, isEmpty} from '/@/api/items'
// 分页组件
@ -27,17 +25,6 @@ import VueUeditorWrap from 'vue-ueditor-wrap';
const app = createApp(App);
// 全局websocket
const onMessageList: Array<Function> = [];
app.provide('onMessageList', onMessageList);
const onMessage = (event: any) => {
onMessageList.forEach((f) => {
f.call(null, event);
});
};
Websocket(onMessage);
directive(app);
other.elSvg(app);
@ -47,7 +34,6 @@ app.use(pinia)
.use(router)
.use(ElementPlus)
.use(i18n)
.use(VueGridLayout)
.use(VueUeditorWrap)
.mount('#app');

View File

@ -1,10 +1,17 @@
import { RouteRecordRaw } from 'vue-router';
// Extend the Window interface to include nextLoading
declare global {
interface Window {
nextLoading?: any;
}
}
import pinia from '/@/stores/index';
import { useUserInfo } from '/@/stores/userInfo';
import { useRequestOldRoutes } from '/@/stores/requestOldRoutes';
import { Session } from '/@/utils/storage';
import { NextLoading } from '/@/utils/loading';
import { demoRoutes,dynamicRoutes, notFoundAndNoPower } from '/@/router/route';
import { dynamicRoutes, notFoundAndNoPower } from '/@/router/route';
import { formatTwoStageRoutes, formatFlatteningRoutes, router } from '/@/router/index';
import { useRoutesList } from '/@/stores/routesList';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
@ -47,7 +54,7 @@ export async function initBackEndControlRoutes() {
// 存储接口原始路由未处理component根据需求选择使用
useRequestOldRoutes().setRequestOldRoutes(JSON.parse(JSON.stringify(menuRoute)));
// 处理路由component替换 dynamicRoutes/@/router/route第一个顶级 children 的路由
dynamicRoutes[0].children?.push(...await backEndComponent(menuRoute),...demoRoutes);
dynamicRoutes[0].children?.push(...await backEndComponent(menuRoute));
// 添加动态路由
await setAddRoute();
// 设置路由到 vuex routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组

File diff suppressed because it is too large Load Diff

43
src/types/index.ts Normal file
View File

@ -0,0 +1,43 @@
export interface DeptItem {
deptId: number;
parentId: number;
ancestors: string;
deptName: string;
orderNum: number;
leader: null;
phone: string;
email: string;
status: number;
createdBy: number;
updatedBy: number;
createdAt: string;
updatedAt: string;
deletedAt: null;
};
export interface UserItem {
id: number;
userName: string;
mobile: string;
userNickname: string;
birthday: number;
userPassword: string;
userSalt: string;
userStatus: number;
userEmail: string;
sex: number;
avatar: string;
deptId: number;
remark: string;
isAdmin: number;
address: string;
describe: string;
lastLoginIp: string;
lastLoginTime: string;
createdAt: string;
updatedAt: string;
deletedAt: null;
openId : string;
dept: DeptItem;
roleInfo: null;
post: null;
};

View File

@ -0,0 +1,200 @@
<template>
<!-- 详情抽屉 -->
<div class="demo-speciesName-detail">
<el-drawer v-model="isShowDialog" size="80%" direction="ltr">
<template #header>
<h4>详情</h4>
</template>
<el-descriptions
class="margin-top"
:column="3"
border
style="margin: 8px;"
>
<el-descriptions-item :span="1">
<template #label>
<div class="cell-item">
主键
</div>
</template>
{{ formData.id }}
</el-descriptions-item>
<el-descriptions-item :span="1">
<template #label>
<div class="cell-item">
物种编号
</div>
</template>
{{ formData.speciesCode }}
</el-descriptions-item>
<el-descriptions-item :span="1">
<template #label>
<div class="cell-item">
物种名称
</div>
</template>
{{ formData.name }}
</el-descriptions-item>
<el-descriptions-item :span="1">
<template #label>
<div class="cell-item">
物种名称内容
</div>
</template>
{{ formData.content }}
</el-descriptions-item>
<el-descriptions-item :span="1">
<template #label>
<div class="cell-item">
数据来源
</div>
</template>
{{ formData.sourcesData }}
</el-descriptions-item>
<el-descriptions-item :span="1">
<template #label>
<div class="cell-item">
数据采集人
</div>
</template>
{{ formData.createUser }}
</el-descriptions-item>
<el-descriptions-item :span="1">
<template #label>
<div class="cell-item">
数据采集信息
</div>
</template>
{{ proxy.parseTime(formData.createDate, '{y}-{m}-{d} {h}:{i}:{s}') }}
</el-descriptions-item>
<el-descriptions-item :span="1">
<template #label>
<div class="cell-item">
数据核查人
</div>
</template>
{{ formData.auditUser }}
</el-descriptions-item>
<el-descriptions-item :span="1">
<template #label>
<div class="cell-item">
数据核查日期
</div>
</template>
{{ proxy.parseTime(formData.auditDate, '{y}-{m}-{d} {h}:{i}:{s}') }}
</el-descriptions-item>
<el-descriptions-item :span="1">
<template #label>
<div class="cell-item">
备注
</div>
</template>
{{ formData.remark }}
</el-descriptions-item>
</el-descriptions>
</el-drawer>
</div>
</template>
<script setup lang="ts">
import { reactive, toRefs, defineComponent,ref,unref,getCurrentInstance,computed } from 'vue';
import {ElMessageBox, ElMessage, FormInstance,UploadProps} from 'element-plus';
import {
listSpeciesName,
getSpeciesName,
delSpeciesName,
addSpeciesName,
updateSpeciesName,
} from "./api";
import {
SpeciesNameTableColumns,
SpeciesNameInfoData,
SpeciesNameTableDataState,
SpeciesNameEditState
} from "./type"
defineOptions({ name: "ApiV1BusinessesSpeciesNameDetail"})
const {proxy} = <any>getCurrentInstance()
const formRef = ref<HTMLElement | null>(null);
const menuRef = ref();
const state = reactive<SpeciesNameEditState>({
loading:false,
isShowDialog: false,
formData: {
id: undefined,
speciesCode: undefined,
name: undefined,
content: undefined,
sourcesData: undefined,
createUser: undefined,
createDate: undefined,
auditUser: undefined,
auditDate: undefined,
remark: undefined,
},
//
rules: {
id : [
{ required: true, message: "主键不能为空", trigger: "blur" }
],
name : [
{ required: true, message: "物种名称不能为空", trigger: "blur" }
],
}
});
const { isShowDialog,formData } = toRefs(state);
//
const openDialog = (row?: SpeciesNameInfoData) => {
resetForm();
if(row) {
getSpeciesName(row.id!).then((res:any)=>{
const data = res.data;
state.formData = data;
})
}
state.isShowDialog = true;
};
//
const closeDialog = () => {
state.isShowDialog = false;
};
defineExpose({
openDialog,
});
//
const onCancel = () => {
closeDialog();
};
const resetForm = ()=>{
state.formData = {
id: undefined,
speciesCode: undefined,
name: undefined,
content: undefined,
sourcesData: undefined,
createUser: undefined,
createDate: undefined,
auditUser: undefined,
auditDate: undefined,
remark: undefined,
}
};
</script>
<style scoped>
.demo-speciesName-detail :deep(.el-form-item--large .el-form-item__label){
font-weight: bolder;
}
.pic-block{
margin-right: 8px;
}
.file-block{
width: 100%;
border: 1px solid var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
margin-bottom: 5px;
padding: 3px 6px;
}
.ml-2{margin-right: 5px;}
</style>

View File

@ -0,0 +1,173 @@
<template>
<div class="demo-speciesName-edit">
<!-- 添加或修改对话框 -->
<el-dialog v-model="isShowDialog" width="800px" :close-on-click-modal="false" :destroy-on-close="true">
<template #header>
<div v-drag="['.demo-speciesName-edit .el-dialog', '.demo-speciesName-edit .el-dialog__header']">{{(!formData.id || formData.id==0?'添加':'修改')+''}}</div>
</template>
<el-form ref="formRef" :model="formData" :rules="rules" label-width="120px">
<el-form-item label="物种编号" prop="speciesCode">
<el-input v-model="formData.speciesCode" placeholder="请输入物种编号" />
</el-form-item>
<el-form-item label="物种名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入物种名称" />
</el-form-item>
<el-form-item label="物种名称内容" prop="content">
<el-input v-model="formData.content" placeholder="请输入物种名称内容" />
</el-form-item>
<el-form-item label="数据来源" prop="sourcesData">
<el-input v-model="formData.sourcesData" placeholder="请输入数据来源" />
</el-form-item>
<el-form-item label="数据采集人" prop="createUser">
<el-input v-model="formData.createUser" placeholder="请输入数据采集人" />
</el-form-item>
<el-form-item label="数据采集信息" prop="createDate">
<el-date-picker clearable style="width: 200px"
v-model="formData.createDate"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择数据采集信息">
</el-date-picker>
</el-form-item>
<el-form-item label="数据核查人" prop="auditUser">
<el-input v-model="formData.auditUser" placeholder="请输入数据核查人" />
</el-form-item>
<el-form-item label="数据核查日期" prop="auditDate">
<el-date-picker clearable style="width: 200px"
v-model="formData.auditDate"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择数据核查日期">
</el-date-picker>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="onSubmit" :disabled="loading"> </el-button>
<el-button @click="onCancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { reactive, toRefs, ref,unref,getCurrentInstance,computed } from 'vue';
import {ElMessageBox, ElMessage, FormInstance,UploadProps} from 'element-plus';
import {
listSpeciesName,
getSpeciesName,
delSpeciesName,
addSpeciesName,
updateSpeciesName,
} from "./api";
import {
SpeciesNameTableColumns,
SpeciesNameInfoData,
SpeciesNameTableDataState,
SpeciesNameEditState
} from "./type"
defineOptions({ name: "ApiV1BusinessesSpeciesNameEdit"})
const emit = defineEmits(['speciesNameList'])
const {proxy} = <any>getCurrentInstance()
const formRef = ref<HTMLElement | null>(null);
const menuRef = ref();
const state = reactive<SpeciesNameEditState>({
loading:false,
isShowDialog: false,
formData: {
id: undefined,
speciesCode: undefined,
name: undefined,
content: undefined,
sourcesData: undefined,
createUser: undefined,
createDate: undefined,
auditUser: undefined,
auditDate: undefined,
remark: undefined,
},
//
rules: {
id : [
{ required: true, message: "主键不能为空", trigger: "blur" }
],
name : [
{ required: true, message: "物种名称不能为空", trigger: "blur" }
],
}
});
const { loading,isShowDialog,formData,rules } = toRefs(state);
//
const openDialog = (row?: SpeciesNameInfoData) => {
resetForm();
if(row) {
getSpeciesName(row.id!).then((res:any)=>{
const data = res.data;
state.formData = data;
})
}
state.isShowDialog = true;
};
//
const closeDialog = () => {
state.isShowDialog = false;
};
defineExpose({
openDialog,
});
//
const onCancel = () => {
closeDialog();
};
//
const onSubmit = () => {
const formWrap = unref(formRef) as any;
if (!formWrap) return;
formWrap.validate((valid: boolean) => {
if (valid) {
state.loading = true;
if(!state.formData.id || state.formData.id===0){
//
addSpeciesName(state.formData).then(()=>{
ElMessage.success('添加成功');
closeDialog(); //
emit('speciesNameList')
}).finally(()=>{
state.loading = false;
})
}else{
//
updateSpeciesName(state.formData).then(()=>{
ElMessage.success('修改成功');
closeDialog(); //
emit('speciesNameList')
}).finally(()=>{
state.loading = false;
})
}
}
});
};
const resetForm = ()=>{
state.formData = {
id: undefined,
speciesCode: undefined,
name: undefined,
content: undefined,
sourcesData: undefined,
createUser: undefined,
createDate: undefined,
auditUser: undefined,
auditDate: undefined,
remark: undefined,
}
};
</script>
<style scoped>
.kv-label{margin-bottom: 15px;font-size: 14px;}
.mini-btn i.el-icon{margin: unset;}
.kv-row{margin-bottom: 12px;}
</style>

View File

@ -0,0 +1,45 @@
import request from '/@/utils/request'
// 查询列表
export function listSpeciesName(query:object) {
return request({
url: '/api/v1/businesses/speciesName/list',
method: 'get',
params: query
})
}
// 查询详细
export function getSpeciesName(id:number) {
return request({
url: '/api/v1/businesses/speciesName/get',
method: 'get',
params: {
id: id.toString()
}
})
}
// 新增
export function addSpeciesName(data:object) {
return request({
url: '/api/v1/businesses/speciesName/add',
method: 'post',
data: data
})
}
// 修改
export function updateSpeciesName(data:object) {
return request({
url: '/api/v1/businesses/speciesName/edit',
method: 'put',
data: data
})
}
// 删除
export function delSpeciesName(ids:number[]) {
return request({
url: '/api/v1/businesses/speciesName/delete',
method: 'delete',
data:{
ids:ids
}
})
}

View File

@ -0,0 +1,273 @@
<template>
<div>
<el-card shadow="hover">
<QueryForm
v-model="searchForm"
:fields="searchFields"
@search="onSearch"
@reset="onReset"
ref="queryFormRef"
/>
<el-row :gutter="10" style="padding-bottom: 10px">
<el-col :span="1.5">
<el-button type="primary" @click="handleAdd" v-auth="'api/v1/businesses/speciesName/add'"
><el-icon><ele-Plus /></el-icon>新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
:disabled="multiple"
@click="handleDelete(null)"
v-auth="'api/v1/businesses/speciesName/delete'"
><el-icon><ele-Delete /></el-icon>删除</el-button
>
</el-col>
</el-row>
<ProTable
ref="proTableRef"
:columns="columns"
:data="tableData.data"
:loading="loading"
:show-selection="true"
@selection-change="handleSelectionChange"
>
</ProTable>
<!-- <el-table-column
label="操作"
align="center"
class-name="small-padding"
min-width="160px"
fixed="right"
>
<template #default="scope">
<el-button
type="primary"
link
@click="handleUpdate(scope.row)"
v-auth="'api/v1/businesses/speciesName/edit'"
><el-icon><ele-EditPen /></el-icon>修改</el-button
>
<el-button
type="primary"
link
@click="handleDelete(scope.row)"
v-auth="'api/v1/businesses/speciesName/delete'"
><el-icon><ele-DeleteFilled /></el-icon>删除</el-button
>
</template>
</el-table-column> -->
<pagination
v-show="tableData.total > 0"
:total="tableData.total"
v-model:page="tableData.param.pageNum"
v-model:limit="tableData.param.pageSize"
@pagination="speciesNameList"
/>
</el-card>
<ApiV1BusinessesSpeciesNameEdit
ref="editRef"
@speciesNameList="speciesNameList"
></ApiV1BusinessesSpeciesNameEdit>
<ApiV1BusinessesSpeciesNameDetail
ref="detailRef"
@speciesNameList="speciesNameList"
></ApiV1BusinessesSpeciesNameDetail>
</div>
</template>
<script setup lang="ts">
import { toRefs, reactive, onMounted, ref, getCurrentInstance, toRaw, computed } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
import { listSpeciesName, delSpeciesName } from './api/index';
import { SpeciesNameTableColumns, SpeciesNameInfoData, SpeciesNameTableDataState } from './type';
import ApiV1BusinessesSpeciesNameDetail from './ApiV1BusinessesSpeciesNameDetail.vue';
import ApiV1BusinessesSpeciesNameEdit from './ApiV1BusinessesSpeciesNameEdit.vue';
import QueryForm from '/@/components/dynamicpage/queryForm/index.vue';
import ProTable from '/@/components/dynamicpage/ProTable/index.vue';
import { QueryFormField, TableColumn } from '/@/components/dynamicpage/type';
import { getUserList } from '/@/api/system/user/index';
import { UserItem } from '/@/types';
import { parseTime } from '/@/utils/gfast';
defineOptions({ name: 'apiV1DemoSpeciesNameList' });
const { proxy } = <any>getCurrentInstance();
const loading = ref(false);
const editRef = ref();
const detailRef = ref();
//
const single = ref(true);
//
const multiple = ref(true);
const userOptions = ref<UserItem[]>([]);
const onSearch = async (val: Record<string, any>) => {
console.log('搜索参数', val);
state.tableData.param = { ...state.tableData.param, ...val };
speciesNameList();
};
const onReset = () => {
state.tableData.param = {
pageNum: 1,
pageSize: 10,
id: undefined,
speciesCode: undefined,
name: undefined,
content: undefined,
sourcesData: undefined,
createUser: undefined,
createDate: undefined,
auditUser: undefined,
auditDate: undefined,
dateRange: [],
};
speciesNameList();
};
const searchForm = ref<Omit<SpeciesNameInfoData, 'id' | 'remark' | 'content'>>({
speciesCode: undefined,
name: undefined,
sourcesData: undefined,
createUser: undefined,
createDate: undefined,
auditUser: undefined,
auditDate: undefined,
});
const searchFields = computed<QueryFormField[]>(() => [
{ label: '物种编码', prop: 'speciesCode', type: 'input', placeholder: '请输入物种编码' },
{ label: '物种名称', prop: 'name', type: 'input', placeholder: '请输入物种名称' },
{ label: '数据来源', prop: 'sourcesData', type: 'input', placeholder: '请输入数据来源' },
{
label: '数据采集人',
prop: 'createUser',
type: 'select',
options: userOptions.value.map((i) => {
return {
label: i.userNickname,
value: i.id,
};
}),
placeholder: '请选择数据采集人',
},
{ label: '数据采集日期', prop: 'createDate', type: 'daterange', valueFormat: 'YYYY-MM-DD' },
{
label: '数据核查人',
prop: 'auditUser',
type: 'select',
options: userOptions.value.map((i) => {
return {
label: i.userNickname,
value: i.id,
};
}),
placeholder: '请选择数据核查人',
},
{ label: '数据核查日期', prop: 'auditDate', type: 'daterange', valueFormat: 'YYYY-MM-DD' },
]);
const state = reactive<SpeciesNameTableDataState>({
ids: [],
tableData: {
data: [],
total: 0,
loading: false,
param: {
pageNum: 1,
pageSize: 10,
id: undefined,
speciesCode: undefined,
name: undefined,
content: undefined,
sourcesData: undefined,
createUser: undefined,
createDate: undefined,
auditUser: undefined,
auditDate: undefined,
dateRange: [],
},
},
});
const { tableData } = toRefs(state);
const columns: TableColumn[] = [
{ label: '物种编码', prop: 'speciesCode' },
{ label: '物种名称', prop: 'name' },
{ label: '物种名称内容', prop: 'content' },
{ label: '数据来源', prop: 'sourcesData' },
{ label: '数据采集人', prop: 'createUser' },
{ label: '数据采集日期', prop: 'createDate',isFormater:true,formater(row,col){
console.log(row,col);
return parseTime(row.createDate,'{y}-{m}-{d}')
} },
{ label: '数据核查人', prop: 'auditUser' },
{ label: '数据核查日期', prop: 'auditDate' },
{ label: '备注', prop: 'remark' },
];
const proTableRef = ref();
//
onMounted(() => {
initTableData();
});
//
const initTableData = () => {
speciesNameList();
reqGetUserList();
};
//
const speciesNameList = async () => {
loading.value = true;
const res = await listSpeciesName(state.tableData.param);
let list = res.data.list ?? [];
state.tableData.data = list;
state.tableData.total = res.data.total;
loading.value = false;
};
const reqGetUserList = async () => {
if (userOptions.value.length > 0) return;
const res = await getUserList({ pageSize: 9999, pageNum: 1 });
userOptions.value = res.data.userList;
};
//
const handleSelectionChange = (selection: Array<SpeciesNameInfoData>) => {
state.ids = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
const handleAdd = () => {
editRef.value.openDialog();
};
const handleUpdate = (row: SpeciesNameTableColumns | null) => {
if (!row) {
row = state.tableData.data.find((item: SpeciesNameTableColumns) => {
return item.id === state.ids[0];
}) as SpeciesNameTableColumns;
}
editRef.value.openDialog(toRaw(row));
};
const handleDelete = (row: SpeciesNameTableColumns | null) => {
let msg = '你确定要删除所选数据?';
let id: number[] = [];
if (row) {
msg = `此操作将永久删除数据,是否继续?`;
id = [row.id];
} else {
id = state.ids;
}
if (id.length === 0) {
ElMessage.error('请选择要删除的数据。');
return;
}
ElMessageBox.confirm(msg, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
delSpeciesName(id).then(() => {
ElMessage.success('删除成功');
speciesNameList();
});
})
.catch(() => {});
};
</script>

View File

@ -0,0 +1,55 @@
export interface SpeciesNameTableColumns {
id: number; // 主键
speciesCode: string; // 物种编号
name: string; // 物种名称
content: string; // 物种名称内容
sourcesData: string; // 数据来源
createUser: number; // 数据采集人
createDate: string; // 数据采集信息
auditUser: number; // 数据核查人
auditDate: string; // 数据核查日期
remark: string; // 备注
}
export interface SpeciesNameInfoData {
id: number | undefined; // 主键
speciesCode: string | undefined; // 物种编号
name: string | undefined; // 物种名称
content: string | undefined; // 物种名称内容
sourcesData: string | undefined; // 数据来源
createUser: number | undefined; // 数据采集人
createDate: string | undefined; // 数据采集信息
auditUser: number | undefined; // 数据核查人
auditDate: string | undefined; // 数据核查日期
remark: string | undefined; // 备注
}
export interface SpeciesNameTableDataState {
ids: any[];
tableData: {
data: Array<SpeciesNameTableColumns>;
total: number;
loading: boolean;
param: {
pageNum: number;
pageSize: number;
id: number | undefined;
speciesCode: string | undefined;
name: string | undefined;
content: string | undefined;
sourcesData: string | undefined;
createUser: number | undefined;
createDate: string | undefined;
auditUser: number | undefined;
auditDate: string | undefined;
dateRange: string[];
};
};
}
export interface SpeciesNameEditState {
loading: boolean;
isShowDialog: boolean;
formData: SpeciesNameInfoData;
rules: object;
}

View File

@ -1,16 +0,0 @@
import {defineComponent,h} from "vue";
export default defineComponent({
name:"baiduMap",
props:{
src:{
type:String,
default:'',
}
},
setup(prop){
return ()=>{
return h('script',{src:prop.src,type:'text/javascript'})
}
},
})

View File

@ -117,7 +117,7 @@ const state = reactive({
isShowPassword: false,
ruleForm: {
username: 'demo',
password: '123456',
password: 'Demo123',
verifyCode: '',
verifyKey:''
},

View File

@ -6,7 +6,7 @@
</template>
<script setup lang="ts">
import { ref, defineComponent, onMounted } from 'vue';
import { ref, onMounted } from 'vue';
import QRCode from 'qrcodejs2-fixes';
defineOptions({ name: "loginScan"})
const qrcodeRef = ref<HTMLElement | null>(null);

View File

@ -14,24 +14,11 @@
<el-tab-pane :label="$t('message.label.one1')" name="account">
<Account />
</el-tab-pane>
<el-tab-pane :label="$t('message.label.two2')" name="mobile">
<!-- <el-tab-pane :label="$t('message.label.two2')" name="mobile">
<Mobile />
</el-tab-pane>
</el-tab-pane> -->
</el-tabs>
</div>
<Scan v-if="isScan" />
<div class="login-content-main-sacn" @click="isScan = !isScan">
<i class="iconfont" :class="isScan ? 'icon-diannao1' : 'icon-barcode-qr'"></i>
<div class="login-content-main-sacn-delta"></div>
</div>
</div>
</div>
</div>
<div class="login-footer">
<div class="login-footer-content mt15">
<div class="login-footer-content-warp">
<div>Copyright © 2021-2023 g-fast.cn All Rights Reserved.</div>
<div class="mt5">云南奇讯科技有限公司版权所有</div>
</div>
</div>
</div>
@ -39,15 +26,12 @@
</template>
<script setup lang="ts">
import { toRefs, reactive, computed, defineComponent, onMounted } from 'vue';
import { toRefs, reactive, computed, onMounted } from 'vue';
import { storeToRefs } from 'pinia';
import { useThemeConfig } from '/@/stores/themeConfig';
import logoMini from '/@/assets/logo-mini.svg';
import loginIconTwo from '/@/assets/login-icon-two.svg';
import { NextLoading } from '/@/utils/loading';
import Account from '/@/views/login/component/account.vue';
import Mobile from '/@/views/login/component/mobile.vue';
import Scan from '/@/views/login/component/scan.vue';
//
interface LoginState {

View File

@ -1,164 +0,0 @@
<template>
<div class="notice-bar-container">
<el-card shadow="hover" header="滚动通知栏:默认">
<NoticeBar
text="🎉🎉🔥基于vue3.x TypescriptviteElement plus等适配手机平板pc
的后台开源免费模板库vue2.x请切换vue-prev-admin分支仓库地址https://gitee.com/lyt-top/vue-next-admin"
/>
</el-card>
<el-card shadow="hover" header="滚动通知栏:设置样式" class="mt15">
<NoticeBar
text="🎉🎉🔥基于vue3.x TypescriptviteElement plus等适配手机平板pc
的后台开源免费模板库vue2.x请切换vue-prev-admin分支仓库地址https://gitee.com/lyt-top/vue-next-admin"
leftIcon="iconfont icon-tongzhi2"
rightIcon="ele-ArrowRight"
background="#ecf5ff"
color="#409eff"
/>
</el-card>
<el-card shadow="hover" header="滚动通知栏:搭配 NoticeBar 和 Carousel 走马灯 组件可以实现垂直滚动的效果" class="mt15">
<NoticeBar :scrollable="true">
<el-carousel height="40px" direction="vertical" :autoplay="true" indicator-position="none" :interval="3000">
<el-carousel-item v-for="v in noticeList" :key="v">{{ v }} </el-carousel-item>
</el-carousel>
</NoticeBar>
</el-card>
<el-card shadow="hover" header="滚动通知栏:参数" class="mt15">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="a1" label="参数"> </el-table-column>
<el-table-column prop="a2" label="说明"> </el-table-column>
<el-table-column prop="a3" label="类型"> </el-table-column>
<el-table-column prop="a4" label="可选值"> </el-table-column>
<el-table-column prop="a5" label="默认值"> </el-table-column>
</el-table>
</el-card>
<el-card shadow="hover" header="图标选择器(宽度自动):事件" class="mt15">
<el-table :data="tableData1" style="width: 100%">
<el-table-column prop="a1" label="事件名称"> </el-table-column>
<el-table-column prop="a2" label="说明"> </el-table-column>
<el-table-column prop="a3" label="类型"> </el-table-column>
<el-table-column prop="a4" label="回调参数"> </el-table-column>
</el-table>
</el-card>
</div>
</template>
<script lang="ts">
import { toRefs, reactive, defineComponent } from 'vue';
import NoticeBar from '/@/components/noticeBar/index.vue';
export default defineComponent({
name: 'makeNoticeBar',
components: { NoticeBar },
setup() {
const state = reactive({
noticeList: [
'🎉🎉🔥基于vue3.x 、Typescript、vite、Element plus等',
'适配手机、平板、pc的后台开源免费模板库vue2.x请切换vue-prev-admin分支',
'仓库地址https://gitee.com/lyt-top/vue-next-admin',
'演示地址https://lyt-top.gitee.io/vue-next-admin-preview/#/login',
],
tableData: [
{
a1: 'mode',
a2: '通知栏模式,用于右侧 icon 图标点击',
a3: 'string',
a4: 'closeable / link',
a5: '',
},
{
a1: 'text',
a2: '通知文本内容scrollable 为 false 时生效',
a3: 'string',
a4: '',
a5: '',
},
{
a1: 'color',
a2: '通知文本颜色',
a3: 'string',
a4: '',
a5: '#e6a23c',
},
{
a1: 'background',
a2: '通知背景色',
a3: 'string',
a4: '',
a5: '#fdf6ec',
},
{
a1: 'size',
a2: '字体大小单位px',
a3: 'number / string',
a4: '',
a5: '14',
},
{
a1: 'height',
a2: '通知栏高度单位px',
a3: 'number / string',
a4: '',
a5: '40',
},
{
a1: 'delay',
a2: '动画延迟时间 (s)',
a3: 'number / string',
a4: '',
a5: '1',
},
{
a1: 'speed',
a2: '滚动速率 (px/s)',
a3: 'number / string',
a4: '',
a5: '100',
},
{
a1: 'scrollable',
a2: '是否开启垂直滚动',
a3: 'boolean',
a4: 'true',
a5: 'false',
},
{
a1: 'leftIcon',
a2: '自定义左侧图标',
a3: 'string',
a4: '',
a5: '',
},
{
a1: 'rightIcon',
a2: '自定义右侧图标',
a3: 'string',
a4: '',
a5: '',
},
],
tableData1: [
{
a1: 'close',
a2: '通知栏模式modecloseable 时回调事件',
a3: 'function',
a4: '',
},
{
a1: 'link',
a2: '通知栏模式modelink 时回调事件',
a3: 'function',
a4: '',
},
],
});
return {
...toRefs(state),
};
},
});
</script>

View File

@ -1,126 +0,0 @@
<template>
<div class="selector-container">
<el-card shadow="hover" header="图标选择器(宽度自动)">
<IconSelector @get="onGetIcon" @clear="onClearIcon" v-model="modelIcon" />
</el-card>
<el-card shadow="hover" header="图标选择器(宽度自动):参数" class="mt15">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="a1" label="参数"> </el-table-column>
<el-table-column prop="a2" label="说明"> </el-table-column>
<el-table-column prop="a3" label="类型"> </el-table-column>
<el-table-column prop="a4" label="可选值"> </el-table-column>
<el-table-column prop="a5" label="默认值"> </el-table-column>
</el-table>
</el-card>
<el-card shadow="hover" header="图标选择器(宽度自动):事件" class="mt15">
<el-table :data="tableData1" style="width: 100%">
<el-table-column prop="a1" label="事件名称"> </el-table-column>
<el-table-column prop="a2" label="说明"> </el-table-column>
<el-table-column prop="a3" label="类型"> </el-table-column>
<el-table-column prop="a4" label="回调参数"> </el-table-column>
</el-table>
</el-card>
</div>
</template>
<script lang="ts">
import { toRefs, reactive, defineComponent } from 'vue';
import IconSelector from '/@/components/iconSelector/index.vue';
export default defineComponent({
name: 'makeSelector',
components: { IconSelector },
setup() {
const state = reactive({
modelIcon: '',
tableData: [
{
a1: 'prepend',
a2: '输入框前置内容,只能字体图标',
a3: 'string',
a4: '',
a5: 'ele-Pointer',
},
{
a1: 'placeholder',
a2: '输入框占位文本',
a3: 'string',
a4: '',
a5: '请输入内容搜索图标或者选择图标',
},
{
a1: 'size',
a2: '尺寸',
a3: 'string',
a4: 'large / default / small',
a5: 'default',
},
{
a1: 'title',
a2: '弹窗标题',
a3: 'string',
a4: '',
a5: '请选择图标',
},
{
a1: 'type',
a2: 'icon 图标类型',
a3: 'string',
a4: 'ali / ele / awe / all',
a5: 'ele',
},
{
a1: 'disabled',
a2: '禁用',
a3: 'boolean',
a4: 'true',
a5: 'false',
},
{
a1: 'clearable',
a2: '是否可清空',
a3: 'boolean',
a4: 'false',
a5: 'true',
},
{
a1: 'emptyDescription',
a2: '自定义空状态描述文字',
a3: 'String',
a4: '',
a5: '无相关图标',
},
],
tableData1: [
{
a1: 'get',
a2: '获取当前点击的 icon 图标',
a3: 'function',
a4: '(icon: string)',
},
{
a1: 'clear',
a2: '清空当前点击的 icon 图标',
a3: 'function',
a4: '(icon: string)',
},
],
});
// icon
const onGetIcon = (icon: string) => {
console.log(icon);
};
// icon
const onClearIcon = (icon: string) => {
console.log(icon);
};
return {
onGetIcon,
onClearIcon,
...toRefs(state),
};
},
});
</script>

View File

@ -1,59 +0,0 @@
<template>
<div class="svg-demo-container">
<el-card shadow="hover" header="svgIcon演示支持本地svg">
<SvgIcon name="iconfont icon-shuju1" color="red" :size="30" />
<SvgIcon name="ele-Trophy" color="var(--el-color-primary)" :size="30" />
<SvgIcon name="fa fa-flag-checkered" color="#09f" :size="30" />
<SvgIcon :name="logoMini" color="#09f" :size="30" />
</el-card>
<el-card shadow="hover" header="svgIcon参数" class="mt15">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="a1" label="参数"> </el-table-column>
<el-table-column prop="a2" label="说明"> </el-table-column>
<el-table-column prop="a3" label="类型"> </el-table-column>
<el-table-column prop="a4" label="可选值"> </el-table-column>
<el-table-column prop="a5" label="默认值"> </el-table-column>
</el-table>
</el-card>
</div>
</template>
<script lang="ts">
import { toRefs, reactive, defineComponent } from 'vue';
import logoMini from '/@/assets/logo-mini.svg';
export default defineComponent({
name: 'makeSvgDemo',
setup() {
const state = reactive({
tableData: [
{
a1: 'name',
a2: 'svg 图标组件名字 / svg 路径 url',
a3: 'string',
a4: '',
a5: '',
},
{
a1: 'size',
a2: 'svg 大小',
a3: 'number',
a4: '',
a5: 14,
},
{
a1: 'color',
a2: 'svg 颜色',
a3: 'string',
a4: '',
a5: '',
},
],
});
return {
logoMini,
...toRefs(state),
};
},
});
</script>

View File

@ -1,127 +0,0 @@
<template>
<div>
<el-card>
<el-alert type="error" title="消息队列测试先生产一条消息再订阅先订阅不存在的topic会失败" :closable="false"></el-alert>
<el-row :gutter="20" style="margin-top: 20px;">
<el-col :span="10">
<div class="my-title">生产者</div>
<el-form :label-width="80">
<el-form-item label="topic">
<el-input v-model="demoForm.topic" />
</el-form-item>
<el-form-item label="topic">
<el-input v-model="demoForm.body" type="textarea" :rows="6" />
</el-form-item>
<el-form-item>
<el-button type="primary" size="default" @click="handleProduce">生产消息</el-button>
</el-form-item>
</el-form>
</el-col>
<el-col :span="14">
<div class="my-title">消费者</div>
<el-form :label-width="80">
<el-form-item label="topic">
<el-input v-model="demoForm.topic" :disabled="wsReady" />
</el-form-item>
<el-form-item label="channel">
<el-input v-model="demoForm.channel" :disabled="wsReady" />
</el-form-item>
<el-form-item>
<el-button size="default" type="primary" @click="handleStartSubscribe" :disabled="wsReady">订阅消费</el-button>
<el-button size="default" type="primary" @click="handleUnSubscribe" :disabled="!wsReady">取消订阅</el-button>
</el-form-item>
<el-form-item label="消费结果">
<el-input :model-value="messageResult" type="textarea" :rows="12"></el-input>
</el-form-item>
</el-form>
</el-col>
</el-row>
</el-card>
</div>
</template>
<script setup lang="ts">
import {reactive, ref} from "vue";
import {ElMessageBox} from "element-plus";
import request from "/@/utils/request";
const demoForm = reactive({
topic: "producer_topic_test",
body: "测试消息队列内容",
channel: "channel1"
})
const consumerForm = reactive({
topic:"producer_topic_test",
channel:"channel1"
})
function handleProduce(){
request({
url: '/api/v1/mqueue/demo/produce',
method: 'post',
data: {topic:demoForm.topic,body:demoForm.body}
}).then((res:any)=>{
window.console.log(res)
})
}
const webSocketURL = import.meta.env.VITE_WEBSOCKET_URL
const messageResult = ref("")
let ws:WebSocket|null = null
const wsReady = ref(false)
function handleStartSubscribe(){
if(ws) return
const url = webSocketURL+"api/v1/mqueue/demo/subscribe?topic="+demoForm.topic+"&channel="+demoForm.channel;
ws = new WebSocket(url);
try {
// ws
ws.onopen = function () {
messageResult.value += "WebSocket Server [" + url +"] 连接成功!\r\n";
wsReady.value = true
};
// ws
ws.onclose = function () {
if (ws) {
ws.close();
ws = null;
wsReady.value = false
}
messageResult.value += "WebSocket Server [" + url +"] 连接被服务器关闭!\r\n";
};
// ws
ws.onerror = function () {
if (ws) {
ws.close();
ws = null;
wsReady.value = false
}
messageResult.value += "WebSocket Server [" + url +"] 连接错误!\r\n";
};
// ws
ws.onmessage = function (result) {
window.console.log(result)
messageResult.value += " > " + result.data+"\r\n";
};
} catch (e:any) {
ElMessageBox.alert(e.message)
}
}
function handleUnSubscribe(){
if(ws) {
ws.close()
ws = null;
wsReady.value = false
messageResult.value += "已手动取消订阅!\r\n";
}
}
</script>
<style scoped lang="scss">
.my-title{
font-size: 16px; font-weight: bold;line-height: 2;
color: #1890ff;
text-align: center;
}
</style>

View File

@ -1,387 +0,0 @@
<template>
<div class="personal">
<el-row>
<!-- 个人信息 -->
<el-col :xs="24" :sm="16">
<el-card shadow="hover" header="个人信息">
<div class="personal-user">
<div class="personal-user-left">
<el-upload class="h100 personal-user-left-upload" action="https://jsonplaceholder.typicode.com/posts/" multiple :limit="1">
<img src="https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500" />
</el-upload>
</div>
<div class="personal-user-right">
<el-row>
<el-col :span="24" class="personal-title mb18">{{ currentTime }}admin生活变的再糟糕也不妨碍我变得更好 </el-col>
<el-col :span="24">
<el-row>
<el-col :xs="24" :sm="8" class="personal-item mb6">
<div class="personal-item-label">昵称</div>
<div class="personal-item-value">小柒</div>
</el-col>
<el-col :xs="24" :sm="16" class="personal-item mb6">
<div class="personal-item-label">身份</div>
<div class="personal-item-value">超级管理</div>
</el-col>
</el-row>
</el-col>
<el-col :span="24">
<el-row>
<el-col :xs="24" :sm="8" class="personal-item mb6">
<div class="personal-item-label">登录IP</div>
<div class="personal-item-value">192.168.1.1</div>
</el-col>
<el-col :xs="24" :sm="16" class="personal-item mb6">
<div class="personal-item-label">登录时间</div>
<div class="personal-item-value">2021-02-05 18:47:26</div>
</el-col>
</el-row>
</el-col>
</el-row>
</div>
</div>
</el-card>
</el-col>
<!-- 消息通知 -->
<el-col :xs="24" :sm="8" class="pl15 personal-info">
<el-card shadow="hover">
<template #header>
<span>消息通知</span>
<span class="personal-info-more">更多</span>
</template>
<div class="personal-info-box">
<ul class="personal-info-ul">
<li v-for="(v, k) in newsInfoList" :key="k" class="personal-info-li">
<a :href="v.link" target="_block" class="personal-info-li-title">{{ v.title }}</a>
</li>
</ul>
</div>
</el-card>
</el-col>
<!-- 营销推荐 -->
<el-col :span="24">
<el-card shadow="hover" class="mt15" header="营销推荐">
<el-row :gutter="15" class="personal-recommend-row">
<el-col :sm="6" v-for="(v, k) in recommendList" :key="k" class="personal-recommend-col">
<div class="personal-recommend" :style="{ 'background-color': v.bg }">
<SvgIcon :name="v.icon" :size="70" :style="{ color: v.iconColor }" />
<div class="personal-recommend-auto">
<div>{{ v.title }}</div>
<div class="personal-recommend-msg">{{ v.msg }}</div>
</div>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
<!-- 更新信息 -->
<el-col :span="24">
<el-card shadow="hover" class="mt15 personal-edit" header="更新信息">
<div class="personal-edit-title">基本信息</div>
<el-form :model="personalForm" size="default" label-width="40px" class="mt35 mb35">
<el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="昵称">
<el-input v-model="personalForm.name" placeholder="请输入昵称" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="邮箱">
<el-input v-model="personalForm.email" placeholder="请输入邮箱" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="签名">
<el-input v-model="personalForm.autograph" placeholder="请输入签名" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="职业">
<el-select v-model="personalForm.occupation" placeholder="请选择职业" clearable class="w100">
<el-option label="计算机 / 互联网 / 通信" value="1"></el-option>
<el-option label="生产 / 工艺 / 制造" value="2"></el-option>
<el-option label="医疗 / 护理 / 制药" value="3"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="手机">
<el-input v-model="personalForm.phone" placeholder="请输入手机" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="性别">
<el-select v-model="personalForm.sex" placeholder="请选择性别" clearable class="w100">
<el-option label="男" value="1"></el-option>
<el-option label="女" value="2"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
<el-form-item>
<el-button type="primary">
<el-icon>
<ele-Position />
</el-icon>
更新个人信息
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="personal-edit-title mb15">账号安全</div>
<div class="personal-edit-safe-box">
<div class="personal-edit-safe-item">
<div class="personal-edit-safe-item-left">
<div class="personal-edit-safe-item-left-label">账户密码</div>
<div class="personal-edit-safe-item-left-value">当前密码强度</div>
</div>
<div class="personal-edit-safe-item-right">
<el-button text type="primary">立即修改</el-button>
</div>
</div>
</div>
<div class="personal-edit-safe-box">
<div class="personal-edit-safe-item">
<div class="personal-edit-safe-item-left">
<div class="personal-edit-safe-item-left-label">密保手机</div>
<div class="personal-edit-safe-item-left-value">已绑定手机132****4108</div>
</div>
<div class="personal-edit-safe-item-right">
<el-button text type="primary">立即修改</el-button>
</div>
</div>
</div>
<div class="personal-edit-safe-box">
<div class="personal-edit-safe-item">
<div class="personal-edit-safe-item-left">
<div class="personal-edit-safe-item-left-label">密保问题</div>
<div class="personal-edit-safe-item-left-value">已设置密保问题账号安全大幅度提升</div>
</div>
<div class="personal-edit-safe-item-right">
<el-button text type="primary">立即设置</el-button>
</div>
</div>
</div>
<div class="personal-edit-safe-box">
<div class="personal-edit-safe-item">
<div class="personal-edit-safe-item-left">
<div class="personal-edit-safe-item-left-label">绑定QQ</div>
<div class="personal-edit-safe-item-left-value">已绑定QQ110****566</div>
</div>
<div class="personal-edit-safe-item-right">
<el-button text type="primary">立即设置</el-button>
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script lang="ts">
import { toRefs, reactive, computed, defineComponent } from 'vue';
import { formatAxis } from '/@/utils/formatTime';
import { newsInfoList, recommendList } from './mock';
//
interface PersonalState {
newsInfoList: any;
recommendList: any;
personalForm: any;
}
export default defineComponent({
name: 'personal',
setup() {
const state = reactive<PersonalState>({
newsInfoList,
recommendList,
personalForm: {
name: '',
email: '',
autograph: '',
occupation: '',
phone: '',
sex: '',
},
});
//
const currentTime = computed(() => {
return formatAxis(new Date());
});
return {
currentTime,
...toRefs(state),
};
},
});
</script>
<style scoped lang="scss">
@use '../../theme/mixins/index.scss' as *;
.personal {
.personal-user {
height: 130px;
display: flex;
align-items: center;
.personal-user-left {
width: 100px;
height: 130px;
border-radius: 3px;
:deep(.el-upload) {
height: 100%;
}
.personal-user-left-upload {
img {
width: 100%;
height: 100%;
border-radius: 3px;
}
&:hover {
img {
animation: logoAnimation 0.3s ease-in-out;
}
}
}
}
.personal-user-right {
flex: 1;
padding: 0 15px;
.personal-title {
font-size: 18px;
@include text-ellipsis(1);
}
.personal-item {
display: flex;
align-items: center;
font-size: 13px;
.personal-item-label {
color: var(--el-text-color-secondary);
@include text-ellipsis(1);
}
.personal-item-value {
@include text-ellipsis(1);
}
}
}
}
.personal-info {
.personal-info-more {
float: right;
color: var(--el-text-color-secondary);
font-size: 13px;
&:hover {
color: var(--el-color-primary);
cursor: pointer;
}
}
.personal-info-box {
height: 130px;
overflow: hidden;
.personal-info-ul {
list-style: none;
.personal-info-li {
font-size: 13px;
padding-bottom: 10px;
.personal-info-li-title {
display: inline-block;
@include text-ellipsis(1);
color: var(--el-text-color-secondary);
text-decoration: none;
}
& a:hover {
color: var(--el-color-primary);
cursor: pointer;
}
}
}
}
}
.personal-recommend-row {
.personal-recommend-col {
.personal-recommend {
position: relative;
height: 100px;
border-radius: 3px;
overflow: hidden;
cursor: pointer;
&:hover {
i {
right: 0px !important;
bottom: 0px !important;
transition: all ease 0.3s;
}
}
i {
position: absolute;
right: -10px;
bottom: -10px;
font-size: 70px;
transform: rotate(-30deg);
transition: all ease 0.3s;
}
.personal-recommend-auto {
padding: 15px;
position: absolute;
left: 0;
top: 5%;
color: var(--next-color-white);
.personal-recommend-msg {
font-size: 12px;
margin-top: 10px;
}
}
}
}
}
.personal-edit {
.personal-edit-title {
position: relative;
padding-left: 10px;
color: var(--el-text-color-regular);
&::after {
content: '';
width: 2px;
height: 10px;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
background: var(--el-color-primary);
}
}
.personal-edit-safe-box {
border-bottom: 1px solid var(--el-border-color-light, #ebeef5);
padding: 15px 0;
.personal-edit-safe-item {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.personal-edit-safe-item-left {
flex: 1;
overflow: hidden;
.personal-edit-safe-item-left-label {
color: var(--el-text-color-regular);
margin-bottom: 5px;
}
.personal-edit-safe-item-left-value {
color: var(--el-text-color-secondary);
@include text-ellipsis(1);
margin-right: 15px;
}
}
}
&:last-of-type {
padding-bottom: 0;
border-bottom: none;
}
}
}
}
</style>

View File

@ -1,66 +0,0 @@
/**
*
* @returns
*/
export const newsInfoList: Array<object> = [
{
title: '[发布] 2021年02月28日发布基于 vue3.x + vite v1.0.0 版本',
date: '02/28',
link: 'https://gitee.com/lyt-top/vue-next-admin',
},
{
title: '[发布] 2021年04月15日发布 vue2.x + webpack 重构版本',
date: '04/15',
link: 'https://gitee.com/lyt-top/vue-next-admin/tree/vue-prev-admin/',
},
{
title: '[重构] 2021年04月10日 重构 vue2.x + webpack v1.0.0 版本',
date: '04/10',
link: 'https://gitee.com/lyt-top/vue-next-admin/tree/vue-prev-admin/',
},
{
title: '[预览] 2020年12月08日基于 vue3.x 版本后台模板的预览',
date: '12/08',
link: 'http://lyt-top.gitee.io/vue-next-admin-preview/#/login',
},
{
title: '[预览] 2020年11月15日基于 vue2.x 版本后台模板的预览',
date: '11/15',
link: 'https://lyt-top.gitee.io/vue-prev-admin-preview/#/login',
},
];
/**
*
* @returns
*/
export const recommendList: Array<object> = [
{
title: '优惠券',
msg: '现金券、折扣券、营销必备',
icon: 'ele-Food',
bg: '#48D18D',
iconColor: '#64d89d',
},
{
title: '多人拼团',
msg: '社交电商、开辟流量',
icon: 'ele-ShoppingCart',
bg: '#F95959',
iconColor: '#F86C6B',
},
{
title: '分销中心',
msg: '轻松招募分销员,成功推广奖励',
icon: 'ele-School',
bg: '#8595F4',
iconColor: '#92A1F4',
},
{
title: '秒杀',
msg: '超低价抢购引导更多销量',
icon: 'ele-AlarmClock',
bg: '#FEBB50',
iconColor: '#FDC566',
},
];

View File

@ -2,7 +2,7 @@
<div class="personal">
<el-row>
<!-- 个人信息 -->
<el-col :xs="24" :sm="16">
<el-col :xs="24" :sm="24">
<el-card shadow="hover" header="个人信息">
<div class="personal-user">
<div class="personal-user-left">
@ -64,7 +64,7 @@
</el-col>
<!-- 消息通知 -->
<el-col :xs="24" :sm="8" class="pl15 personal-info">
<!-- <el-col :xs="24" :sm="8" class="pl15 personal-info">
<el-card shadow="hover">
<template #header>
<span>消息通知</span>
@ -78,10 +78,10 @@
</ul>
</div>
</el-card>
</el-col>
</el-col> -->
<!-- 营销推荐 -->
<el-col :span="24">
<!-- <el-col :span="24">
<el-card shadow="hover" class="mt15" header="营销推荐">
<el-row :gutter="15" class="personal-recommend-row">
<el-col :sm="6" v-for="(v, k) in recommendList" :key="k" class="personal-recommend-col">
@ -95,7 +95,7 @@
</el-col>
</el-row>
</el-card>
</el-col>
</el-col> -->
<!-- 更新信息 -->
<el-col :span="24">
@ -164,39 +164,6 @@
</div>
</div>
</div>
<div class="personal-edit-safe-box">
<div class="personal-edit-safe-item">
<div class="personal-edit-safe-item-left">
<div class="personal-edit-safe-item-left-label">密保手机</div>
<div class="personal-edit-safe-item-left-value">已绑定手机132****4108</div>
</div>
<div class="personal-edit-safe-item-right">
<el-button text type="primary">立即修改</el-button>
</div>
</div>
</div>
<div class="personal-edit-safe-box">
<div class="personal-edit-safe-item">
<div class="personal-edit-safe-item-left">
<div class="personal-edit-safe-item-left-label">密保问题</div>
<div class="personal-edit-safe-item-left-value">已设置密保问题账号安全大幅度提升</div>
</div>
<div class="personal-edit-safe-item-right">
<el-button text type="primary">立即设置</el-button>
</div>
</div>
</div>
<div class="personal-edit-safe-box">
<div class="personal-edit-safe-item">
<div class="personal-edit-safe-item-left">
<div class="personal-edit-safe-item-left-label">绑定QQ</div>
<div class="personal-edit-safe-item-left-value">已绑定QQ110****566</div>
</div>
<div class="personal-edit-safe-item-right">
<el-button text type="primary">立即设置</el-button>
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 607 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 783 KiB

View File

@ -1,51 +0,0 @@
// 地图模拟数据
export const echartsMapList: Array<object> = [
{ name: '深圳市人民政府', value: '100' },
{ name: '莲花山公园', value: '100' },
{ name: '世界之窗', value: '100' },
{ name: '华侨城欢乐谷', value: '100' },
{ name: '宝安区西乡', value: '100' },
];
// 地图经纬度数据
export const echartsMapData: object = {
: [114.064524, 22.549225],
: [114.0658, 22.560072],
: [113.979419, 22.540579],
: [113.986066, 22.548056],
西: [113.869053, 22.581714],
};
// 地图图片显示
export const echartsMapImgs: Array<object> = [
{
url: 'https://img1.baidu.com/it/u=4244861097,3561366422&fm=11&fmt=auto&gp=0.jpg',
name: '深圳市人民政府',
add: '深圳市福田区福中三路市民中心C区',
dec: '深圳市人民政府是根据《中华人民共和国地方各级人民代表大会和地方各级人民政府组织法》设立的,是深圳市人民代表大会的执行机关,是深圳市的国家行政机关。',
},
{
url: 'https://img1.baidu.com/it/u=3793608028,4006842751&fm=26&fmt=auto&gp=0.jpg',
name: '莲花山公园',
add: '广东省深圳市福田区莲花街道莲花北社区红荔路6030号',
dec: '莲花山公园筹建于1992年10月10日 1997年6月23日正式对外局部开放。',
},
{
url: 'https://img0.baidu.com/it/u=1406340112,1927292660&fm=26&fmt=auto&gp=0.jpg',
name: '世界之窗',
add: '深圳市南山区深南大道9037号',
dec: '这里,世界首座实景拍摄悬空式球幕影院“飞跃美利坚””,为游客提供集休闲放松于一体的都市时尚生活空间。',
},
{
url: 'https://img0.baidu.com/it/u=3042342330,902556630&fm=26&fmt=auto&gp=0.jpg',
name: '华侨城欢乐谷',
add: '广东省深圳市南山区沙河街道星河街社区侨城西街1号',
dec: '深圳欢乐谷注重满足人们参与、体验的新型诱游需求,营造出自然、清新、活泼、惊奇、热烈、刺激的休闲旅游氛围。',
},
{
url: 'https://img2.baidu.com/it/u=1075072079,1229283519&fm=11&fmt=auto&gp=0.jpg',
name: '宝安区西乡',
add: '西乡街道下辖25个社区',
dec: '西乡街道,隶属于广东省深圳市宝安区,位于宝安区西南部,东接石岩街道,南接新安街道,西至珠江口岸边,北接航城街道。',
},
];

View File

@ -1,131 +0,0 @@
// 顶部下来菜单
export const dropdownList: Array<object> = [
{
label: '广东省农业农村厅',
},
{
label: '广西省农业农村厅',
},
{
label: '四川省农业农村厅',
},
{
label: '湖北省农业农村厅',
},
{
label: '福建省农业农村厅',
},
{
label: '山东省农业农村厅',
},
{
label: '江西省农业农村厅',
},
];
// sky 天气
export const skyList: Array<object> = [
{
v1: '时间',
v2: '天气',
v3: '温度',
v4: '湿度',
v5: '降水概率',
v6: '风向',
v7: '风力',
type: 'title',
},
{
v1: '今天',
v2: 'ele-Sunny',
v3: '20°/26°',
v4: '80%',
v5: '50%',
v6: '东南风',
v7: '13m/s',
},
{
v1: '明天',
v2: 'ele-Lightning',
v3: '20°/26°',
v4: '80%',
v5: '50%',
v6: '东南风',
v7: '13m/s',
},
{
v1: '后天',
v2: 'ele-Sunny',
v3: '20°/26°',
v4: '80%',
v5: '50%',
v6: '东南风',
v7: '13m/s',
},
];
// 当前设置状态
export const dBtnList: Array<object> = [
{
v1: '地块A-灌溉',
v2: '阳光玫瑰种植',
v3: '126天',
v4: '设备在线',
},
{
v1: '地块B-收割',
v2: '阳光玫瑰种植',
v3: '360天',
v4: '设备预警',
},
];
// 当前设备监测
export const chartData4List: Array<object> = [
{
label: '温度',
},
{
label: '光照',
},
{
label: '湿度',
},
{
label: '风力',
},
{
label: '张力',
},
{
label: '气压',
},
];
// 3DEarth 地图周围按钮组
export const earth3DBtnList: Array<object> = [
{
topLevelClass: 'fixed-top',
icon: 'ele-MagicStick',
label: '环境监测',
type: 0,
},
{
topLevelClass: 'fixed-right',
icon: 'ele-MoonNight',
label: '精准管理',
type: 1,
},
{
topLevelClass: 'fixed-bottom',
icon: 'ele-TrendCharts',
label: '数据报表',
type: 2,
},
{
topLevelClass: 'fixed-left',
icon: 'ele-Van',
label: '产品追溯',
type: 3,
},
];

View File

@ -69,6 +69,6 @@
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"include": ["src/**/*.ts", "src/**/*.vue", "src/**/*.tsx", "src/**/*.d.ts"], // **Represents any directory, and * represents any file. Indicates that all files in the src directory will be compiled
"include": ["src/**/*.ts", "src/**/*.vue", "src/**/*.tsx", "src/**/*.d.ts", "shim.d.ts"], // **Represents any directory, and * represents any file. Indicates that all files in the src directory will be compiled
"exclude": ["node_modules", "dist"] // Indicates the file directory that does not need to be compiled
}