Compare commits
10 Commits
8addeaf491
...
a5a74a2ead
Author | SHA1 | Date | |
---|---|---|---|
a5a74a2ead | |||
0f7c42b949 | |||
575c278572 | |||
![]() |
012025080d | ||
![]() |
68648f2a86 | ||
![]() |
9deae50ccc | ||
![]() |
8a38eaa7d6 | ||
![]() |
02d67c7ac3 | ||
![]() |
3a7cf77d7b | ||
![]() |
bb39c4bfd9 |
@ -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',
|
||||
|
@ -1,6 +1,6 @@
|
||||
module.exports = {
|
||||
// 一行最多多少个字符
|
||||
printWidth: 150,
|
||||
printWidth: 100,
|
||||
// 指定每个缩进级别的空格数
|
||||
tabWidth: 2,
|
||||
// 使用制表符而不是空格缩进行
|
||||
|
367
CHANGELOG.md
367
CHANGELOG.md
@ -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
21
LICENSE
@ -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.
|
57
README.md
57
README.md
@ -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> </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 |
|
||||
| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ |
|
||||
|  |  |  |  |
|
||||
|
||||
> 由于 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)
|
3547
package-lock.json
generated
3547
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@ -14,14 +14,15 @@
|
||||
"@codemirror/lang-javascript": "^6.1.1",
|
||||
"@codemirror/theme-one-dark": "^6.1.0",
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "1.7.4",
|
||||
"@vue/reactivity": "^3.5.18",
|
||||
"axios": "1.8.2",
|
||||
"codemirror": "^6.0.1",
|
||||
"countup.js": "^2.8.0",
|
||||
"cropperjs": "^1.6.0",
|
||||
"echarts": "^5.5.0",
|
||||
"echarts-gl": "^2.0.9",
|
||||
"echarts-wordcloud": "^2.1.0",
|
||||
"element-plus": "^2.8.7",
|
||||
"element-plus": "^2.9.0",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jsplumb": "^2.15.6",
|
||||
"lodash": "^4.17.21",
|
||||
@ -40,14 +41,16 @@
|
||||
"vue-codemirror": "^6.1.1",
|
||||
"vue-demi": "^0.14.7",
|
||||
"vue-grid-layout": "^3.0.0-beta1",
|
||||
"vue-i18n": "^9.10.2",
|
||||
"vue-i18n": "11.1.2",
|
||||
"vue-router": "^4.3.0",
|
||||
"vue-simple-uploader": "^1.0.0-beta.5",
|
||||
"vue-ueditor-wrap": "^3.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/node": "^20.11.28",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/qs": "^6.14.0",
|
||||
"@types/sortablejs": "^1.15.8",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
@ -60,8 +63,8 @@
|
||||
"sass": "^1.80.7",
|
||||
"sass-loader": "^16.0.3",
|
||||
"typescript": "^5.4.2",
|
||||
"vite": "5.4.6",
|
||||
"vite-plugin-cdn-import": "^0.3.5",
|
||||
"vite": "6.3.4",
|
||||
"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"
|
||||
|
3524
pnpm-lock.yaml
generated
Normal file
3524
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
4
pnpm-workspace.yaml
Normal file
4
pnpm-workspace.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
onlyBuiltDependencies:
|
||||
- '@parcel/watcher'
|
||||
- esbuild
|
||||
- vue-demi
|
@ -43,10 +43,11 @@ export function deleteType(dictIds:number[]) {
|
||||
|
||||
|
||||
// 获取字典选择框列表
|
||||
export function optionselect() {
|
||||
export function optionselect(all?:boolean) {
|
||||
return request({
|
||||
url: '/api/v1/system/dict/type/optionSelect',
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params:{all}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -88,12 +88,12 @@ export function getJobLogs(req:object){
|
||||
}
|
||||
|
||||
// 删除定时任务日志
|
||||
export function delSysJobLog(logIds:number[]) {
|
||||
export function delSysJobLog(targetName:string) {
|
||||
return request({
|
||||
url: '/api/v1/system/sysJob/deleteLogs',
|
||||
method: 'delete',
|
||||
data:{
|
||||
logIds:logIds
|
||||
targetName
|
||||
}
|
||||
})
|
||||
}
|
||||
|
181
src/components/dynamicpage/ProTable/index.vue
Normal file
181
src/components/dynamicpage/ProTable/index.vue
Normal file
@ -0,0 +1,181 @@
|
||||
<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="showExpand" type="expand" align="center" :width="expandWidth">
|
||||
<template #default="scope">
|
||||
<slot name="expand" v-bind="scope" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 选择框 -->
|
||||
<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="col.formater"
|
||||
/>
|
||||
|
||||
<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"
|
||||
class-name="small-padding"
|
||||
>
|
||||
<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 { 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;
|
||||
showExpand?: boolean; // 新增:是否显示展开行
|
||||
expandWidth?: string | number; // 新增:展开列宽度
|
||||
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,
|
||||
showExpand: false, // 默认不显示展开行
|
||||
expandWidth: 55, // 默认宽度与选择框一致
|
||||
highlightCurrentRow: false,
|
||||
actionWidth: 200,
|
||||
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();
|
||||
|
||||
// 新增:展开行相关方法
|
||||
const toggleRowExpansion = (row: any, expanded?: boolean) =>
|
||||
tableRef.value?.toggleRowExpansion(row, expanded);
|
||||
const setExpandedRows = (rows: any[]) => tableRef.value?.setExpandedRows(rows);
|
||||
|
||||
defineExpose({
|
||||
clearSelection,
|
||||
toggleRowSelection,
|
||||
getSelectionRows,
|
||||
tableRef,
|
||||
toggleRowExpansion, // 暴露展开行方法
|
||||
setExpandedRows, // 暴露设置展开行方法
|
||||
});
|
||||
</script>
|
114
src/components/dynamicpage/auditForm/index.vue
Normal file
114
src/components/dynamicpage/auditForm/index.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<el-dialog :model-value="visible" :title="title" width="30%" @close="handleCancel">
|
||||
<el-form :model="form" ref="formRef" label-width="80px" :rules="rules">
|
||||
<slot>
|
||||
<el-form-item label="审批意见" prop="auditView">
|
||||
<el-input v-model="form.auditView" placeholder="请输入审批意见" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="审核状态" prop="auditStatus">
|
||||
<el-radio v-model="form.auditStatus" label="1" size="large">通过</el-radio>
|
||||
<el-radio v-model="form.auditStatus" label="2" size="large">不通过</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="审核人" prop="auditUser">
|
||||
<el-select v-model="form.auditUser" placeholder="请选择审核人" filterable clearable>
|
||||
<el-option
|
||||
v-for="item in userList"
|
||||
:key="item.id"
|
||||
:label="item.userNickname"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="日期" prop="auditDate">
|
||||
<el-date-picker
|
||||
v-model="form.auditDate"
|
||||
type="date"
|
||||
placeholder="请选择日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</slot>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, defineProps, defineEmits } from 'vue';
|
||||
import type { AuditFormModel } from '../type';
|
||||
import { UserItem, VersionMap } from '/@/types';
|
||||
|
||||
defineOptions({
|
||||
name: 'AuditForm',
|
||||
});
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
title?: string;
|
||||
defaultForm?: Partial<AuditFormModel>;
|
||||
}>();
|
||||
const formRef = ref();
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: boolean): void;
|
||||
(e: 'submit', data: any): void;
|
||||
}>();
|
||||
const rules = ref({
|
||||
auditView: [{ required: true, message: '请输入审批意见', trigger: 'blur' }],
|
||||
auditStatus: [{ required: true, message: '请选择审核状态', trigger: 'change' }],
|
||||
auditUser: [{ required: true, message: '请选择审核人', trigger: 'change' }],
|
||||
auditDate: [{ required: true, message: '请选择日期', trigger: 'change' }],
|
||||
});
|
||||
const visible = ref(props.modelValue);
|
||||
const userList = ref<UserItem[]>([]);
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => (visible.value = val)
|
||||
);
|
||||
watch(visible, (val) => emit('update:modelValue', val));
|
||||
|
||||
const form = ref<AuditFormModel>({
|
||||
id: '',
|
||||
auditView: '',
|
||||
auditStatus: '',
|
||||
auditUser: '',
|
||||
auditDate: '',
|
||||
...(props.defaultForm || {}),
|
||||
});
|
||||
const open = (row: AuditFormModel, userOptions: UserItem[]) => {
|
||||
visible.value = true;
|
||||
row.auditStatus='1'
|
||||
form.value = row;
|
||||
userList.value = userOptions;
|
||||
};
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
const handleSubmit = () => {
|
||||
formRef.value.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
emit('submit', form.value);
|
||||
handleCancel();
|
||||
} else {
|
||||
console.log('error submit!!');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
form.value = {
|
||||
id: '',
|
||||
auditView: '',
|
||||
auditStatus: '',
|
||||
auditUser: '',
|
||||
auditDate: '',
|
||||
};
|
||||
};
|
||||
</script>
|
176
src/components/dynamicpage/modalForm/index.vue
Normal file
176
src/components/dynamicpage/modalForm/index.vue
Normal file
@ -0,0 +1,176 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="localVisible"
|
||||
:title="title"
|
||||
:width="width"
|
||||
:close-on-click-modal="false"
|
||||
@closed="handleCancel"
|
||||
@open="handleOpen"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="modelValue"
|
||||
:rules="rules"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
>
|
||||
<el-row :gutter="gutter">
|
||||
<template v-for="(item, index) in fields" :key="item.prop">
|
||||
<el-col :span="item.span||24">
|
||||
<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)"
|
||||
>
|
||||
<!-- 下拉选项 -->
|
||||
<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>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<template #footer v-if="showFooter">
|
||||
<slot name="footer">
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||
</slot>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from 'vue';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import {PopupFormField} from '../type'
|
||||
|
||||
defineOptions({ name: 'ModalForm' });
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
title?: string;
|
||||
width?: string;
|
||||
modelValue: Record<string, any>;
|
||||
fields: PopupFormField[];
|
||||
labelWidth?: string;
|
||||
labelPosition?: 'left' | 'right' | 'top';
|
||||
gutter?: number;
|
||||
showFooter?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', val: boolean): void;
|
||||
(e: 'update:modelValue', val: Record<string, any>): void;
|
||||
(e: 'submit', val:any): void;
|
||||
(e: 'cancel'): void;
|
||||
(e: 'open'): void;
|
||||
}>();
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const localVisible = ref(props.visible);
|
||||
|
||||
watch(() => props.visible, val => localVisible.value = val);
|
||||
watch(localVisible, val => emit('update:visible', val));
|
||||
|
||||
const labelWidth = computed(() => props.labelWidth || '100px');
|
||||
const labelPosition = computed(() => props.labelPosition || 'right');
|
||||
const gutter = computed(() => props.gutter || 10);
|
||||
const showFooter = computed(() => props.showFooter !== false);
|
||||
|
||||
const rules = computed<FormRules>(() => {
|
||||
const map: FormRules = {};
|
||||
props.fields.forEach(field => {
|
||||
if (field.rules) map[field.prop] = field.rules;
|
||||
});
|
||||
return map;
|
||||
});
|
||||
|
||||
const componentMap: Record<string, any> = {
|
||||
input: 'el-input',
|
||||
select: 'el-select',
|
||||
date: 'el-date-picker',
|
||||
dateTime: 'el-date-picker',
|
||||
daterange: 'el-date-picker',
|
||||
datetimerange: 'el-date-picker',
|
||||
switch: 'el-switch',
|
||||
radio: 'el-radio-group',
|
||||
checkbox: 'el-checkbox-group',
|
||||
upload: 'el-upload',
|
||||
cascader: 'el-cascader',
|
||||
rate: 'el-rate',
|
||||
slider: 'el-slider',
|
||||
timePicker: 'el-time-picker',
|
||||
inputNumber: 'el-input-number',
|
||||
colorPicker: 'el-color-picker',
|
||||
treeSelect: 'el-tree-select',
|
||||
};
|
||||
|
||||
const getComponent = (type?: string) => componentMap[type || 'input'] || 'el-input';
|
||||
|
||||
const getProps = (item: PopupFormField) => {
|
||||
const props = item.componentProps || {};
|
||||
if (item.type === 'select') {
|
||||
return { ...props, filterable: true };
|
||||
}
|
||||
if (item.type === 'daterange' || item.type === 'datetimerange') {
|
||||
return {
|
||||
...props,
|
||||
type: item.type,
|
||||
'value-format': 'YYYY-MM-DD',
|
||||
'range-separator': '至',
|
||||
'start-placeholder': '开始日期',
|
||||
'end-placeholder': '结束日期',
|
||||
};
|
||||
}
|
||||
return props;
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return;
|
||||
await formRef.value.validate((valid) => {
|
||||
if (valid) emit('submit', props.modelValue);
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('cancel');
|
||||
localVisible.value = false;
|
||||
formRef.value?.resetFields();
|
||||
};
|
||||
|
||||
const handleOpen = () => {
|
||||
emit('open');
|
||||
};
|
||||
|
||||
const loadOptions = async () => {
|
||||
const loaded = new Set();
|
||||
for (const field of props.fields) {
|
||||
if (field.fetchOptions && !loaded.has(field.fetchOptions)) {
|
||||
field.options = await field.fetchOptions();
|
||||
loaded.add(field.fetchOptions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(loadOptions);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-item-wrapper {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
199
src/components/dynamicpage/queryForm/index.vue
Normal file
199
src/components/dynamicpage/queryForm/index.vue
Normal 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>
|
51
src/components/dynamicpage/type.ts
Normal file
51
src/components/dynamicpage/type.ts
Normal file
@ -0,0 +1,51 @@
|
||||
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, cellValue: any, index: number) => any;
|
||||
isFormater?: boolean;
|
||||
}
|
||||
export interface PopupFormField {
|
||||
label: string;
|
||||
prop: string;
|
||||
type?: string;
|
||||
rules?: any;
|
||||
span?: number;
|
||||
defaultValue?: any;
|
||||
componentProps?: Record<string, any>;
|
||||
options?: Array<{ value: any; label: any }>;
|
||||
fetchOptions?: () => Promise<Array<{ label: string; value: any }>>;
|
||||
}
|
||||
|
||||
export interface AuditFormModel {
|
||||
auditView: string;
|
||||
auditStatus: string;
|
||||
auditUser: string | number;
|
||||
auditDate: string;
|
||||
id: string | number;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="{'hidden':hidden}" class="pagination-container">
|
||||
<div :class="{ hidden: hidden }" class="pagination-container">
|
||||
<el-pagination
|
||||
:background="background"
|
||||
v-model:current-page="currentPage"
|
||||
@ -15,84 +15,86 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { toRefs, defineComponent,computed } from 'vue';
|
||||
import { toRefs, defineComponent, computed } from 'vue';
|
||||
const props = {
|
||||
total: {
|
||||
required: true,
|
||||
type: Number
|
||||
type: Number,
|
||||
},
|
||||
page: {
|
||||
type: Number,
|
||||
default: 1
|
||||
default: 1,
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 20
|
||||
default: 20,
|
||||
},
|
||||
pageSizes: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [10, 20, 30, 50]
|
||||
}
|
||||
return [10, 20, 30, 50];
|
||||
},
|
||||
},
|
||||
// 移动端页码按钮的数量端默认值5
|
||||
pagerCount: {
|
||||
type: Number,
|
||||
default: document.body.clientWidth < 992 ? 5 : 7
|
||||
default: document.body.clientWidth < 992 ? 5 : 7,
|
||||
},
|
||||
layout: {
|
||||
type: String,
|
||||
default: 'total, sizes, prev, pager, next, jumper'
|
||||
default: 'total, sizes, prev, pager, next, jumper',
|
||||
},
|
||||
background: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
default: true,
|
||||
},
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
default: false,
|
||||
},
|
||||
};
|
||||
export default defineComponent({
|
||||
name: 'pagination',
|
||||
props: props,
|
||||
setup(props,{emit}){
|
||||
const { page,limit,pageSizes } = toRefs(props);
|
||||
setup(props, { emit }) {
|
||||
const { page, limit, pageSizes } = toRefs(props);
|
||||
const currentPage = computed({
|
||||
get() {
|
||||
return page.value;
|
||||
},
|
||||
set(val) {
|
||||
emit('update:page', val)
|
||||
}
|
||||
emit('update:page', val);
|
||||
},
|
||||
});
|
||||
const pageSize = computed({
|
||||
get() {
|
||||
return limit.value
|
||||
return limit.value;
|
||||
},
|
||||
set(val) {
|
||||
emit('update:limit', val)
|
||||
}
|
||||
emit('update:limit', val);
|
||||
},
|
||||
});
|
||||
const handleSizeChange = (val:number) => {
|
||||
emit('pagination', { page: currentPage.value, limit: val })
|
||||
const handleSizeChange = (val: number) => {
|
||||
emit('pagination', { page: currentPage.value, limit: val });
|
||||
};
|
||||
const handleCurrentChange = (val: number) => {
|
||||
emit('pagination', { page: val, limit: pageSizes.value });
|
||||
};
|
||||
const handleCurrentChange=(val:number) => {
|
||||
emit('pagination', { page: val, limit: pageSizes.value })
|
||||
}
|
||||
return {
|
||||
currentPage,
|
||||
pageSize,
|
||||
handleSizeChange,
|
||||
handleCurrentChange
|
||||
}
|
||||
}
|
||||
handleCurrentChange,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pagination-container {
|
||||
padding: 32px 16px;
|
||||
padding: 20px 16px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.pagination-container.hidden {
|
||||
display: none;
|
||||
|
@ -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;
|
||||
}
|
||||
|
14
src/main.ts
14
src/main.ts
@ -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');
|
||||
|
||||
|
@ -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 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
|
||||
|
1023
src/router/route.ts
1023
src/router/route.ts
File diff suppressed because it is too large
Load Diff
48
src/types/index.ts
Normal file
48
src/types/index.ts
Normal file
@ -0,0 +1,48 @@
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
export interface VersionMap{
|
||||
[key: string]: number
|
||||
}
|
@ -45,6 +45,9 @@ export function handleTree(data:any[], id:string, parentId:string, children:stri
|
||||
rootIds.push(item[parentId])
|
||||
}
|
||||
})
|
||||
}else if(typeof rootId ==='string'){
|
||||
rootId = rootId || ''
|
||||
rootIds = [rootId]
|
||||
}else{
|
||||
rootId = rootId || 0
|
||||
rootIds = [rootId]
|
||||
|
0
src/utils/index.ts
Normal file
0
src/utils/index.ts
Normal file
55
src/views/businesses/characteristic/api.ts
Normal file
55
src/views/businesses/characteristic/api.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import request from '/@/utils/request'
|
||||
// 查询识别特征列表
|
||||
export function listCharacteristic(query:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/characteristic/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
// 查询识别特征详细
|
||||
export function getCharacteristic(id:number) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/characteristic/get',
|
||||
method: 'get',
|
||||
params: {
|
||||
id: id.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
// 新增识别特征
|
||||
export function addCharacteristic(data:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/characteristic/add',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 修改识别特征
|
||||
export function updateCharacteristic(data:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/characteristic/edit',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 删除识别特征
|
||||
export function delCharacteristic(ids:number[], version: number[]) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/characteristic/delete',
|
||||
method: 'delete',
|
||||
data:{
|
||||
ids:ids,
|
||||
version: version,
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function auditCharacteristic(data: object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/characteristic/audit',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
512
src/views/businesses/characteristic/index.vue
Normal file
512
src/views/businesses/characteristic/index.vue
Normal file
@ -0,0 +1,512 @@
|
||||
<template>
|
||||
<div class="businesses-characteristic-container">
|
||||
<el-card shadow="hover">
|
||||
<QueryForm
|
||||
v-model="searchForm"
|
||||
:fields="searchFields"
|
||||
@search="onSearch"
|
||||
@reset="onReset"
|
||||
:labelWidth="'120px'"
|
||||
ref="queryFormRef"
|
||||
/>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleAdd"
|
||||
v-auth="'api/v1/businesses/characteristic/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/characteristic/delete'"
|
||||
><el-icon><ele-Delete /></el-icon>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<ProTable
|
||||
v-if="columns.length > 0"
|
||||
ref="proTableRef"
|
||||
:columns="columns"
|
||||
:data="tableData.data"
|
||||
:loading="loading"
|
||||
:show-selection="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
:heightOffset="400"
|
||||
:action-width="280"
|
||||
>
|
||||
<template #actions="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleUpdate(row)"
|
||||
size="small"
|
||||
v-auth="'api/v1/businesses/characteristic/edit'"
|
||||
v-if="row.auditStatus != 1"
|
||||
><el-icon><ele-EditPen /></el-icon>修改</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(row)"
|
||||
v-auth="'api/v1/businesses/characteristic/delete'"
|
||||
><el-icon><ele-DeleteFilled /></el-icon>删除</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="handleAudit(row)"
|
||||
v-if="row.auditStatus == 0"
|
||||
v-auth="'api/v1/businesses/characteristic/audit'"
|
||||
><el-icon><ele-Check /></el-icon>审核</el-button
|
||||
>
|
||||
</template>
|
||||
</ProTable>
|
||||
<pagination
|
||||
v-show="tableData.total > 0"
|
||||
:total="tableData.total"
|
||||
v-model:page="tableData.param.pageNum"
|
||||
v-model:limit="tableData.param.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
<ModalForm
|
||||
v-model:visible="showDialog"
|
||||
:title="formTitle"
|
||||
:fields="formFields"
|
||||
v-model:modelValue="formData"
|
||||
:type="formType"
|
||||
:show-footer="true"
|
||||
:label-width="'120px'"
|
||||
:width="'50%'"
|
||||
@submit="handleFormSubmit"
|
||||
@cancel="handleCancel"
|
||||
ref="modalFormRef"
|
||||
>
|
||||
</ModalForm>
|
||||
<AuditForm
|
||||
ref="auditFormRef"
|
||||
v-model="showAuditDialog"
|
||||
title="审核数据"
|
||||
@submit="onAuditSubmit"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { toRefs, reactive, onMounted, ref, computed } from 'vue';
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import {
|
||||
listCharacteristic,
|
||||
delCharacteristic,
|
||||
addCharacteristic,
|
||||
updateCharacteristic,
|
||||
auditCharacteristic,
|
||||
} from './api';
|
||||
import {
|
||||
CharacteristicTableColumns,
|
||||
CharacteristicInfoData,
|
||||
CharacteristicTableDataState,
|
||||
} from './type';
|
||||
|
||||
import { getUserList } from '/@/api/system/user/index';
|
||||
import { UserItem, VersionMap } from '/@/types';
|
||||
import { parseTime } from '/@/utils/gfast';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { listSpeciesName } from '../speciesName/api';
|
||||
|
||||
import { QueryFormField, TableColumn, PopupFormField } from '/@/components/dynamicpage/type';
|
||||
import QueryForm from '/@/components/dynamicpage/queryForm/index.vue';
|
||||
import ProTable from '/@/components/dynamicpage/ProTable/index.vue';
|
||||
import ModalForm from '/@/components/dynamicpage/modalForm/index.vue';
|
||||
import AuditForm from '/@/components/dynamicpage/auditForm/index.vue';
|
||||
import { SpeciesNameInfoData } from '../speciesName/type';
|
||||
|
||||
defineOptions({ name: 'BusinessesCharacteristicList' });
|
||||
|
||||
const loading = ref(false);
|
||||
// 非单个禁用
|
||||
const single = ref(true);
|
||||
// 非多个禁用
|
||||
const multiple = ref(true);
|
||||
const userOptions = ref<UserItem[]>([]);
|
||||
|
||||
const state = reactive<CharacteristicTableDataState>({
|
||||
ids: [],
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
param: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
},
|
||||
});
|
||||
const versionMap = ref<VersionMap>({} as VersionMap);
|
||||
const proTableRef = ref();
|
||||
const { tableData } = toRefs(state);
|
||||
const columns: TableColumn[] = [
|
||||
{ label: '物种编码', prop: 'speciesCode' },
|
||||
{ label: '形态学特征', prop: 'formCharacteristic', minWidth: 200 },
|
||||
{ label: '分子生物学特征', prop: 'biologyCharacteristic', minWidth: 200 },
|
||||
{ label: '数据来源', prop: 'sourcesData', minWidth: 150 },
|
||||
{
|
||||
label: '数据采集人',
|
||||
prop: 'createUser',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
prop: 'createDate',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(_, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查人',
|
||||
prop: 'auditUser',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查日期',
|
||||
prop: 'auditDate',
|
||||
minWidth: 120,
|
||||
isFormater: true,
|
||||
formater(_, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'auditStatus',
|
||||
isFormater: true,
|
||||
formater(row, column, cellValue, index) {
|
||||
return cellValue == 0 ? '待审核' : cellValue == 1 ? '通过' : '不通过';
|
||||
},
|
||||
},
|
||||
{ label: '核查意见', prop: 'auditView' },
|
||||
{ label: '备注', prop: 'remark' },
|
||||
];
|
||||
|
||||
const onSearch = async (val: Record<string, any>) => {
|
||||
let newVal: Record<string, any> = {};
|
||||
for (const v in val) {
|
||||
if (val[v] || val[v] === 0) {
|
||||
newVal[v] = val[v];
|
||||
}
|
||||
}
|
||||
state.tableData.param = { ...state.tableData.param, ...newVal };
|
||||
getList();
|
||||
};
|
||||
const onReset = () => {
|
||||
state.tableData.param = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
getList();
|
||||
};
|
||||
const searchForm = ref<Partial<CharacteristicInfoData>>({
|
||||
speciesCode: undefined,
|
||||
formCharacteristic: undefined,
|
||||
biologyCharacteristic: undefined,
|
||||
sourcesData: undefined,
|
||||
createUser: undefined,
|
||||
auditUser: undefined,
|
||||
auditStatus: undefined,
|
||||
});
|
||||
const searchFields = computed<QueryFormField[]>(() => [
|
||||
{ label: '物种编码', prop: 'speciesCode', type: 'input', placeholder: '请输入物种编码' },
|
||||
{ label: '形态学特征', prop: 'formCharacteristic', type: 'input', placeholder: '请输入形态学特征' },
|
||||
{ label: '分子生物学特征', prop: 'biologyCharacteristic', type: 'input', placeholder: '请输入分子生物学特征' },
|
||||
{ label: '数据来源', prop: 'sourcesData', type: 'input', placeholder: '请输入数据来源' },
|
||||
{
|
||||
label: '核查状态',
|
||||
prop: 'auditStatus',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: '待审核', value: 0 },
|
||||
{ label: '通过', value: 1 },
|
||||
{ label: '不通过', value: 2 },
|
||||
],
|
||||
placeholder: '请输入物种编码',
|
||||
},
|
||||
|
||||
{
|
||||
label: '数据采集人',
|
||||
prop: 'createUser',
|
||||
type: 'select',
|
||||
options: userOptions.value.map((i) => {
|
||||
return {
|
||||
label: i.userNickname,
|
||||
value: i.id,
|
||||
};
|
||||
}),
|
||||
placeholder: '请选择数据采集人',
|
||||
},
|
||||
|
||||
{
|
||||
label: '数据核查人',
|
||||
prop: 'auditUser',
|
||||
type: 'select',
|
||||
options: userOptions.value.map((i) => {
|
||||
return {
|
||||
label: i.userNickname,
|
||||
value: i.id,
|
||||
};
|
||||
}),
|
||||
placeholder: '请选择数据核查人',
|
||||
},
|
||||
]);
|
||||
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initTableData();
|
||||
});
|
||||
// 初始化表格数据
|
||||
const initTableData = () => {
|
||||
getList();
|
||||
reqGetUserList();
|
||||
reqListSpeciesName();
|
||||
};
|
||||
// 获取列表数据
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listCharacteristic(state.tableData.param);
|
||||
let list = res.data.list ?? [];
|
||||
state.tableData.data = list;
|
||||
versionMap.value = list.reduce((acc: any, cur: any) => {
|
||||
acc[cur.id] = cur.version;
|
||||
return acc;
|
||||
}, {});
|
||||
state.tableData.total = res.data.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const specieslist = ref<SpeciesNameInfoData[]>([]);
|
||||
/**获取物种列表 */
|
||||
const reqListSpeciesName = async () => {
|
||||
if (userOptions.value.length > 0) return;
|
||||
const res = await listSpeciesName({ pageSize: 9999, pageNum: 1 });
|
||||
specieslist.value = res.data.list;
|
||||
};
|
||||
|
||||
/**获取用户列表 */
|
||||
|
||||
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<CharacteristicInfoData>) => {
|
||||
state.ids = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
const showDialog = ref(false);
|
||||
const formTitle = ref('');
|
||||
const formFields = computed<PopupFormField[]>(() => [
|
||||
{
|
||||
label: '物种编码',
|
||||
prop: 'speciesCode',
|
||||
type: 'select',
|
||||
options: specieslist.value.map((i) => {
|
||||
return {
|
||||
value: i.speciesCode,
|
||||
label: i.speciesCode,
|
||||
};
|
||||
}),
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入物种编码', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择物种编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '形态学特征',
|
||||
prop: 'formCharacteristic',
|
||||
rules: [{ required: true, message: '请输入形态学特征', trigger: 'blur' }],
|
||||
type: 'input',
|
||||
span: 24,
|
||||
componentProps: {
|
||||
type: 'textarea',
|
||||
placeholder: '请输入形态学特征',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '分子生物学特征',
|
||||
prop: 'biologyCharacteristic',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入分子生物学特征', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
type: 'textarea',
|
||||
placeholder: '请输入分子生物学特征',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据来源',
|
||||
prop: 'sourcesData',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入数据来源', trigger: 'blur' }],
|
||||
|
||||
componentProps: {
|
||||
type: 'textarea',
|
||||
placeholder: '请输入数据来源',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据采集人',
|
||||
span: 12,
|
||||
prop: 'createUser',
|
||||
type: 'select',
|
||||
rules: [{ required: true, message: '请选择数据采集人', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集人',
|
||||
},
|
||||
options: userOptions.value.map((i) => {
|
||||
return {
|
||||
label: i.userNickname,
|
||||
value: i.id,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
span: 12,
|
||||
prop: 'createDate',
|
||||
type: 'date',
|
||||
rules: [{ required: true, message: '请选择数据采集日期', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集日期',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
span: 24,
|
||||
type: 'input',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
type: 'textarea',
|
||||
},
|
||||
},
|
||||
]);
|
||||
const formData = ref<Partial<CharacteristicInfoData>>({
|
||||
speciesCode: undefined,
|
||||
formCharacteristic: undefined,
|
||||
biologyCharacteristic: undefined,
|
||||
sourcesData: undefined,
|
||||
createUser: undefined,
|
||||
createDate: undefined,
|
||||
remark: undefined,
|
||||
});
|
||||
const formType = ref<'add' | 'edit'>('add');
|
||||
|
||||
const handleFormSubmit = (form: CharacteristicInfoData) => {
|
||||
if (formType.value === 'add') {
|
||||
addCharacteristic(form).then(() => {
|
||||
ElMessage.success('新增成功');
|
||||
handleCancel();
|
||||
getList();
|
||||
});
|
||||
} else {
|
||||
form.auditStatus = 0;
|
||||
updateCharacteristic(form).then(() => {
|
||||
ElMessage.success('编辑成功');
|
||||
handleCancel();
|
||||
getList();
|
||||
});
|
||||
}
|
||||
};
|
||||
const handleCancel = () => {
|
||||
showDialog.value = false;
|
||||
formTitle.value = '';
|
||||
formType.value = 'add';
|
||||
formData.value = {
|
||||
speciesCode: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '新增分类地位';
|
||||
formType.value = 'add';
|
||||
};
|
||||
const handleUpdate = (row: CharacteristicInfoData) => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '编辑分类地位';
|
||||
formType.value = 'edit';
|
||||
formData.value = cloneDeep(row);
|
||||
};
|
||||
const handleDelete = (row: CharacteristicTableColumns | 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(() => {
|
||||
delCharacteristic(
|
||||
id,
|
||||
id.map((i) => versionMap.value[i])
|
||||
).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
getList();
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const auditFormRef = ref();
|
||||
const showAuditDialog = ref(false);
|
||||
const handleAudit = (row: CharacteristicTableColumns) => {
|
||||
auditFormRef.value.open(cloneDeep(row), userOptions.value);
|
||||
};
|
||||
const onAuditSubmit = (val: CharacteristicTableColumns) => {
|
||||
auditCharacteristic(val).then(() => {
|
||||
ElMessage.success('审核成功');
|
||||
showAuditDialog.value = false;
|
||||
getList();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.colBlock {
|
||||
display: block;
|
||||
}
|
||||
.colNone {
|
||||
display: none;
|
||||
}
|
||||
.ml-2 {
|
||||
margin: 3px;
|
||||
}
|
||||
</style>
|
54
src/views/businesses/characteristic/type.ts
Normal file
54
src/views/businesses/characteristic/type.ts
Normal file
@ -0,0 +1,54 @@
|
||||
export interface CharacteristicTableColumns {
|
||||
id:number; //
|
||||
speciesCode:string; // 物种编码
|
||||
formCharacteristic:string; // 形态学特征
|
||||
biologyCharacteristic:string; // 分子生物学特征
|
||||
sourcesData:string; // 数据来源
|
||||
createUser:number; // 数据采集人
|
||||
createDate:string; // 数据采集日期
|
||||
auditUser:number; // 数据核查人
|
||||
auditDate:string; // 数据核查日期
|
||||
auditStatus:number; //
|
||||
auditView:string; //
|
||||
remark:string; //
|
||||
version:number; //
|
||||
}
|
||||
|
||||
|
||||
export interface CharacteristicInfoData {
|
||||
id:number|undefined; //
|
||||
speciesCode:string|undefined; // 物种编码
|
||||
formCharacteristic:string|undefined; // 形态学特征
|
||||
biologyCharacteristic:string|undefined; // 分子生物学特征
|
||||
sourcesData:string|undefined; // 数据来源
|
||||
createUser:number|undefined; // 数据采集人
|
||||
createDate:string|undefined; // 数据采集日期
|
||||
auditUser:number|undefined; // 数据核查人
|
||||
auditDate:string|undefined; // 数据核查日期
|
||||
auditStatus:number|undefined; //
|
||||
auditView:string|undefined; //
|
||||
remark:string|undefined; //
|
||||
version:number|undefined; //
|
||||
}
|
||||
|
||||
|
||||
export interface CharacteristicTableDataState {
|
||||
ids:any[];
|
||||
tableData: {
|
||||
data: Array<CharacteristicTableColumns>;
|
||||
total: number;
|
||||
loading: boolean;
|
||||
param: {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export interface CharacteristicEditState{
|
||||
loading:boolean;
|
||||
isShowDialog: boolean;
|
||||
formData:CharacteristicInfoData;
|
||||
rules: object;
|
||||
}
|
54
src/views/businesses/classifyStatuse/api.ts
Normal file
54
src/views/businesses/classifyStatuse/api.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import request from '/@/utils/request'
|
||||
// 查询分类地位列表
|
||||
export function listClassifyStatuse(query:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/classifyStatuse/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
// 查询分类地位详细
|
||||
export function getClassifyStatuse(id:number) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/classifyStatuse/get',
|
||||
method: 'get',
|
||||
params: {
|
||||
id: id.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
// 新增分类地位
|
||||
export function addClassifyStatuse(data:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/classifyStatuse/add',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 修改分类地位
|
||||
export function updateClassifyStatuse(data:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/classifyStatuse/edit',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 删除分类地位
|
||||
export function delClassifyStatuse(ids:number[],version:number[]) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/classifyStatuse/delete',
|
||||
method: 'delete',
|
||||
data:{
|
||||
ids:ids,
|
||||
version:version
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function auditSpeciesName(data:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/classifyStatuse/audit',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
682
src/views/businesses/classifyStatuse/index.vue
Normal file
682
src/views/businesses/classifyStatuse/index.vue
Normal file
@ -0,0 +1,682 @@
|
||||
<template>
|
||||
<div class="businesses-classifyStatuse-container">
|
||||
<el-card shadow="hover">
|
||||
<QueryForm
|
||||
v-model="searchForm"
|
||||
:fields="searchFields"
|
||||
@search="onSearch"
|
||||
@reset="onReset"
|
||||
ref="queryFormRef"
|
||||
/>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleAdd"
|
||||
v-auth="'api/v1/businesses/classifyStatuse/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/classifyStatuse/delete'"
|
||||
><el-icon><ele-Delete /></el-icon>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<ProTable
|
||||
v-if="columns.length > 0"
|
||||
ref="proTableRef"
|
||||
:columns="columns"
|
||||
:data="tableData.data"
|
||||
:loading="loading"
|
||||
:show-selection="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
:heightOffset="400"
|
||||
:action-width="280"
|
||||
>
|
||||
<template #actions="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleUpdate(row)"
|
||||
size="small"
|
||||
v-auth="'api/v1/businesses/classifyStatuse/edit'"
|
||||
v-if="row.auditStatus != 1"
|
||||
><el-icon><ele-EditPen /></el-icon>修改</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(row)"
|
||||
v-auth="'api/v1/businesses/classifyStatuse/delete'"
|
||||
><el-icon><ele-DeleteFilled /></el-icon>删除</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="handleAudit(row)"
|
||||
v-if="row.auditStatus == 0"
|
||||
v-auth="'api/v1/businesses/classifyStatuse/audit'"
|
||||
><el-icon><ele-Check /></el-icon>审核</el-button
|
||||
>
|
||||
</template>
|
||||
</ProTable>
|
||||
|
||||
<pagination
|
||||
v-show="tableData.total > 0"
|
||||
:total="tableData.total"
|
||||
v-model:page="tableData.param.pageNum"
|
||||
v-model:limit="tableData.param.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<ModalForm
|
||||
v-model:visible="showDialog"
|
||||
:title="formTitle"
|
||||
:fields="formFields"
|
||||
v-model:modelValue="formData"
|
||||
:type="formType"
|
||||
:show-footer="true"
|
||||
:label-width="'120px'"
|
||||
:width="'50%'"
|
||||
@submit="handleFormSubmit"
|
||||
@cancel="handleCancel"
|
||||
ref="modalFormRef"
|
||||
>
|
||||
</ModalForm>
|
||||
<AuditForm
|
||||
ref="auditFormRef"
|
||||
v-model="showAuditDialog"
|
||||
title="审核数据"
|
||||
@submit="onAuditSubmit"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { toRefs, reactive, onMounted, ref, computed } from 'vue';
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import {
|
||||
listClassifyStatuse,
|
||||
delClassifyStatuse,
|
||||
addClassifyStatuse,
|
||||
updateClassifyStatuse,
|
||||
auditSpeciesName,
|
||||
} from './api';
|
||||
import {
|
||||
ClassifyStatuseTableColumns,
|
||||
ClassifyStatuseInfoData,
|
||||
ClassifyStatuseTableDataState,
|
||||
} from './type';
|
||||
import { SpeciesNameInfoData } from '../speciesName/type';
|
||||
import { listSpeciesName } from '../speciesName/api';
|
||||
import { getUserList } from '/@/api/system/user/index';
|
||||
import { UserItem, VersionMap } from '/@/types';
|
||||
import { parseTime } from '/@/utils/gfast';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
import { QueryFormField, TableColumn, PopupFormField } from '/@/components/dynamicpage/type';
|
||||
import QueryForm from '/@/components/dynamicpage/queryForm/index.vue';
|
||||
import ProTable from '/@/components/dynamicpage/ProTable/index.vue';
|
||||
import ModalForm from '/@/components/dynamicpage/modalForm/index.vue';
|
||||
import AuditForm from '/@/components/dynamicpage/auditForm/index.vue';
|
||||
|
||||
defineOptions({ name: 'ClassifyStatuse' });
|
||||
const loading = ref(false);
|
||||
// 非单个禁用
|
||||
const single = ref(true);
|
||||
// 非多个禁用
|
||||
const multiple = ref(true);
|
||||
const userOptions = ref<UserItem[]>([]);
|
||||
|
||||
const state = reactive<ClassifyStatuseTableDataState>({
|
||||
ids: [],
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
param: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
},
|
||||
});
|
||||
const versionMap = ref<VersionMap>({} as VersionMap);
|
||||
const proTableRef = ref();
|
||||
const { tableData } = toRefs(state);
|
||||
const columns: TableColumn[] = [
|
||||
{ label: '物种编码', prop: 'speciesCode' },
|
||||
{ label: '界', prop: 'jie' },
|
||||
{ label: 'Kingdom', prop: 'kingdom', minWidth: 120 },
|
||||
{ label: '门', prop: 'men' },
|
||||
{ label: 'Phylum', prop: 'phylum' },
|
||||
{ label: '纲', prop: 'gang' },
|
||||
{ label: 'Class', prop: 'classTitle' },
|
||||
{ label: '目', prop: 'mu' },
|
||||
{ label: 'Order', prop: 'orderTitle' },
|
||||
{ label: '科', prop: 'ke' },
|
||||
{ label: 'Family', prop: 'family' },
|
||||
{ label: '属', prop: 'shu' },
|
||||
{ label: 'Genus', prop: 'genus' },
|
||||
{ label: '种', prop: 'zhong' },
|
||||
{ label: 'Species', prop: 'species' },
|
||||
{ label: '其他分类信息', prop: 'otherInfo', minWidth: 120 },
|
||||
{ label: '数据来源', prop: 'sourcesData' },
|
||||
{
|
||||
label: '数据采集人',
|
||||
prop: 'createUser',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
prop: 'createDate',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(_: ClassifyStatuseTableColumns, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查人',
|
||||
prop: 'auditUser',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查日期',
|
||||
prop: 'auditDate',
|
||||
minWidth: 120,
|
||||
isFormater: true,
|
||||
formater(_: ClassifyStatuseTableColumns, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'auditStatus',
|
||||
isFormater: true,
|
||||
formater(row, column, cellValue, index) {
|
||||
return cellValue == 0 ? '待审核' : cellValue == 1 ? '通过' : '不通过';
|
||||
},
|
||||
},
|
||||
{ label: '核查意见', prop: 'auditView' },
|
||||
{ label: '备注', prop: 'remark' },
|
||||
];
|
||||
|
||||
const onSearch = async (val: Record<string, any>) => {
|
||||
let newVal: Record<string, any> = {};
|
||||
for (const v in val) {
|
||||
if (val[v]) {
|
||||
newVal[v] = val[v];
|
||||
}
|
||||
}
|
||||
state.tableData.param = { ...state.tableData.param, ...newVal };
|
||||
getList();
|
||||
};
|
||||
const onReset = () => {
|
||||
state.tableData.param = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
getList();
|
||||
};
|
||||
const searchForm = ref<Partial<ClassifyStatuseInfoData>>({
|
||||
speciesCode: undefined,
|
||||
jie: undefined,
|
||||
kingdom: undefined,
|
||||
men: undefined,
|
||||
phylum: undefined,
|
||||
gang: undefined,
|
||||
classTitle: undefined,
|
||||
mu: undefined,
|
||||
orderTitle: undefined,
|
||||
ke: undefined,
|
||||
family: undefined,
|
||||
shu: undefined,
|
||||
genus: undefined,
|
||||
zhong: undefined,
|
||||
species: undefined,
|
||||
otherInfo: undefined,
|
||||
sourcesData: undefined,
|
||||
});
|
||||
const searchFields = computed<QueryFormField[]>(() => [
|
||||
{ label: '物种编码', prop: 'speciesCode', type: 'input', placeholder: '请输入物种编码' },
|
||||
{ label: '界', prop: 'jie', type: 'input', placeholder: '请输入界' },
|
||||
{ label: 'kingdom', prop: 'kingdom', type: 'input', placeholder: '请输入kingdom' },
|
||||
{ label: '门', prop: 'men', type: 'input', placeholder: '请输入门' },
|
||||
{ label: 'Phylum', prop: 'phylum', type: 'input', placeholder: '请输入Phylum' },
|
||||
{ label: '纲', prop: 'gang', type: 'input', placeholder: '请输入纲' },
|
||||
{ label: 'Class', prop: 'classTitle', type: 'input', placeholder: '请输入Class' },
|
||||
{ label: '目', prop: 'mu', type: 'input', placeholder: '请输入目' },
|
||||
{ label: 'Order', prop: 'orderTitle', type: 'input', placeholder: '请输入Order' },
|
||||
{ label: '科', prop: 'ke', type: 'input', placeholder: '请输入科' },
|
||||
{ label: 'Family', prop: 'family', type: 'input', placeholder: '请输入Family' },
|
||||
{ label: '属', prop: 'shu', type: 'input', placeholder: '请输入属' },
|
||||
{ label: 'Genus', prop: 'genus', type: 'input', placeholder: '请输入Genus' },
|
||||
{ label: '种', prop: 'zhong', type: 'input', placeholder: '请输入种' },
|
||||
{ label: 'Species', prop: 'species', type: 'input', placeholder: '请输入Species' },
|
||||
]);
|
||||
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initTableData();
|
||||
});
|
||||
// 初始化表格数据
|
||||
const initTableData = () => {
|
||||
getList();
|
||||
reqGetUserList();
|
||||
reqListSpeciesName();
|
||||
};
|
||||
// 获取列表数据
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listClassifyStatuse(state.tableData.param);
|
||||
let list = res.data.list ?? [];
|
||||
state.tableData.data = list;
|
||||
versionMap.value = list.reduce((acc: any, cur: any) => {
|
||||
acc[cur.id] = cur.version;
|
||||
return acc;
|
||||
}, {});
|
||||
state.tableData.total = res.data.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const specieslist = ref<SpeciesNameInfoData[]>([]);
|
||||
/**获取物种列表 */
|
||||
const reqListSpeciesName = async () => {
|
||||
if (userOptions.value.length > 0) return;
|
||||
const res = await listSpeciesName({ pageSize: 9999, pageNum: 1 });
|
||||
specieslist.value = res.data.list;
|
||||
};
|
||||
|
||||
/**获取用户列表 */
|
||||
|
||||
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<ClassifyStatuseInfoData>) => {
|
||||
state.ids = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
const showDialog = ref(false);
|
||||
const formTitle = ref('');
|
||||
const formFields = computed<PopupFormField[]>(() => [
|
||||
{
|
||||
label: '物种编码',
|
||||
prop: 'speciesCode',
|
||||
type: 'select',
|
||||
options: specieslist.value.map((i) => {
|
||||
return {
|
||||
value: i.speciesCode,
|
||||
label: i.speciesCode,
|
||||
};
|
||||
}),
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入物种编码', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择物种编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '界',
|
||||
prop: 'jie',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入界', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入界',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'kingdom',
|
||||
prop: 'kingdom',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入kingdom', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入界',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '门',
|
||||
prop: 'men',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入门', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入门',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Phylum',
|
||||
prop: 'phylum',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入Phylum', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入Phylum',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '纲',
|
||||
prop: 'gang',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入纲', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入纲',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Class',
|
||||
prop: 'classTitle',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入Class', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入Class',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '目',
|
||||
prop: 'mu',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入目', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入目',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Order',
|
||||
prop: 'orderTitle',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入Order', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入Order',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '科',
|
||||
prop: 'ke',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入科', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入科',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Family',
|
||||
prop: 'family',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入Family', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入Family',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '属',
|
||||
prop: 'shu',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入属', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入属',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Genus',
|
||||
prop: 'genus',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入Genus', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入Genus',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '种',
|
||||
prop: 'zhong',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入种', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入种',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Species',
|
||||
prop: 'species',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入Species', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入Species',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据来源',
|
||||
prop: 'sourcesData',
|
||||
span: 12,
|
||||
type: 'input',
|
||||
rules: [{ required: true, message: '请输入数据来源', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入数据来源',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '其他分类信息',
|
||||
prop: 'otherInfo',
|
||||
span: 24,
|
||||
type: 'input',
|
||||
rules: [{ required: true, message: '请输入其他分类信息', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入其他信息',
|
||||
type: 'textarea',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
label: '数据采集人',
|
||||
span: 12,
|
||||
prop: 'createUser',
|
||||
type: 'select',
|
||||
// rules: [{ required: true, message: '请选择数据采集人', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集人',
|
||||
},
|
||||
options: userOptions.value.map((i) => {
|
||||
return {
|
||||
label: i.userNickname,
|
||||
value: i.id,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
span: 12,
|
||||
prop: 'createDate',
|
||||
type: 'date',
|
||||
rules: [{ required: true, message: '请选择数据采集日期', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集日期',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
span: 24,
|
||||
type: 'input',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
type: 'textarea',
|
||||
},
|
||||
},
|
||||
]);
|
||||
const formData = ref<ClassifyStatuseInfoData>({
|
||||
speciesCode: undefined,
|
||||
jie: undefined,
|
||||
kingdom: undefined,
|
||||
men: undefined,
|
||||
phylum: undefined,
|
||||
gang: undefined,
|
||||
classTitle: undefined,
|
||||
mu: undefined,
|
||||
orderTitle: undefined,
|
||||
ke: undefined,
|
||||
family: undefined,
|
||||
shu: undefined,
|
||||
genus: undefined,
|
||||
id: undefined,
|
||||
zhong: undefined,
|
||||
species: undefined,
|
||||
otherInfo: undefined,
|
||||
sourcesData: undefined,
|
||||
createUser: undefined,
|
||||
createDate: undefined,
|
||||
remark: undefined,
|
||||
auditStatus: undefined,
|
||||
auditUser: undefined,
|
||||
auditDate: undefined,
|
||||
version: undefined,
|
||||
auditView: undefined,
|
||||
});
|
||||
const formType = ref<'add' | 'edit'>('add');
|
||||
|
||||
const handleFormSubmit = (form: ClassifyStatuseInfoData) => {
|
||||
if (formType.value === 'add') {
|
||||
addClassifyStatuse(form).then(() => {
|
||||
ElMessage.success('新增成功');
|
||||
handleCancel();
|
||||
getList();
|
||||
});
|
||||
} else {
|
||||
form.auditStatus = 0;
|
||||
updateClassifyStatuse(form).then(() => {
|
||||
ElMessage.success('编辑成功');
|
||||
handleCancel();
|
||||
getList();
|
||||
});
|
||||
}
|
||||
};
|
||||
const handleCancel = () => {
|
||||
showDialog.value = false;
|
||||
formTitle.value = '';
|
||||
formType.value = 'add';
|
||||
formData.value = {
|
||||
speciesCode: undefined,
|
||||
jie: undefined,
|
||||
kingdom: undefined,
|
||||
men: undefined,
|
||||
phylum: undefined,
|
||||
gang: undefined,
|
||||
classTitle: undefined,
|
||||
mu: undefined,
|
||||
orderTitle: undefined,
|
||||
ke: undefined,
|
||||
family: undefined,
|
||||
shu: undefined,
|
||||
genus: undefined,
|
||||
zhong: undefined,
|
||||
species: undefined,
|
||||
otherInfo: undefined,
|
||||
sourcesData: undefined,
|
||||
id: undefined,
|
||||
createUser: undefined,
|
||||
createDate: undefined,
|
||||
remark: undefined,
|
||||
auditStatus: undefined,
|
||||
auditUser: undefined,
|
||||
auditDate: undefined,
|
||||
version: undefined,
|
||||
auditView: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '新增分类地位';
|
||||
formType.value = 'add';
|
||||
};
|
||||
const handleUpdate = (row: ClassifyStatuseInfoData) => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '编辑分类地位';
|
||||
formType.value = 'edit';
|
||||
formData.value = cloneDeep(row);
|
||||
};
|
||||
const handleDelete = (row: ClassifyStatuseTableColumns | 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(() => {
|
||||
delClassifyStatuse(
|
||||
id,
|
||||
id.map((i) => versionMap.value[i])
|
||||
).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
getList();
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const auditFormRef = ref();
|
||||
const showAuditDialog = ref(false);
|
||||
const handleAudit = (row: ClassifyStatuseTableColumns) => {
|
||||
auditFormRef.value.open(cloneDeep(row), userOptions.value);
|
||||
};
|
||||
const onAuditSubmit = (val: ClassifyStatuseTableColumns) => {
|
||||
auditSpeciesName(val).then(() => {
|
||||
ElMessage.success('审核成功');
|
||||
showAuditDialog.value = false;
|
||||
getList();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.colBlock {
|
||||
display: block;
|
||||
}
|
||||
.colNone {
|
||||
display: none;
|
||||
}
|
||||
.ml-2 {
|
||||
margin: 3px;
|
||||
}
|
||||
</style>
|
78
src/views/businesses/classifyStatuse/type.ts
Normal file
78
src/views/businesses/classifyStatuse/type.ts
Normal file
@ -0,0 +1,78 @@
|
||||
export interface ClassifyStatuseTableColumns {
|
||||
id: number; //
|
||||
speciesCode: string; // 物种编码
|
||||
jie: string; // 界
|
||||
kingdom: string; // Kingdom
|
||||
men: string; // 门
|
||||
phylum: string; // Phylum
|
||||
gang: string; // 纲
|
||||
classTitle: string; // Class
|
||||
mu: string; // 目
|
||||
orderTitle: string; // Order
|
||||
ke: string; // 科
|
||||
family: string; // Family
|
||||
shu: string; // 属
|
||||
genus: string; // Genus
|
||||
zhong: string; // Genus
|
||||
species: string; // Species
|
||||
otherInfo: string; // 其他分类信息
|
||||
sourcesData: string; // 数据来源
|
||||
createUser: number; // 数据采集人
|
||||
createDate: string; // 数据采集日期
|
||||
auditUser: number; // 数据核查人
|
||||
auditDate: string; // 数据核查日期
|
||||
auditStatus: number; // 核查
|
||||
auditView: string; // 核查意见
|
||||
remark: string; // 备注
|
||||
version: number; // 版本
|
||||
createdAt: string; //
|
||||
}
|
||||
|
||||
export interface ClassifyStatuseInfoData {
|
||||
id?: number | undefined; //
|
||||
speciesCode: string | undefined; // 物种编码
|
||||
jie: string | undefined; // 界
|
||||
kingdom: string | undefined; // Kingdom
|
||||
men: string | undefined; // 门
|
||||
phylum: string | undefined; // Phylum
|
||||
gang: string | undefined; // 纲
|
||||
classTitle: string | undefined; // Class
|
||||
mu: string | undefined; // 目
|
||||
orderTitle: string | undefined; // Order
|
||||
ke: string | undefined; // 科
|
||||
family: string | undefined; // Family
|
||||
shu: string | undefined; // 属
|
||||
genus: string | undefined; // Genus
|
||||
zhong: string | undefined; // Genus
|
||||
species: string | undefined; // Species
|
||||
otherInfo: string | undefined; // 其他分类信息
|
||||
sourcesData: string | undefined; // 数据来源
|
||||
createUser: number | undefined; // 数据采集人
|
||||
createDate: string | undefined; // 数据采集日期
|
||||
auditUser: number | undefined; // 数据核查人
|
||||
auditDate: string | undefined; // 数据核查日期
|
||||
auditStatus: number | undefined; // 核查
|
||||
auditView: string | undefined; // 核查意见
|
||||
remark: string | undefined; // 备注
|
||||
version: number | undefined; // 版本
|
||||
}
|
||||
|
||||
export interface ClassifyStatuseTableDataState {
|
||||
ids: any[];
|
||||
tableData: {
|
||||
data: Array<ClassifyStatuseTableColumns>;
|
||||
total: number;
|
||||
loading: boolean;
|
||||
param: {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface ClassifyStatuseEditState {
|
||||
loading: boolean;
|
||||
isShowDialog: boolean;
|
||||
formData: ClassifyStatuseInfoData;
|
||||
rules: object;
|
||||
}
|
53
src/views/businesses/domestiDistribuion/api.ts
Normal file
53
src/views/businesses/domestiDistribuion/api.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import request from '/@/utils/request'
|
||||
// 查询国内分布列表
|
||||
export function listDomestiDistribuion(query:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/domestiDistribuion/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
// 查询国内分布详细
|
||||
export function getDomestiDistribuion(id:number) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/domestiDistribuion/get',
|
||||
method: 'get',
|
||||
params: {
|
||||
id: id.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
// 新增国内分布
|
||||
export function addDomestiDistribuion(data:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/domestiDistribuion/add',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 修改国内分布
|
||||
export function updateDomestiDistribuion(data:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/domestiDistribuion/edit',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 删除国内分布
|
||||
export function delDomestiDistribuion(ids:number[],version: number[]) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/domestiDistribuion/delete',
|
||||
method: 'delete',
|
||||
data:{
|
||||
ids:ids,
|
||||
version: version,
|
||||
}
|
||||
})
|
||||
}
|
||||
export function auditDomestiDistribuion(data: object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/domestiDistribuion/audit',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
519
src/views/businesses/domestiDistribuion/index.vue
Normal file
519
src/views/businesses/domestiDistribuion/index.vue
Normal file
@ -0,0 +1,519 @@
|
||||
<template>
|
||||
<div class="businesses-domestiDistribuion-container">
|
||||
<el-card shadow="hover">
|
||||
<QueryForm
|
||||
v-model="searchForm"
|
||||
:fields="searchFields"
|
||||
@search="onSearch"
|
||||
@reset="onReset"
|
||||
ref="queryFormRef"
|
||||
/>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleAdd"
|
||||
v-auth="'api/v1/businesses/domestiDistribuion/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/domestiDistribuion/delete'"
|
||||
><el-icon><ele-Delete /></el-icon>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<ProTable
|
||||
v-if="columns.length > 0"
|
||||
ref="proTableRef"
|
||||
:columns="columns"
|
||||
:data="tableData.data"
|
||||
:loading="loading"
|
||||
:show-selection="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
:heightOffset="400"
|
||||
:action-width="280"
|
||||
>
|
||||
<template #actions="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleUpdate(row)"
|
||||
size="small"
|
||||
v-auth="'api/v1/businesses/domestiDistribuion/edit'"
|
||||
v-if="row.auditStatus != 1"
|
||||
><el-icon><ele-EditPen /></el-icon>修改</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(row)"
|
||||
v-auth="'api/v1/businesses/domestiDistribuion/delete'"
|
||||
><el-icon><ele-DeleteFilled /></el-icon>删除</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="handleAudit(row)"
|
||||
v-if="row.auditStatus == 0"
|
||||
v-auth="'api/v1/businesses/domestiDistribuion/audit'"
|
||||
><el-icon><ele-Check /></el-icon>审核</el-button
|
||||
>
|
||||
</template>
|
||||
</ProTable>
|
||||
<pagination
|
||||
v-show="tableData.total > 0"
|
||||
:total="tableData.total"
|
||||
v-model:page="tableData.param.pageNum"
|
||||
v-model:limit="tableData.param.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
<ModalForm
|
||||
v-model:visible="showDialog"
|
||||
:title="formTitle"
|
||||
:fields="formFields"
|
||||
v-model:modelValue="formData"
|
||||
:type="formType"
|
||||
:show-footer="true"
|
||||
:label-width="'120px'"
|
||||
:width="'50%'"
|
||||
@submit="handleFormSubmit"
|
||||
@cancel="handleCancel"
|
||||
ref="modalFormRef"
|
||||
>
|
||||
</ModalForm>
|
||||
<AuditForm
|
||||
ref="auditFormRef"
|
||||
v-model="showAuditDialog"
|
||||
title="审核数据"
|
||||
@submit="onAuditSubmit"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { toRefs, reactive, onMounted, ref, computed } from 'vue';
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import {
|
||||
listDomestiDistribuion,
|
||||
getDomestiDistribuion,
|
||||
delDomestiDistribuion,
|
||||
addDomestiDistribuion,
|
||||
updateDomestiDistribuion,
|
||||
auditDomestiDistribuion,
|
||||
} from './api';
|
||||
import {
|
||||
DomestiDistribuionTableColumns,
|
||||
DomestiDistribuionInfoData,
|
||||
DomestiDistribuionTableDataState,
|
||||
} from './type';
|
||||
import { getUserList } from '/@/api/system/user/index';
|
||||
import { UserItem, VersionMap } from '/@/types';
|
||||
import { parseTime } from '/@/utils/gfast';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { listSpeciesName } from '../speciesName/api';
|
||||
|
||||
import { QueryFormField, TableColumn, PopupFormField } from '/@/components/dynamicpage/type';
|
||||
import QueryForm from '/@/components/dynamicpage/queryForm/index.vue';
|
||||
import ProTable from '/@/components/dynamicpage/ProTable/index.vue';
|
||||
import ModalForm from '/@/components/dynamicpage/modalForm/index.vue';
|
||||
import AuditForm from '/@/components/dynamicpage/auditForm/index.vue';
|
||||
import { SpeciesNameInfoData } from '../speciesName/type';
|
||||
defineOptions({ name: 'BusinessesDomestiDistribuionList' });
|
||||
const loading = ref(false);
|
||||
// 非单个禁用
|
||||
const single = ref(true);
|
||||
// 非多个禁用
|
||||
const multiple = ref(true);
|
||||
const userOptions = ref<UserItem[]>([]);
|
||||
|
||||
const state = reactive<DomestiDistribuionTableDataState>({
|
||||
ids: [],
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
param: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
},
|
||||
});
|
||||
const versionMap = ref<VersionMap>({} as VersionMap);
|
||||
const proTableRef = ref();
|
||||
const { tableData } = toRefs(state);
|
||||
const columns: TableColumn[] = [
|
||||
{ label: '物种编码', prop: 'speciesCode' },
|
||||
{ label: '所属省区', prop: 'province', minWidth: 150 },
|
||||
{ label: '所属地级州市', prop: 'city', minWidth: 150 },
|
||||
{ label: '所属区县', prop: 'county', minWidth: 150 },
|
||||
{ label: '发现年份', prop: 'year', minWidth: 150 },
|
||||
{ label: '数据来源', prop: 'sourcesData', minWidth: 150 },
|
||||
{
|
||||
label: '数据采集人',
|
||||
prop: 'createUser',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
prop: 'createDate',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(_, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查人',
|
||||
prop: 'auditUser',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查日期',
|
||||
prop: 'auditDate',
|
||||
minWidth: 120,
|
||||
isFormater: true,
|
||||
formater(_, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'auditStatus',
|
||||
isFormater: true,
|
||||
formater(row, column, cellValue, index) {
|
||||
return cellValue == 0 ? '待审核' : cellValue == 1 ? '通过' : '不通过';
|
||||
},
|
||||
},
|
||||
{ label: '核查意见', prop: 'auditView' },
|
||||
{ label: '备注', prop: 'remark' },
|
||||
];
|
||||
|
||||
const onSearch = async (val: Record<string, any>) => {
|
||||
let newVal: Record<string, any> = {};
|
||||
for (const v in val) {
|
||||
if (val[v] || val[v] === 0) {
|
||||
newVal[v] = val[v];
|
||||
}
|
||||
}
|
||||
state.tableData.param = { ...state.tableData.param, ...newVal };
|
||||
getList();
|
||||
};
|
||||
const onReset = () => {
|
||||
state.tableData.param = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
getList();
|
||||
};
|
||||
const searchForm = ref<Partial<DomestiDistribuionInfoData>>({
|
||||
speciesCode: undefined,
|
||||
province: undefined,
|
||||
city: undefined,
|
||||
county: undefined,
|
||||
year: undefined,
|
||||
sourcesData: undefined,
|
||||
createUser: undefined,
|
||||
auditStatus: undefined,
|
||||
});
|
||||
const searchFields = computed<QueryFormField[]>(() => [
|
||||
{ label: '物种编码', prop: 'speciesCode', type: 'input', placeholder: '请输入物种编码' },
|
||||
{ label: '所属省区', prop: 'province', type: 'input', placeholder: '请输入所属省区' },
|
||||
{ label: '所属地级州市', prop: 'city', type: 'input', placeholder: '请输入所属地级州市' },
|
||||
{ label: '所属区县', prop: 'county', type: 'input', placeholder: '请输入所属区县' },
|
||||
{ label: '发现年份', prop: 'year', type: 'input', placeholder: '请输入发现年份' },
|
||||
{ label: '数据来源', prop: 'sourcesData', type: 'input', placeholder: '请输入数据来源' },
|
||||
{
|
||||
label: '核查状态',
|
||||
prop: 'auditStatus',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: '待审核', value: 0 },
|
||||
{ label: '通过', value: 1 },
|
||||
{ label: '不通过', value: 2 },
|
||||
],
|
||||
placeholder: '请输入物种编码',
|
||||
},
|
||||
{
|
||||
label: '数据采集人',
|
||||
prop: 'createUser',
|
||||
type: 'select',
|
||||
options: userOptions.value.map((i) => {
|
||||
return {
|
||||
label: i.userNickname,
|
||||
value: i.id,
|
||||
};
|
||||
}),
|
||||
placeholder: '请选择数据采集人',
|
||||
},
|
||||
]);
|
||||
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initTableData();
|
||||
});
|
||||
// 初始化表格数据
|
||||
const initTableData = () => {
|
||||
getList();
|
||||
reqGetUserList();
|
||||
reqListSpeciesName();
|
||||
};
|
||||
// 获取列表数据
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listDomestiDistribuion(state.tableData.param);
|
||||
let list = res.data.list ?? [];
|
||||
state.tableData.data = list;
|
||||
versionMap.value = list.reduce((acc: any, cur: any) => {
|
||||
acc[cur.id] = cur.version;
|
||||
return acc;
|
||||
}, {});
|
||||
state.tableData.total = res.data.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const specieslist = ref<SpeciesNameInfoData[]>([]);
|
||||
/**获取物种列表 */
|
||||
const reqListSpeciesName = async () => {
|
||||
if (userOptions.value.length > 0) return;
|
||||
const res = await listSpeciesName({ pageSize: 9999, pageNum: 1 });
|
||||
specieslist.value = res.data.list;
|
||||
};
|
||||
|
||||
/**获取用户列表 */
|
||||
|
||||
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<DomestiDistribuionTableColumns>) => {
|
||||
state.ids = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
const showDialog = ref(false);
|
||||
const formTitle = ref('');
|
||||
const formFields = computed<PopupFormField[]>(() => [
|
||||
{
|
||||
label: '物种编码',
|
||||
prop: 'speciesCode',
|
||||
type: 'select',
|
||||
options: specieslist.value.map((i) => {
|
||||
return {
|
||||
value: i.speciesCode,
|
||||
label: i.speciesCode,
|
||||
};
|
||||
}),
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入物种编码', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择物种编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '所属省区',
|
||||
prop: 'province',
|
||||
rules: [{ required: true, message: '请输入所属省区', trigger: 'blur' }],
|
||||
type: 'input',
|
||||
span: 24,
|
||||
componentProps: {
|
||||
placeholder: '请输入所属省区',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '所属地级州市',
|
||||
prop: 'city',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入所属地级州市', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入所属地级州市',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '所属区县',
|
||||
prop: 'county',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入所属区县', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入所属区县',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '发现年份',
|
||||
prop: 'year',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入发现年份', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入发现年份',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据来源',
|
||||
prop: 'sourcesData',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入数据来源', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入数据来源',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据采集人',
|
||||
span: 12,
|
||||
prop: 'createUser',
|
||||
type: 'select',
|
||||
rules: [{ required: true, message: '请选择数据采集人', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集人',
|
||||
},
|
||||
options: userOptions.value.map((i) => {
|
||||
return {
|
||||
label: i.userNickname,
|
||||
value: i.id,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
span: 12,
|
||||
prop: 'createDate',
|
||||
type: 'date',
|
||||
rules: [{ required: true, message: '请选择数据采集日期', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集日期',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
span: 24,
|
||||
type: 'input',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
type: 'textarea',
|
||||
},
|
||||
},
|
||||
]);
|
||||
const formData = ref<Partial<DomestiDistribuionInfoData>>({
|
||||
speciesCode: undefined,
|
||||
province: undefined,
|
||||
county: undefined,
|
||||
city: undefined,
|
||||
year: undefined,
|
||||
sourcesData: undefined,
|
||||
createUser: undefined,
|
||||
createDate: undefined,
|
||||
remark: undefined,
|
||||
});
|
||||
const formType = ref<'add' | 'edit'>('add');
|
||||
|
||||
const handleFormSubmit = (form: DomestiDistribuionInfoData) => {
|
||||
if (formType.value === 'add') {
|
||||
addDomestiDistribuion(form).then(() => {
|
||||
ElMessage.success('新增成功');
|
||||
handleCancel();
|
||||
getList();
|
||||
});
|
||||
} else {
|
||||
form.auditStatus = 0;
|
||||
updateDomestiDistribuion(form).then(() => {
|
||||
ElMessage.success('编辑成功');
|
||||
handleCancel();
|
||||
getList();
|
||||
});
|
||||
}
|
||||
};
|
||||
const handleCancel = () => {
|
||||
showDialog.value = false;
|
||||
formTitle.value = '';
|
||||
formType.value = 'add';
|
||||
formData.value = {
|
||||
speciesCode: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '新增分类地位';
|
||||
formType.value = 'add';
|
||||
};
|
||||
const handleUpdate = (row: DomestiDistribuionInfoData) => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '编辑分类地位';
|
||||
formType.value = 'edit';
|
||||
formData.value = cloneDeep(row);
|
||||
};
|
||||
const handleDelete = (row: DomestiDistribuionTableColumns | 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(() => {
|
||||
delDomestiDistribuion(
|
||||
id,
|
||||
id.map((i) => versionMap.value[i])
|
||||
).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
getList();
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const auditFormRef = ref();
|
||||
const showAuditDialog = ref(false);
|
||||
const handleAudit = (row: DomestiDistribuionTableColumns) => {
|
||||
auditFormRef.value.open(cloneDeep(row), userOptions.value);
|
||||
};
|
||||
const onAuditSubmit = (val: DomestiDistribuionTableColumns) => {
|
||||
auditDomestiDistribuion(val).then(() => {
|
||||
ElMessage.success('审核成功');
|
||||
showAuditDialog.value = false;
|
||||
getList();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.colBlock {
|
||||
display: block;
|
||||
}
|
||||
.colNone {
|
||||
display: none;
|
||||
}
|
||||
.ml-2 {
|
||||
margin: 3px;
|
||||
}
|
||||
</style>
|
55
src/views/businesses/domestiDistribuion/type.ts
Normal file
55
src/views/businesses/domestiDistribuion/type.ts
Normal file
@ -0,0 +1,55 @@
|
||||
export interface DomestiDistribuionTableColumns {
|
||||
id: number; //
|
||||
speciesCode: string; // 物种编码
|
||||
province: string; // 所属省区
|
||||
city: string; // 所属地级州市
|
||||
county: string; // 所属区县
|
||||
year: string; // 发现年份
|
||||
sourcesData: string; // 数据来源
|
||||
createUser: number; // 数据采集人
|
||||
createDate: string; // 数据采集日期
|
||||
auditUser: number; // 数据核查人
|
||||
auditDate: string; // 数据核查日期
|
||||
auditStatus: number; //
|
||||
auditView: string; //
|
||||
remark: string; //
|
||||
version: number; //
|
||||
}
|
||||
|
||||
export interface DomestiDistribuionInfoData {
|
||||
id: number | undefined; //
|
||||
speciesCode: string | undefined; // 物种编码
|
||||
province: string | undefined; // 所属省区
|
||||
city: string | undefined; // 所属地级州市
|
||||
county: string | undefined; // 所属区县
|
||||
year: string | undefined; // 发现年份
|
||||
sourcesData: string | undefined; // 数据来源
|
||||
createUser: number | undefined; // 数据采集人
|
||||
createDate: string | undefined; // 数据采集日期
|
||||
auditUser: number | undefined; // 数据核查人
|
||||
auditDate: string | undefined; // 数据核查日期
|
||||
auditStatus: number | undefined; //
|
||||
auditView: string | undefined; //
|
||||
remark: string | undefined; //
|
||||
version: number | undefined; //
|
||||
}
|
||||
|
||||
export interface DomestiDistribuionTableDataState {
|
||||
ids: any[];
|
||||
tableData: {
|
||||
data: Array<DomestiDistribuionTableColumns>;
|
||||
total: number;
|
||||
loading: boolean;
|
||||
param: {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface DomestiDistribuionEditState {
|
||||
loading: boolean;
|
||||
isShowDialog: boolean;
|
||||
formData: DomestiDistribuionInfoData;
|
||||
rules: object;
|
||||
}
|
53
src/views/businesses/foreignDistribution/api.ts
Normal file
53
src/views/businesses/foreignDistribution/api.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import request from '/@/utils/request'
|
||||
// 查询国外分布列表
|
||||
export function listForeignDistribution(query:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/foreignDistribution/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
// 查询国外分布详细
|
||||
export function getForeignDistribution(id:number) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/foreignDistribution/get',
|
||||
method: 'get',
|
||||
params: {
|
||||
id: id.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
// 新增国外分布
|
||||
export function addForeignDistribution(data:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/foreignDistribution/add',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 修改国外分布
|
||||
export function updateForeignDistribution(data:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/foreignDistribution/edit',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 删除国外分布
|
||||
export function delForeignDistribution(ids:number[],version: number[]) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/foreignDistribution/delete',
|
||||
method: 'delete',
|
||||
data:{
|
||||
ids:ids,
|
||||
version: version,
|
||||
}
|
||||
})
|
||||
}
|
||||
export function auditForeignDistribution(data: object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/foreignDistribution/audit',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
520
src/views/businesses/foreignDistribution/index.vue
Normal file
520
src/views/businesses/foreignDistribution/index.vue
Normal file
@ -0,0 +1,520 @@
|
||||
<template>
|
||||
<div class="businesses-foreignDistribution-container">
|
||||
<el-card shadow="hover">
|
||||
<QueryForm
|
||||
v-model="searchForm"
|
||||
:fields="searchFields"
|
||||
@search="onSearch"
|
||||
@reset="onReset"
|
||||
ref="queryFormRef"
|
||||
/>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleAdd"
|
||||
v-auth="'api/v1/businesses/foreignDistribution/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/foreignDistribution/delete'"
|
||||
><el-icon><ele-Delete /></el-icon>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<ProTable
|
||||
v-if="columns.length > 0"
|
||||
ref="proTableRef"
|
||||
:columns="columns"
|
||||
:data="tableData.data"
|
||||
:loading="loading"
|
||||
:show-selection="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
:heightOffset="400"
|
||||
:action-width="280"
|
||||
>
|
||||
<template #actions="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleUpdate(row)"
|
||||
size="small"
|
||||
v-auth="'api/v1/businesses/foreignDistribution/edit'"
|
||||
v-if="row.auditStatus != 1"
|
||||
><el-icon><ele-EditPen /></el-icon>修改</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(row)"
|
||||
v-auth="'api/v1/businesses/foreignDistribution/delete'"
|
||||
><el-icon><ele-DeleteFilled /></el-icon>删除</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="handleAudit(row)"
|
||||
v-if="row.auditStatus == 0"
|
||||
v-auth="'api/v1/businesses/foreignDistribution/audit'"
|
||||
><el-icon><ele-Check /></el-icon>审核</el-button
|
||||
>
|
||||
</template>
|
||||
</ProTable>
|
||||
<pagination
|
||||
v-show="tableData.total > 0"
|
||||
:total="tableData.total"
|
||||
v-model:page="tableData.param.pageNum"
|
||||
v-model:limit="tableData.param.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
<ModalForm
|
||||
v-model:visible="showDialog"
|
||||
:title="formTitle"
|
||||
:fields="formFields"
|
||||
v-model:modelValue="formData"
|
||||
:type="formType"
|
||||
:show-footer="true"
|
||||
:label-width="'120px'"
|
||||
:width="'50%'"
|
||||
@submit="handleFormSubmit"
|
||||
@cancel="handleCancel"
|
||||
ref="modalFormRef"
|
||||
>
|
||||
</ModalForm>
|
||||
<AuditForm
|
||||
ref="auditFormRef"
|
||||
v-model="showAuditDialog"
|
||||
title="审核数据"
|
||||
@submit="onAuditSubmit"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { toRefs, reactive, onMounted, ref, computed } from 'vue';
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import {
|
||||
listForeignDistribution,
|
||||
delForeignDistribution,
|
||||
addForeignDistribution,
|
||||
updateForeignDistribution,
|
||||
auditForeignDistribution,
|
||||
} from './api';
|
||||
import {
|
||||
ForeignDistributionTableColumns,
|
||||
ForeignDistributionInfoData,
|
||||
ForeignDistributionTableDataState,
|
||||
} from './type';
|
||||
|
||||
import { getUserList } from '/@/api/system/user/index';
|
||||
import { UserItem, VersionMap } from '/@/types';
|
||||
import { parseTime } from '/@/utils/gfast';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { listSpeciesName } from '../speciesName/api';
|
||||
|
||||
import { QueryFormField, TableColumn, PopupFormField } from '/@/components/dynamicpage/type';
|
||||
import QueryForm from '/@/components/dynamicpage/queryForm/index.vue';
|
||||
import ProTable from '/@/components/dynamicpage/ProTable/index.vue';
|
||||
import ModalForm from '/@/components/dynamicpage/modalForm/index.vue';
|
||||
import AuditForm from '/@/components/dynamicpage/auditForm/index.vue';
|
||||
import { SpeciesNameInfoData } from '../speciesName/type';
|
||||
defineOptions({ name: 'BusinessesForeignDistributionList' });
|
||||
|
||||
const loading = ref(false);
|
||||
// 非单个禁用
|
||||
const single = ref(true);
|
||||
// 非多个禁用
|
||||
const multiple = ref(true);
|
||||
const userOptions = ref<UserItem[]>([]);
|
||||
|
||||
const state = reactive<ForeignDistributionTableDataState>({
|
||||
ids: [],
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
param: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
},
|
||||
});
|
||||
const versionMap = ref<VersionMap>({} as VersionMap);
|
||||
const proTableRef = ref();
|
||||
const { tableData } = toRefs(state);
|
||||
const columns: TableColumn[] = [
|
||||
{ label: '物种编码', prop: 'speciesCode' },
|
||||
{ label: '所属大洲', prop: 'continent', minWidth: 150 },
|
||||
{ label: '所属国家/地区', prop: 'region', minWidth: 150 },
|
||||
{ label: '所属州', prop: 'belongState', minWidth: 150 },
|
||||
{ label: '发现/报道年份', prop: 'year', minWidth: 150 },
|
||||
{ label: '参考文献', prop: 'references', minWidth: 150 },
|
||||
{
|
||||
label: '数据采集人',
|
||||
prop: 'createUser',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
prop: 'createDate',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(_, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查人',
|
||||
prop: 'auditUser',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查日期',
|
||||
prop: 'auditDate',
|
||||
minWidth: 120,
|
||||
isFormater: true,
|
||||
formater(_, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'auditStatus',
|
||||
isFormater: true,
|
||||
formater(row, column, cellValue, index) {
|
||||
return cellValue == 0 ? '待审核' : cellValue == 1 ? '通过' : '不通过';
|
||||
},
|
||||
},
|
||||
{ label: '核查意见', prop: 'auditView' },
|
||||
{ label: '备注', prop: 'remark' },
|
||||
];
|
||||
|
||||
const onSearch = async (val: Record<string, any>) => {
|
||||
let newVal: Record<string, any> = {};
|
||||
for (const v in val) {
|
||||
if (val[v] || val[v] === 0) {
|
||||
newVal[v] = val[v];
|
||||
}
|
||||
}
|
||||
state.tableData.param = { ...state.tableData.param, ...newVal };
|
||||
getList();
|
||||
};
|
||||
const onReset = () => {
|
||||
state.tableData.param = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
getList();
|
||||
};
|
||||
const searchForm = ref<Partial<ForeignDistributionInfoData>>({
|
||||
speciesCode: undefined,
|
||||
continent: undefined,
|
||||
region: undefined,
|
||||
belongState: undefined,
|
||||
year: undefined,
|
||||
references: undefined,
|
||||
createUser: undefined,
|
||||
auditStatus: undefined,
|
||||
});
|
||||
const searchFields = computed<QueryFormField[]>(() => [
|
||||
{ label: '物种编码', prop: 'speciesCode', type: 'input', placeholder: '请输入物种编码' },
|
||||
{ label: '所属大洲', prop: 'continent', type: 'input', placeholder: '请输入所属大洲' },
|
||||
{ label: '所属国家/地区', prop: 'region', type: 'input', placeholder: '请输入所属国家/地区' },
|
||||
{ label: '所属州', prop: 'belongState', type: 'input', placeholder: '请输入所属州' },
|
||||
{ label: '发现/报道年份', prop: 'year', type: 'input', placeholder: '请输入发现/报道年份' },
|
||||
{ label: '参考文献', prop: 'references', type: 'input', placeholder: '请输入参考文献' },
|
||||
|
||||
{
|
||||
label: '核查状态',
|
||||
prop: 'auditStatus',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: '待审核', value: 0 },
|
||||
{ label: '通过', value: 1 },
|
||||
{ label: '不通过', value: 2 },
|
||||
],
|
||||
placeholder: '请输入物种编码',
|
||||
},
|
||||
{
|
||||
label: '数据采集人',
|
||||
prop: 'createUser',
|
||||
type: 'select',
|
||||
options: userOptions.value.map((i) => {
|
||||
return {
|
||||
label: i.userNickname,
|
||||
value: i.id,
|
||||
};
|
||||
}),
|
||||
placeholder: '请选择数据采集人',
|
||||
},
|
||||
]);
|
||||
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initTableData();
|
||||
});
|
||||
// 初始化表格数据
|
||||
const initTableData = () => {
|
||||
getList();
|
||||
reqGetUserList();
|
||||
reqListSpeciesName();
|
||||
};
|
||||
// 获取列表数据
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listForeignDistribution(state.tableData.param);
|
||||
let list = res.data.list ?? [];
|
||||
state.tableData.data = list;
|
||||
versionMap.value = list.reduce((acc: any, cur: any) => {
|
||||
acc[cur.id] = cur.version;
|
||||
return acc;
|
||||
}, {});
|
||||
state.tableData.total = res.data.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const specieslist = ref<SpeciesNameInfoData[]>([]);
|
||||
/**获取物种列表 */
|
||||
const reqListSpeciesName = async () => {
|
||||
if (userOptions.value.length > 0) return;
|
||||
const res = await listSpeciesName({ pageSize: 9999, pageNum: 1 });
|
||||
specieslist.value = res.data.list;
|
||||
};
|
||||
|
||||
/**获取用户列表 */
|
||||
|
||||
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<ForeignDistributionInfoData>) => {
|
||||
state.ids = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
const showDialog = ref(false);
|
||||
const formTitle = ref('');
|
||||
const formFields = computed<PopupFormField[]>(() => [
|
||||
{
|
||||
label: '物种编码',
|
||||
prop: 'speciesCode',
|
||||
type: 'select',
|
||||
options: specieslist.value.map((i) => {
|
||||
return {
|
||||
value: i.speciesCode,
|
||||
label: i.speciesCode,
|
||||
};
|
||||
}),
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入物种编码', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择物种编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '所属大洲',
|
||||
prop: 'continent',
|
||||
rules: [{ required: true, message: '请输入所属大洲', trigger: 'blur' }],
|
||||
type: 'input',
|
||||
span: 24,
|
||||
componentProps: {
|
||||
placeholder: '请输入所属大洲',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '所属国家/地区',
|
||||
prop: 'region',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入所属国家/地区', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入所属国家/地区',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '所属州',
|
||||
prop: 'belongState',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入所属州', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入所属州',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '发现/报道年份',
|
||||
prop: 'year',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入发现/报道年份', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入发现/报道年份',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '参考文献',
|
||||
prop: 'references',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入参考文献', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入参考文献',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据采集人',
|
||||
span: 12,
|
||||
prop: 'createUser',
|
||||
type: 'select',
|
||||
rules: [{ required: true, message: '请选择数据采集人', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集人',
|
||||
},
|
||||
options: userOptions.value.map((i) => {
|
||||
return {
|
||||
label: i.userNickname,
|
||||
value: i.id,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
span: 12,
|
||||
prop: 'createDate',
|
||||
type: 'date',
|
||||
rules: [{ required: true, message: '请选择数据采集日期', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集日期',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
span: 24,
|
||||
type: 'input',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
type: 'textarea',
|
||||
},
|
||||
},
|
||||
]);
|
||||
const formData = ref<Partial<ForeignDistributionInfoData>>({
|
||||
speciesCode: undefined,
|
||||
continent: undefined,
|
||||
region: undefined,
|
||||
belongState: undefined,
|
||||
year: undefined,
|
||||
references: undefined,
|
||||
createUser: undefined,
|
||||
createDate: undefined,
|
||||
remark: undefined,
|
||||
});
|
||||
const formType = ref<'add' | 'edit'>('add');
|
||||
|
||||
const handleFormSubmit = (form: ForeignDistributionInfoData) => {
|
||||
if (formType.value === 'add') {
|
||||
addForeignDistribution(form).then(() => {
|
||||
ElMessage.success('新增成功');
|
||||
handleCancel();
|
||||
getList();
|
||||
});
|
||||
} else {
|
||||
form.auditStatus = 0;
|
||||
updateForeignDistribution(form).then(() => {
|
||||
ElMessage.success('编辑成功');
|
||||
handleCancel();
|
||||
getList();
|
||||
});
|
||||
}
|
||||
};
|
||||
const handleCancel = () => {
|
||||
showDialog.value = false;
|
||||
formTitle.value = '';
|
||||
formType.value = 'add';
|
||||
formData.value = {
|
||||
speciesCode: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '新增分类地位';
|
||||
formType.value = 'add';
|
||||
};
|
||||
const handleUpdate = (row: ForeignDistributionInfoData) => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '编辑分类地位';
|
||||
formType.value = 'edit';
|
||||
formData.value = cloneDeep(row);
|
||||
};
|
||||
const handleDelete = (row: ForeignDistributionTableColumns | 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(() => {
|
||||
delForeignDistribution(
|
||||
id,
|
||||
id.map((i) => versionMap.value[i])
|
||||
).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
getList();
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const auditFormRef = ref();
|
||||
const showAuditDialog = ref(false);
|
||||
const handleAudit = (row: ForeignDistributionTableColumns) => {
|
||||
auditFormRef.value.open(cloneDeep(row), userOptions.value);
|
||||
};
|
||||
const onAuditSubmit = (val: ForeignDistributionTableColumns) => {
|
||||
auditForeignDistribution(val).then(() => {
|
||||
ElMessage.success('审核成功');
|
||||
showAuditDialog.value = false;
|
||||
getList();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.colBlock {
|
||||
display: block;
|
||||
}
|
||||
.colNone {
|
||||
display: none;
|
||||
}
|
||||
.ml-2 {
|
||||
margin: 3px;
|
||||
}
|
||||
</style>
|
55
src/views/businesses/foreignDistribution/type.ts
Normal file
55
src/views/businesses/foreignDistribution/type.ts
Normal file
@ -0,0 +1,55 @@
|
||||
export interface ForeignDistributionTableColumns {
|
||||
id: number; //
|
||||
speciesCode: string; // 物种编码
|
||||
continent: string; // 所属大洲
|
||||
region: string; // 所属国家/地区
|
||||
belongState: string; // 所属州
|
||||
year: string; // 发现/报道年份
|
||||
references: string; // 参考文献
|
||||
createUser: number; // 数据采集人
|
||||
createDate: string; // 数据采集日期
|
||||
auditUser: number; // 数据核查人
|
||||
auditDate: string; // 数据核查日期
|
||||
auditStatus: number; //
|
||||
auditView: string; //
|
||||
remark: string; //
|
||||
version: number; //
|
||||
}
|
||||
|
||||
export interface ForeignDistributionInfoData {
|
||||
id: number | undefined; //
|
||||
speciesCode: string | undefined; // 物种编码
|
||||
continent: string | undefined; // 所属大洲
|
||||
region: string | undefined; // 所属国家/地区
|
||||
belongState: string | undefined; // 所属州
|
||||
year: string | undefined; // 发现/报道年份
|
||||
references: string | undefined; // 参考文献
|
||||
createUser: number | undefined; // 数据采集人
|
||||
createDate: string | undefined; // 数据采集日期
|
||||
auditUser: number | undefined; // 数据核查人
|
||||
auditDate: string | undefined; // 数据核查日期
|
||||
auditStatus: number | undefined; //
|
||||
auditView: string | undefined; //
|
||||
remark: string | undefined; //
|
||||
version: number | undefined; //
|
||||
}
|
||||
|
||||
export interface ForeignDistributionTableDataState {
|
||||
ids: any[];
|
||||
tableData: {
|
||||
data: Array<ForeignDistributionTableColumns>;
|
||||
total: number;
|
||||
loading: boolean;
|
||||
param: {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface ForeignDistributionEditState {
|
||||
loading: boolean;
|
||||
isShowDialog: boolean;
|
||||
formData: ForeignDistributionInfoData;
|
||||
rules: object;
|
||||
}
|
53
src/views/businesses/geography/api.ts
Normal file
53
src/views/businesses/geography/api.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import request from '/@/utils/request';
|
||||
// 查询地理分布列表
|
||||
export function listGeography(query: object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/geography/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
// 查询地理分布详细
|
||||
export function getGeography(id: number) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/geography/get',
|
||||
method: 'get',
|
||||
params: {
|
||||
id: id.toString(),
|
||||
},
|
||||
});
|
||||
}
|
||||
// 新增地理分布
|
||||
export function addGeography(data: object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/geography/add',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
// 修改地理分布
|
||||
export function updateGeography(data: object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/geography/edit',
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
// 删除地理分布
|
||||
export function delGeography(ids: number[], version: number[]) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/geography/delete',
|
||||
method: 'delete',
|
||||
data: {
|
||||
ids: ids,
|
||||
version: version,
|
||||
},
|
||||
});
|
||||
}
|
||||
export function auditGeography(data: object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/geography/audit',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
512
src/views/businesses/geography/index.vue
Normal file
512
src/views/businesses/geography/index.vue
Normal file
@ -0,0 +1,512 @@
|
||||
<template>
|
||||
<div class="businesses-geography-container">
|
||||
<el-card shadow="hover">
|
||||
<QueryForm
|
||||
v-model="searchForm"
|
||||
:fields="searchFields"
|
||||
@search="onSearch"
|
||||
@reset="onReset"
|
||||
ref="queryFormRef"
|
||||
/>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" @click="handleAdd" v-auth="'api/v1/businesses/geography/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/geography/delete'"
|
||||
><el-icon><ele-Delete /></el-icon>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<ProTable
|
||||
v-if="columns.length > 0"
|
||||
ref="proTableRef"
|
||||
:columns="columns"
|
||||
:data="tableData.data"
|
||||
:loading="loading"
|
||||
:show-selection="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
:heightOffset="400"
|
||||
:action-width="280"
|
||||
>
|
||||
<template #actions="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleUpdate(row)"
|
||||
size="small"
|
||||
v-auth="'api/v1/businesses/geography/edit'"
|
||||
v-if="row.auditStatus != 1"
|
||||
><el-icon><ele-EditPen /></el-icon>修改</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(row)"
|
||||
v-auth="'api/v1/businesses/geography/delete'"
|
||||
><el-icon><ele-DeleteFilled /></el-icon>删除</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="handleAudit(row)"
|
||||
v-if="row.auditStatus == 0"
|
||||
v-auth="'api/v1/businesses/geography/audit'"
|
||||
><el-icon><ele-Check /></el-icon>审核</el-button
|
||||
>
|
||||
</template>
|
||||
</ProTable>
|
||||
<pagination
|
||||
v-show="tableData.total > 0"
|
||||
:total="tableData.total"
|
||||
v-model:page="tableData.param.pageNum"
|
||||
v-model:limit="tableData.param.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
<ModalForm
|
||||
v-model:visible="showDialog"
|
||||
:title="formTitle"
|
||||
:fields="formFields"
|
||||
v-model:modelValue="formData"
|
||||
:type="formType"
|
||||
:show-footer="true"
|
||||
:label-width="'120px'"
|
||||
:width="'50%'"
|
||||
@submit="handleFormSubmit"
|
||||
@cancel="handleCancel"
|
||||
ref="modalFormRef"
|
||||
>
|
||||
</ModalForm>
|
||||
<AuditForm
|
||||
ref="auditFormRef"
|
||||
v-model="showAuditDialog"
|
||||
title="审核数据"
|
||||
@submit="onAuditSubmit"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { toRefs, reactive, onMounted, ref, computed, toRaw } from 'vue';
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import { listGeography, delGeography, addGeography, updateGeography, auditGeography } from './api';
|
||||
import { GeographyTableColumns, GeographyInfoData, GeographyTableDataState } from './type';
|
||||
|
||||
import { getUserList } from '/@/api/system/user/index';
|
||||
import { UserItem, VersionMap } from '/@/types';
|
||||
import { parseTime } from '/@/utils/gfast';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { listSpeciesName } from '../speciesName/api';
|
||||
|
||||
import { QueryFormField, TableColumn, PopupFormField } from '/@/components/dynamicpage/type';
|
||||
import QueryForm from '/@/components/dynamicpage/queryForm/index.vue';
|
||||
import ProTable from '/@/components/dynamicpage/ProTable/index.vue';
|
||||
import ModalForm from '/@/components/dynamicpage/modalForm/index.vue';
|
||||
import AuditForm from '/@/components/dynamicpage/auditForm/index.vue';
|
||||
import {SpeciesNameInfoData} from '../speciesName/type'
|
||||
defineOptions({ name: 'BusinessesGeographyList' });
|
||||
|
||||
const loading = ref(false);
|
||||
// 非单个禁用
|
||||
const single = ref(true);
|
||||
// 非多个禁用
|
||||
const multiple = ref(true);
|
||||
const userOptions = ref<UserItem[]>([]);
|
||||
|
||||
const state = reactive<GeographyTableDataState>({
|
||||
ids: [],
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
param: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
},
|
||||
});
|
||||
const versionMap = ref<VersionMap>({} as VersionMap);
|
||||
const proTableRef = ref();
|
||||
const { tableData } = toRefs(state);
|
||||
const columns: TableColumn[] = [
|
||||
{ label: '物种编码', prop: 'speciesCode' },
|
||||
{ label: '地理分布描述', prop: 'distributionInfo', minWidth: 150 },
|
||||
{ label: '原产地描述', prop: 'originInfo', minWidth: 150 },
|
||||
{ label: '国外分布描述', prop: 'abroadInfo', minWidth: 150 },
|
||||
{ label: '国内分布描述', prop: 'domesticInfo', minWidth: 150 },
|
||||
{
|
||||
label: '数据采集人',
|
||||
prop: 'createUser',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
prop: 'createDate',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(_, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查人',
|
||||
prop: 'auditUser',
|
||||
isFormater: true,
|
||||
minWidth: 120,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查日期',
|
||||
prop: 'auditDate',
|
||||
minWidth: 120,
|
||||
isFormater: true,
|
||||
formater(_, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'auditStatus',
|
||||
isFormater: true,
|
||||
formater(row, column, cellValue, index) {
|
||||
return cellValue == 0 ? '待审核' : cellValue == 1 ? '通过' : '不通过';
|
||||
},
|
||||
},
|
||||
{ label: '核查意见', prop: 'auditView' },
|
||||
{ label: '备注', prop: 'remark' },
|
||||
];
|
||||
|
||||
const onSearch = async (val: Record<string, any>) => {
|
||||
console.log(val);
|
||||
|
||||
let newVal: Record<string, any> = {};
|
||||
for (const v in val) {
|
||||
if (val[v]||val[v]===0) {
|
||||
newVal[v] = val[v];
|
||||
}
|
||||
}
|
||||
state.tableData.param = { ...state.tableData.param, ...newVal };
|
||||
getList();
|
||||
};
|
||||
const onReset = () => {
|
||||
state.tableData.param = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
getList();
|
||||
};
|
||||
const searchForm = ref<Partial<GeographyInfoData>>({
|
||||
speciesCode: undefined,
|
||||
createUser: undefined,
|
||||
createDate: undefined,
|
||||
auditUser: undefined,
|
||||
auditDate: undefined,
|
||||
auditStatus: undefined,
|
||||
});
|
||||
const searchFields = computed<QueryFormField[]>(() => [
|
||||
{ label: '物种编码', prop: 'speciesCode', type: 'input', placeholder: '请输入物种编码' },
|
||||
{
|
||||
label: '核查状态',
|
||||
prop: 'auditStatus',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: '待审核', value: 0 },
|
||||
{ label: '通过', value: 1 },
|
||||
{ label: '不通过', value: 2 },
|
||||
],
|
||||
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' },
|
||||
]);
|
||||
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initTableData();
|
||||
});
|
||||
// 初始化表格数据
|
||||
const initTableData = () => {
|
||||
getList();
|
||||
reqGetUserList();
|
||||
reqListSpeciesName();
|
||||
};
|
||||
// 获取列表数据
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listGeography(state.tableData.param);
|
||||
let list = res.data.list ?? [];
|
||||
state.tableData.data = list;
|
||||
versionMap.value = list.reduce((acc: any, cur: any) => {
|
||||
acc[cur.id] = cur.version;
|
||||
return acc;
|
||||
}, {});
|
||||
state.tableData.total = res.data.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const specieslist = ref<SpeciesNameInfoData[]>([]);
|
||||
/**获取物种列表 */
|
||||
const reqListSpeciesName = async () => {
|
||||
if (userOptions.value.length > 0) return;
|
||||
const res = await listSpeciesName({ pageSize: 9999, pageNum: 1 });
|
||||
specieslist.value = res.data.list;
|
||||
};
|
||||
|
||||
/**获取用户列表 */
|
||||
|
||||
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<GeographyInfoData>) => {
|
||||
state.ids = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
const showDialog = ref(false);
|
||||
const formTitle = ref('');
|
||||
const formFields = computed<PopupFormField[]>(() => [
|
||||
{
|
||||
label: '物种编码',
|
||||
prop: 'speciesCode',
|
||||
type: 'select',
|
||||
options: specieslist.value.map((i) => {
|
||||
return {
|
||||
value: i.speciesCode,
|
||||
label: i.speciesCode,
|
||||
};
|
||||
}),
|
||||
span: 24,
|
||||
rules: [{ required: true, message: '请输入物种编码', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择物种编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
label:"地理分布描述",
|
||||
prop:'distributionInfo',
|
||||
rules: [{ required: true, message: '请输入地理分布描述', trigger: 'blur' }],
|
||||
type:'input',
|
||||
span:24,
|
||||
componentProps:{
|
||||
type:'textarea',
|
||||
placeholder:'请输入地理分布描述'
|
||||
}
|
||||
},
|
||||
{
|
||||
label:"原产地描述",
|
||||
prop:'originInfo',
|
||||
type:'input',
|
||||
span:24,
|
||||
rules: [{ required: true, message: '请输入原产地描述', trigger: 'blur' }],
|
||||
componentProps:{
|
||||
type:'textarea',
|
||||
placeholder:'请输入原产地描述'
|
||||
}
|
||||
},
|
||||
{
|
||||
label:"国外分布描述",
|
||||
prop:'abroadInfo',
|
||||
type:'input',
|
||||
span:24,
|
||||
rules: [{ required: true, message: '请输入国外分布描述', trigger: 'blur' }],
|
||||
|
||||
componentProps:{
|
||||
type:'textarea',
|
||||
placeholder:'请输入国外分布描述'
|
||||
}
|
||||
},
|
||||
{
|
||||
label:"国内分布描述",
|
||||
prop:'domesticInfo',
|
||||
type:'input',
|
||||
span:24,
|
||||
rules: [{ required: true, message: '请输入国内分布描述', trigger: 'blur' }],
|
||||
componentProps:{
|
||||
type:'textarea',
|
||||
placeholder:'请输入国内分布描述'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '数据采集人',
|
||||
span: 12,
|
||||
prop: 'createUser',
|
||||
type: 'select',
|
||||
rules: [{ required: true, message: '请选择数据采集人', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集人',
|
||||
},
|
||||
options: userOptions.value.map((i) => {
|
||||
return {
|
||||
label: i.userNickname,
|
||||
value: i.id,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
span: 12,
|
||||
prop: 'createDate',
|
||||
type: 'date',
|
||||
rules: [{ required: true, message: '请选择数据采集日期', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集日期',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
span: 24,
|
||||
type: 'input',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
type: 'textarea',
|
||||
},
|
||||
},
|
||||
]);
|
||||
const formData = ref<Partial<GeographyInfoData>>({
|
||||
speciesCode: undefined,
|
||||
distributionInfo: undefined,
|
||||
originInfo: undefined,
|
||||
abroadInfo: undefined,
|
||||
domesticInfo: undefined,
|
||||
createUser: undefined,
|
||||
createDate: undefined,
|
||||
auditStatus: undefined,
|
||||
remark: undefined,
|
||||
});
|
||||
const formType = ref<'add' | 'edit'>('add');
|
||||
|
||||
const handleFormSubmit = (form: GeographyInfoData) => {
|
||||
if (formType.value === 'add') {
|
||||
addGeography(form).then(() => {
|
||||
ElMessage.success('新增成功');
|
||||
handleCancel();
|
||||
getList();
|
||||
});
|
||||
} else {
|
||||
form.auditStatus = 0;
|
||||
updateGeography(form).then(() => {
|
||||
ElMessage.success('编辑成功');
|
||||
handleCancel();
|
||||
getList();
|
||||
});
|
||||
}
|
||||
};
|
||||
const handleCancel = () => {
|
||||
showDialog.value = false;
|
||||
formTitle.value = '';
|
||||
formType.value = 'add';
|
||||
formData.value = {
|
||||
speciesCode: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '新增分类地位';
|
||||
formType.value = 'add';
|
||||
};
|
||||
const handleUpdate = (row: GeographyInfoData) => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '编辑分类地位';
|
||||
formType.value = 'edit';
|
||||
formData.value = cloneDeep(row);
|
||||
};
|
||||
const handleDelete = (row: GeographyTableColumns | 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(() => {
|
||||
delGeography(
|
||||
id,
|
||||
id.map((i) => versionMap.value[i])
|
||||
).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
getList();
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const auditFormRef = ref();
|
||||
const showAuditDialog = ref(false);
|
||||
const handleAudit = (row: GeographyTableColumns) => {
|
||||
auditFormRef.value.open(cloneDeep(row), userOptions.value);
|
||||
};
|
||||
const onAuditSubmit = (val: GeographyTableColumns) => {
|
||||
auditGeography(val).then(() => {
|
||||
ElMessage.success('审核成功');
|
||||
showAuditDialog.value = false;
|
||||
getList();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.colBlock {
|
||||
display: block;
|
||||
}
|
||||
.colNone {
|
||||
display: none;
|
||||
}
|
||||
.ml-2 {
|
||||
margin: 3px;
|
||||
}
|
||||
</style>
|
54
src/views/businesses/geography/type.ts
Normal file
54
src/views/businesses/geography/type.ts
Normal file
@ -0,0 +1,54 @@
|
||||
export interface GeographyTableColumns {
|
||||
id: number; //
|
||||
speciesCode: string; // 物种编码
|
||||
distributionInfo: string; // 地理分布描述
|
||||
originInfo: string; // 原产地描述
|
||||
abroadInfo: string; // 国外分布描述
|
||||
domesticInfo: string; // 国内分布描述
|
||||
createUser: number; // 数据采集人
|
||||
createDate: string; // 数据采集日期
|
||||
auditUser: number; // 数据核查人
|
||||
auditDate: string; // 数据核查日期
|
||||
auditStatus: number; // 核查状态
|
||||
auditView: string; // 核查意见
|
||||
remark: string; // 备注
|
||||
version: number; //
|
||||
createdAt: string; //
|
||||
}
|
||||
|
||||
export interface GeographyInfoData {
|
||||
id: number | undefined; //
|
||||
speciesCode: string | undefined; // 物种编码
|
||||
distributionInfo: string | undefined; // 地理分布描述
|
||||
originInfo: string | undefined; // 原产地描述
|
||||
abroadInfo: string | undefined; // 国外分布描述
|
||||
domesticInfo: string | undefined; // 国内分布描述
|
||||
createUser: number | undefined; // 数据采集人
|
||||
createDate: string | undefined; // 数据采集日期
|
||||
auditUser: number | undefined; // 数据核查人
|
||||
auditDate: string | undefined; // 数据核查日期
|
||||
auditStatus: number | undefined; // 核查状态
|
||||
auditView: string | undefined; // 核查意见
|
||||
remark: string | undefined; // 备注
|
||||
version: number | undefined; //
|
||||
}
|
||||
|
||||
export interface GeographyTableDataState {
|
||||
ids: any[];
|
||||
tableData: {
|
||||
data: Array<GeographyTableColumns>;
|
||||
total: number;
|
||||
loading: boolean;
|
||||
param: {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface GeographyEditState {
|
||||
loading: boolean;
|
||||
isShowDialog: boolean;
|
||||
formData: GeographyInfoData;
|
||||
rules: object;
|
||||
}
|
54
src/views/businesses/speciesName/api.ts
Normal file
54
src/views/businesses/speciesName/api.ts
Normal file
@ -0,0 +1,54 @@
|
||||
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[], version: number[]) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/speciesName/delete',
|
||||
method: 'delete',
|
||||
data: {
|
||||
ids: ids,
|
||||
version: version,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function auditSpeciesName(data:object) {
|
||||
return request({
|
||||
url: '/api/v1/businesses/speciesName/audit',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
505
src/views/businesses/speciesName/index.vue
Normal file
505
src/views/businesses/speciesName/index.vue
Normal file
@ -0,0 +1,505 @@
|
||||
<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
|
||||
v-if="columns.length > 0"
|
||||
ref="proTableRef"
|
||||
:columns="columns"
|
||||
:data="tableData.data"
|
||||
:loading="loading"
|
||||
:show-selection="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
:heightOffset="400"
|
||||
:action-width="280"
|
||||
:show-expand="true"
|
||||
>
|
||||
<template #expand="{ row }">
|
||||
<el-form-item label="核查意见">
|
||||
{{ row.auditView }}
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
{{ row.remark }}
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template #actions="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleUpdate(row)"
|
||||
size="small"
|
||||
v-auth="'api/v1/businesses/speciesName/edit'"
|
||||
v-if="row.auditStatus != 1"
|
||||
><el-icon><ele-EditPen /></el-icon>修改</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(row)"
|
||||
v-auth="'api/v1/businesses/speciesName/delete'"
|
||||
><el-icon><ele-DeleteFilled /></el-icon>删除</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="handleAudit(row)"
|
||||
v-if="row.auditStatus == 0"
|
||||
v-auth="'api/v1/businesses/speciesName/audit'"
|
||||
><el-icon><ele-Check /></el-icon>审核</el-button
|
||||
>
|
||||
</template>
|
||||
</ProTable>
|
||||
|
||||
<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>
|
||||
|
||||
<ModalForm
|
||||
v-model:visible="showDialog"
|
||||
:title="formTitle"
|
||||
:fields="formFields"
|
||||
v-model:modelValue="formData"
|
||||
:type="formType"
|
||||
:show-footer="true"
|
||||
:label-width="'120px'"
|
||||
:width="'50%'"
|
||||
@submit="handleFormSubmit"
|
||||
@cancel="handleCancel"
|
||||
ref="modalFormRef"
|
||||
>
|
||||
</ModalForm>
|
||||
|
||||
<AuditForm
|
||||
ref="auditFormRef"
|
||||
v-model="showAuditDialog"
|
||||
title="审核数据"
|
||||
@submit="onAuditSubmit"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { toRefs, reactive, onMounted, ref, computed } from 'vue';
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import {
|
||||
listSpeciesName,
|
||||
delSpeciesName,
|
||||
addSpeciesName,
|
||||
updateSpeciesName,
|
||||
auditSpeciesName,
|
||||
} from './api';
|
||||
import {
|
||||
SpeciesNameTableColumns,
|
||||
SpeciesNameInfoData,
|
||||
SpeciesNameTableDataState,
|
||||
} from '/@/views/businesses/speciesName/type';
|
||||
import QueryForm from '/@/components/dynamicpage/queryForm/index.vue';
|
||||
import ProTable from '/@/components/dynamicpage/ProTable/index.vue';
|
||||
import ModalForm from '/@/components/dynamicpage/modalForm/index.vue';
|
||||
import AuditForm from '/@/components/dynamicpage/auditForm/index.vue';
|
||||
import { QueryFormField, TableColumn, PopupFormField } from '/@/components/dynamicpage/type';
|
||||
import { getUserList } from '/@/api/system/user/index';
|
||||
import { UserItem, VersionMap } from '/@/types';
|
||||
import { parseTime } from '/@/utils/gfast';
|
||||
import { cloneDeep } from 'lodash';
|
||||
defineOptions({ name: 'apiV1DemoSpeciesNameList' });
|
||||
|
||||
const loading = ref(false);
|
||||
// 非单个禁用
|
||||
const single = ref(true);
|
||||
// 非多个禁用
|
||||
const multiple = ref(true);
|
||||
const userOptions = ref<UserItem[]>([]);
|
||||
|
||||
const state = reactive<SpeciesNameTableDataState>({
|
||||
ids: [],
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
param: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
},
|
||||
});
|
||||
const versionMap = ref<VersionMap>({} as VersionMap);
|
||||
const proTableRef = ref();
|
||||
const { tableData } = toRefs(state);
|
||||
const columns: TableColumn[] = [
|
||||
{ label: '物种编码', prop: 'speciesCode' },
|
||||
{ label: '物种名称', prop: 'name' },
|
||||
{ label: '物种名称内容', prop: 'content' },
|
||||
{ label: '数据来源', prop: 'sourcesData' },
|
||||
{
|
||||
label: '数据采集人',
|
||||
prop: 'createUser',
|
||||
isFormater: true,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
prop: 'createDate',
|
||||
isFormater: true,
|
||||
formater(_: SpeciesNameTableColumns, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查人',
|
||||
prop: 'auditUser',
|
||||
isFormater: true,
|
||||
formater(row, column, cellValue, index) {
|
||||
const user = userOptions.value.find((i) => i.id === cellValue);
|
||||
return user ? user.userNickname : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据核查日期',
|
||||
prop: 'auditDate',
|
||||
isFormater: true,
|
||||
formater(_: SpeciesNameTableColumns, col: any, val: string) {
|
||||
return parseTime(val, '{y}-{m}-{d}');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'auditStatus',
|
||||
isFormater: true,
|
||||
formater(row, column, cellValue, index) {
|
||||
return cellValue == 0 ? '待审核' : cellValue == 1 ? '通过' : '不通过';
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const onSearch = async (val: Record<string, any>) => {
|
||||
let newVal: Record<string, any> = {};
|
||||
for (const v in val) {
|
||||
if (val[v]) {
|
||||
newVal[v] = val[v];
|
||||
}
|
||||
}
|
||||
state.tableData.param = { ...state.tableData.param, ...newVal };
|
||||
speciesNameList();
|
||||
};
|
||||
const onReset = () => {
|
||||
state.tableData.param = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
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' },
|
||||
]);
|
||||
|
||||
// 页面加载时
|
||||
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;
|
||||
versionMap.value = list.reduce((acc: any, cur: any) => {
|
||||
acc[cur.id] = cur.version;
|
||||
return acc;
|
||||
}, {});
|
||||
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 showDialog = ref(false);
|
||||
const formTitle = ref('');
|
||||
const formFields = computed<PopupFormField[]>(() => [
|
||||
{
|
||||
label: '物种编码',
|
||||
prop: 'speciesCode',
|
||||
type: 'input',
|
||||
span: 12,
|
||||
rules: [{ required: true, message: '请输入物种编码', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入物种编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '物种名称',
|
||||
prop: 'name',
|
||||
span: 12,
|
||||
type: 'input',
|
||||
rules: [{ required: true, message: '请输入物种名称', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入物种名称',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '物种名称内容',
|
||||
prop: 'content',
|
||||
type: 'input',
|
||||
rules: [{ required: true, message: '请输入物种名称内容', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入物种名称内容',
|
||||
type: 'textarea',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据来源',
|
||||
prop: 'sourcesData',
|
||||
span: 24,
|
||||
type: 'input',
|
||||
rules: [{ required: true, message: '请输入数据来源', trigger: 'blur' }],
|
||||
componentProps: {
|
||||
placeholder: '请输入数据来源',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数据采集人',
|
||||
span: 12,
|
||||
prop: 'createUser',
|
||||
type: 'select',
|
||||
rules: [{ required: true, message: '请选择数据采集人', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集人',
|
||||
},
|
||||
options: userOptions.value.map((i) => {
|
||||
return {
|
||||
label: i.userNickname,
|
||||
value: i.id,
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: '数据采集日期',
|
||||
span: 12,
|
||||
prop: 'createDate',
|
||||
type: 'date',
|
||||
rules: [{ required: true, message: '请选择数据采集日期', trigger: 'change' }],
|
||||
componentProps: {
|
||||
placeholder: '请选择数据采集日期',
|
||||
},
|
||||
},
|
||||
// {
|
||||
// label: '数据核查人',
|
||||
// span: 12,
|
||||
// prop: 'auditUser',
|
||||
// type: 'select',
|
||||
// rules: [{ required: true, message: '请选择数据核查人', trigger: 'change' }],
|
||||
// componentProps: {
|
||||
// placeholder: '请选择数据核查人',
|
||||
// },
|
||||
// options: userOptions.value.map((i) => {
|
||||
// return {
|
||||
// label: i.userNickname,
|
||||
// value: i.id,
|
||||
// };
|
||||
// }),
|
||||
// },
|
||||
// {
|
||||
// label: '数据核查日期',
|
||||
// span: 12,
|
||||
// prop: 'auditDate',
|
||||
// type: 'date',
|
||||
// rules: [{ required: true, message: '请选择数据核查日期', trigger: 'change' }],
|
||||
// componentProps: {
|
||||
// placeholder: '请选择数据核查日期',
|
||||
// },
|
||||
// },
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
span: 24,
|
||||
type: 'input',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
type: 'textarea',
|
||||
},
|
||||
},
|
||||
]);
|
||||
const formData = ref<SpeciesNameInfoData>({
|
||||
id: undefined,
|
||||
speciesCode: undefined,
|
||||
name: undefined,
|
||||
content: undefined,
|
||||
sourcesData: undefined,
|
||||
createUser: undefined,
|
||||
createDate: undefined,
|
||||
auditUser: undefined,
|
||||
auditDate: undefined,
|
||||
remark: undefined,
|
||||
});
|
||||
const formType = ref<'add' | 'edit'>('add');
|
||||
|
||||
const handleFormSubmit = (form: SpeciesNameInfoData) => {
|
||||
if (formType.value === 'add') {
|
||||
addSpeciesName(form).then(() => {
|
||||
ElMessage.success('新增成功');
|
||||
handleCancel();
|
||||
speciesNameList();
|
||||
});
|
||||
} else {
|
||||
form.auditStatus = 0;
|
||||
updateSpeciesName(form).then(() => {
|
||||
ElMessage.success('编辑成功');
|
||||
handleCancel();
|
||||
speciesNameList();
|
||||
});
|
||||
}
|
||||
};
|
||||
const handleCancel = () => {
|
||||
showDialog.value = false;
|
||||
formTitle.value = '';
|
||||
formType.value = 'add';
|
||||
formData.value = {
|
||||
id: undefined,
|
||||
speciesCode: undefined,
|
||||
name: undefined,
|
||||
content: undefined,
|
||||
sourcesData: undefined,
|
||||
createUser: undefined,
|
||||
createDate: undefined,
|
||||
auditUser: undefined,
|
||||
auditDate: undefined,
|
||||
remark: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '新增物种名称';
|
||||
formType.value = 'add';
|
||||
};
|
||||
const handleUpdate = (row: SpeciesNameTableColumns) => {
|
||||
showDialog.value = true;
|
||||
formTitle.value = '编辑物种名称';
|
||||
formType.value = 'edit';
|
||||
formData.value = cloneDeep(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,
|
||||
id.map((i) => versionMap.value[i])
|
||||
).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
speciesNameList();
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const auditFormRef = ref();
|
||||
const showAuditDialog = ref(false);
|
||||
const handleAudit = (row: SpeciesNameTableColumns) => {
|
||||
auditFormRef.value.open(cloneDeep(row), userOptions.value);
|
||||
};
|
||||
const onAuditSubmit = (val: SpeciesNameTableColumns) => {
|
||||
auditSpeciesName(val).then(() => {
|
||||
ElMessage.success('审核成功');
|
||||
showAuditDialog.value = false;
|
||||
speciesNameList();
|
||||
});
|
||||
};
|
||||
</script>
|
46
src/views/businesses/speciesName/type.ts
Normal file
46
src/views/businesses/speciesName/type.ts
Normal file
@ -0,0 +1,46 @@
|
||||
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; // 备注
|
||||
auditStatus?: number | undefined; // 审核状态
|
||||
}
|
||||
|
||||
export interface SpeciesNameTableDataState {
|
||||
ids: any[];
|
||||
tableData: {
|
||||
data: Array<SpeciesNameTableColumns>;
|
||||
total: number;
|
||||
loading: boolean;
|
||||
param: {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface SpeciesNameEditState {
|
||||
loading: boolean;
|
||||
isShowDialog: boolean;
|
||||
formData: SpeciesNameInfoData;
|
||||
rules: object;
|
||||
}
|
@ -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'})
|
||||
}
|
||||
},
|
||||
})
|
@ -117,7 +117,7 @@ const state = reactive({
|
||||
isShowPassword: false,
|
||||
ruleForm: {
|
||||
username: 'demo',
|
||||
password: '123456',
|
||||
password: 'Demo123',
|
||||
verifyCode: '',
|
||||
verifyKey:''
|
||||
},
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -1,164 +0,0 @@
|
||||
<template>
|
||||
<div class="notice-bar-container">
|
||||
<el-card shadow="hover" header="滚动通知栏:默认">
|
||||
<NoticeBar
|
||||
text="🎉🎉🔥基于vue3.x 、Typescript、vite、Element 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 、Typescript、vite、Element 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: '通知栏模式(mode)closeable 时回调事件',
|
||||
a3: 'function',
|
||||
a4: '',
|
||||
},
|
||||
{
|
||||
a1: 'link',
|
||||
a2: '通知栏模式(mode)link 时回调事件',
|
||||
a3: 'function',
|
||||
a4: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
return {
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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">已绑定QQ:110****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>
|
@ -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',
|
||||
},
|
||||
];
|
@ -2,6 +2,9 @@
|
||||
<div class="system-edit-dic-container">
|
||||
<el-dialog :title="(ruleForm.dictId!==0?'修改':'添加')+'字典'" v-model="isShowDialog" width="769px">
|
||||
<el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="90px">
|
||||
<el-form-item label="上级" prop="pid">
|
||||
<el-cascader v-model="ruleForm.pid" :options="dictTypeOpt" :props="typeProps" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="字典名称" prop="dictName">
|
||||
<el-input v-model="ruleForm.dictName" placeholder="请输入字典名称" />
|
||||
</el-form-item>
|
||||
@ -29,11 +32,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, toRefs, defineComponent,ref, unref } from 'vue';
|
||||
import { getType,addType,editType } from '/@/api/system/dict/type';
|
||||
import { reactive, toRefs, ref, unref, getCurrentInstance } from 'vue';
|
||||
import { getType, addType, editType, optionselect } from '/@/api/system/dict/type';
|
||||
import {ElMessage} from "element-plus";
|
||||
interface RuleFormState {
|
||||
dictId:number;
|
||||
pid:number;
|
||||
dictName:string;
|
||||
dictType:string;
|
||||
status:number;
|
||||
@ -45,12 +49,22 @@ interface DicState {
|
||||
rules:{}
|
||||
}
|
||||
defineOptions({ name: "systemEditDic"})
|
||||
const {proxy} = getCurrentInstance() as any;
|
||||
const emit = defineEmits(['typeList']);
|
||||
const formRef = ref<HTMLElement | null>(null);
|
||||
const dictTypeOpt = ref<RuleFormState>()
|
||||
const typeProps = ref({
|
||||
value: 'dictId',
|
||||
label: 'dictName',
|
||||
children: 'children',
|
||||
checkStrictly:true,
|
||||
emitPath: false
|
||||
})
|
||||
const state = reactive<DicState>({
|
||||
isShowDialog: false,
|
||||
ruleForm: {
|
||||
dictId:0,
|
||||
pid:0,
|
||||
dictName:'',
|
||||
dictType:'',
|
||||
status:1,
|
||||
@ -66,9 +80,16 @@ const state = reactive<DicState>({
|
||||
}
|
||||
});
|
||||
const { isShowDialog,ruleForm,rules } = toRefs(state);
|
||||
const getParent = () => {
|
||||
optionselect(true).then((res:any)=>{
|
||||
const data = res.data.dictType??[]
|
||||
dictTypeOpt.value = proxy.handleTree(data, 'dictId', 'pid', 'children', true)
|
||||
})
|
||||
}
|
||||
// 打开弹窗
|
||||
const openDialog = (row: RuleFormState|null) => {
|
||||
resetForm();
|
||||
getParent();
|
||||
if (row){
|
||||
getType(row.dictId).then((res:any)=>{
|
||||
state.ruleForm = res.data.dictType
|
||||
@ -81,6 +102,7 @@ defineExpose({ openDialog})
|
||||
const resetForm = ()=>{
|
||||
state.ruleForm = {
|
||||
dictId:0,
|
||||
pid:0,
|
||||
dictName:'',
|
||||
dictType:'',
|
||||
status:1,
|
||||
|
@ -2,8 +2,8 @@
|
||||
<div class="system-edit-dic-container">
|
||||
<el-dialog :title="(ruleForm.dictCode!==0?'修改':'添加')+'字典'" v-model="isShowDialog" width="769px">
|
||||
<el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="90px">
|
||||
<el-form-item label="字典类型">
|
||||
<el-input v-model="ruleForm.dictType" :disabled="true" />
|
||||
<el-form-item label="字典类型" prop="dictType">
|
||||
<el-cascader v-model="ruleForm.dictType" :options="dictTypeOpt" :props="typeProps" clearable :show-all-levels="false"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="数据标签" prop="dictLabel">
|
||||
<el-input v-model="ruleForm.dictLabel" placeholder="请输入数据标签" />
|
||||
@ -45,9 +45,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, toRefs, defineComponent,ref, unref } from 'vue';
|
||||
import { reactive, toRefs, ref, unref, getCurrentInstance } from 'vue';
|
||||
import { getData,addData,editData } from '/@/api/system/dict/data';
|
||||
import {ElMessage} from "element-plus";
|
||||
import { optionselect } from '/@/api/system/dict/type';
|
||||
interface RuleFormState {
|
||||
dictCode: number;
|
||||
dictLabel: string;
|
||||
@ -64,6 +65,7 @@ interface DicState {
|
||||
rules:{}
|
||||
}
|
||||
defineOptions({ name: "systemEditDicData"})
|
||||
const {proxy} = getCurrentInstance() as any;
|
||||
const prop = defineProps({
|
||||
dictType:{
|
||||
type:String,
|
||||
@ -72,6 +74,14 @@ const prop = defineProps({
|
||||
})
|
||||
const emit = defineEmits(['dataList']);
|
||||
const formRef = ref<HTMLElement | null>(null);
|
||||
const dictTypeOpt = ref<RuleFormState>()
|
||||
const typeProps = ref({
|
||||
value: 'dictType',
|
||||
label: 'dictName',
|
||||
children: 'children',
|
||||
emitPath: false,
|
||||
checkStrictly:true
|
||||
})
|
||||
const state = reactive<DicState>({
|
||||
isShowDialog: false,
|
||||
ruleForm: {
|
||||
@ -85,6 +95,9 @@ const state = reactive<DicState>({
|
||||
dictType:prop.dictType
|
||||
},
|
||||
rules: {
|
||||
dictType:[
|
||||
{ required: true, message: "请选择字典类型", trigger: "change" }
|
||||
],
|
||||
dictLabel: [
|
||||
{ required: true, message: "数据标签不能为空", trigger: "blur" }
|
||||
],
|
||||
@ -97,9 +110,16 @@ const state = reactive<DicState>({
|
||||
}
|
||||
});
|
||||
const { isShowDialog,ruleForm,rules } = toRefs(state);
|
||||
const getTypeOpt = () => {
|
||||
optionselect(true).then((res:any)=>{
|
||||
const data = res.data.dictType??[]
|
||||
dictTypeOpt.value = proxy.handleTree(data, 'dictId', 'pid', 'children', true)
|
||||
})
|
||||
}
|
||||
// 打开弹窗
|
||||
const openDialog = (row: RuleFormState|null) => {
|
||||
resetForm();
|
||||
getTypeOpt()
|
||||
resetForm()
|
||||
if (row){
|
||||
getData(row.dictCode).then((res:any)=>{
|
||||
state.ruleForm = res.data.dict
|
||||
|
@ -64,7 +64,7 @@
|
||||
<el-table-column label="字典标签" align="center" prop="dictLabel" />
|
||||
<el-table-column label="字典键值" align="center" prop="dictValue" />
|
||||
<el-table-column label="字典排序" align="center" prop="dictSort" />
|
||||
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="字典类型" align="center" prop="dictType" />
|
||||
<el-table-column label="创建时间" align="center" prop="createdAt" width="180"/>
|
||||
<el-table-column prop="status" label="字典状态" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
@ -87,12 +87,12 @@
|
||||
@pagination="dataList"
|
||||
/>
|
||||
</el-card>
|
||||
<EditDic ref="editDicRef" @dataList="dataList" :dict-type="tableData.param.dictType"/>
|
||||
<EditDic ref="editDicRef" @dataList="dataList" :dict-type="selectedTypeCode"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue';
|
||||
import { toRefs, reactive, onMounted, ref } from 'vue';
|
||||
import { ElMessageBox, ElMessage,FormInstance} from 'element-plus';
|
||||
import EditDic from '/@/views/system/dict/component/editDicData.vue';
|
||||
import {getDataList,deleteData} from "/@/api/system/dict/data";
|
||||
@ -121,14 +121,15 @@ interface TableDataState {
|
||||
dictType: string;
|
||||
dictLabel:string;
|
||||
status: string;
|
||||
typeId:number;
|
||||
};
|
||||
};
|
||||
}
|
||||
defineOptions({ name: "apiV1SystemDictDataList"})
|
||||
const route = useRoute();
|
||||
const addDicRef = ref();
|
||||
const editDicRef = ref();
|
||||
const queryRef = ref();
|
||||
const selectedTypeCode = ref("");
|
||||
const state = reactive<TableDataState>({
|
||||
ids:[],
|
||||
tableData: {
|
||||
@ -140,13 +141,16 @@ const state = reactive<TableDataState>({
|
||||
pageSize: 10,
|
||||
dictLabel:'',
|
||||
dictType:'',
|
||||
status:''
|
||||
status:'',
|
||||
typeId:0
|
||||
},
|
||||
},
|
||||
});
|
||||
const { tableData } = toRefs(state);
|
||||
// 初始化表格数据
|
||||
const initTableData = () => {
|
||||
const initTableData = (typeId?: number,code?:string) => {
|
||||
state.tableData.param.typeId = typeId as number;
|
||||
selectedTypeCode.value = code as string;
|
||||
dataList()
|
||||
};
|
||||
const dataList=()=>{
|
||||
@ -206,4 +210,5 @@ const resetQuery = (formEl: FormInstance | undefined) => {
|
||||
const handleSelectionChange = (selection:TableDataRow[])=> {
|
||||
state.ids = selection.map(item => item.dictCode)
|
||||
};
|
||||
defineExpose({initTableData})
|
||||
</script>
|
||||
|
@ -1,183 +1,114 @@
|
||||
<template>
|
||||
<div class="system-dic-container">
|
||||
<el-row :gutter="10" style="width: 100%;">
|
||||
<el-col :span="5">
|
||||
<el-card shadow="hover">
|
||||
<div class="system-user-search mb15">
|
||||
<el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="字典名称" prop="dictName">
|
||||
<el-input
|
||||
v-model="tableData.param.dictName"
|
||||
placeholder="请输入字典名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter.native="typeList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="字典类型" prop="dictType">
|
||||
<el-input
|
||||
v-model="tableData.param.dictType"
|
||||
placeholder="请输入字典类型"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter.native="typeList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status" style="width: 200px;">
|
||||
<el-select
|
||||
v-model="tableData.param.status"
|
||||
placeholder="字典状态"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
>
|
||||
<el-option label="启用" :value="1"/>
|
||||
<el-option label="禁用" :value="0"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" prop="dateRange">
|
||||
<el-date-picker
|
||||
v-model="tableData.param.dateRange"
|
||||
style="width: 240px"
|
||||
value-format="YYYY-MM-DD"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button size="default" type="primary" class="ml10" @click="typeList">
|
||||
<el-icon>
|
||||
<ele-Search />
|
||||
</el-icon>
|
||||
查询
|
||||
</el-button>
|
||||
<el-button size="default" @click="resetQuery(queryRef)">
|
||||
<el-icon>
|
||||
<ele-Refresh />
|
||||
</el-icon>
|
||||
重置
|
||||
</el-button>
|
||||
<el-button size="default" type="success" class="ml10" @click="onOpenAddDic">
|
||||
<el-aside style="width: 100%;">
|
||||
<el-scrollbar>
|
||||
<div class="act-btn">
|
||||
<el-button size="default" type="success" class="ml10 btm8" @click="onOpenAddDic">
|
||||
<el-icon>
|
||||
<ele-FolderAdd />
|
||||
</el-icon>
|
||||
新增字典
|
||||
新增
|
||||
</el-button>
|
||||
<el-button size="default" type="danger" class="ml10" @click="onRowDel(null)">
|
||||
<el-button size="default" type="primary" class="ml10 btm8" @click="onOpenEditDic" :disabled="selectedNode===null">
|
||||
<el-icon>
|
||||
<ele-Edit />
|
||||
</el-icon>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button size="default" type="danger" class="ml10 btm8" @click="onRowDel(null)" :disabled="checkedNodes.length===0">
|
||||
<el-icon>
|
||||
<ele-Delete />
|
||||
</el-icon>
|
||||
删除字典
|
||||
删除
|
||||
</el-button>
|
||||
<el-button size="default" type="warning" class="ml10 btm8" @click="expandedOn">
|
||||
<el-icon>
|
||||
<ele-DCaret />
|
||||
</el-icon>
|
||||
{{expanded?'收起':'展开'}}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-table :data="tableData.data" style="width: 100%" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="字典ID" align="center" prop="dictId" width="120"/>
|
||||
<el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
|
||||
<template #default="scope">
|
||||
<router-link :to="'/system/dict/data/list/' + scope.row.dictType" class="link-type">
|
||||
<span>{{ scope.row.dictType }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="字典状态" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-tag type="success" v-if="scope.row.status">启用</el-tag>
|
||||
<el-tag type="info" v-else>禁用</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="字典描述" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="createdAt" label="创建时间" show-overflow-tooltip width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="200">
|
||||
<template #default="scope">
|
||||
<el-button size="small" text type="primary" @click="onOpenEditDic(scope.row)">修改</el-button>
|
||||
<el-button size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="tableData.total>0"
|
||||
:total="tableData.total"
|
||||
v-model:page="tableData.param.pageNum"
|
||||
v-model:limit="tableData.param.pageSize"
|
||||
@pagination="typeList"
|
||||
<el-divider />
|
||||
<el-input :prefix-icon="search" v-model="filterText" placeholder="请输入字典名称" clearable style="margin-bottom: 8px;"/>
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
class="filter-tree"
|
||||
:data="dictTypeData"
|
||||
:props="treeProps"
|
||||
:filter-node-method="filterNode"
|
||||
@node-click="handleNodeClick"
|
||||
show-checkbox
|
||||
@check-change="handleCheckChange"
|
||||
node-key="dictId"
|
||||
:check-on-click-leaf="false"
|
||||
/>
|
||||
</el-scrollbar>
|
||||
</el-aside>
|
||||
</el-card>
|
||||
<EditDic ref="editDicRef" @typeList="typeList"/>
|
||||
</el-col>
|
||||
<el-col :span="19">
|
||||
<apiV1SystemDictDataList ref="dataViewRef"></apiV1SystemDictDataList>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<EditDic ref="editDicRef" @typeList="getTypeData"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue';
|
||||
import { ElMessageBox, ElMessage,FormInstance} from 'element-plus';
|
||||
import { onMounted, ref, getCurrentInstance, watch } from 'vue';
|
||||
import { ElMessageBox, ElMessage, ElTree } from 'element-plus';
|
||||
import EditDic from '/@/views/system/dict/component/editDic.vue';
|
||||
import {deleteType, getTypeList} from "/@/api/system/dict/type";
|
||||
|
||||
|
||||
import { deleteType, optionselect } from '/@/api/system/dict/type';
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import apiV1SystemDictDataList from '/@/views/system/dict/dataList.vue'
|
||||
// 定义接口来定义对象的类型
|
||||
interface TableDataRow {
|
||||
dictId:number;
|
||||
pid:number;
|
||||
dictName: string;
|
||||
dictType: string;
|
||||
status: number;
|
||||
remark:string;
|
||||
createdAt:string;
|
||||
}
|
||||
interface TableDataState {
|
||||
ids:number[];
|
||||
tableData: {
|
||||
data: Array<TableDataRow>;
|
||||
total: number;
|
||||
loading: boolean;
|
||||
param: {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
dictName: string;
|
||||
dictType: string;
|
||||
status: string;
|
||||
dateRange:string[];
|
||||
};
|
||||
};
|
||||
}
|
||||
defineOptions({ name: "systemDic"})
|
||||
const addDicRef = ref();
|
||||
defineOptions({ name: "apiV1SystemDictTypeList"})
|
||||
const search = Search
|
||||
const filterText = ref('');
|
||||
const treeRef = ref()
|
||||
const {proxy} = getCurrentInstance() as any;
|
||||
const editDicRef = ref();
|
||||
const queryRef = ref();
|
||||
const state = reactive<TableDataState>({
|
||||
ids:[],
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
param: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
dictName:'',
|
||||
dictType:'',
|
||||
status:'',
|
||||
dateRange:[],
|
||||
},
|
||||
},
|
||||
});
|
||||
const { tableData } = toRefs(state);
|
||||
const dictTypeData = ref([])
|
||||
const selectedNode = ref<TableDataRow|null>(null)
|
||||
const checkedNodes = ref<TableDataRow[]>([])
|
||||
const expanded = ref<boolean>(false)
|
||||
const dataViewRef = ref()
|
||||
const treeProps = ref({
|
||||
value: 'dictId',
|
||||
label: 'dictName',
|
||||
children: 'children',
|
||||
checkStrictly:true,
|
||||
emitPath: false
|
||||
})
|
||||
const getTypeData = () => {
|
||||
optionselect(true).then((res:any)=>{
|
||||
const data = res.data.dictType??[]
|
||||
dictTypeData.value = proxy.handleTree(data, 'dictId', 'pid', 'children', true)
|
||||
})
|
||||
}
|
||||
// 初始化表格数据
|
||||
const initTableData = () => {
|
||||
typeList()
|
||||
};
|
||||
const typeList=()=>{
|
||||
getTypeList(state.tableData.param).then((res:any)=>{
|
||||
state.tableData.data = res.data.dictTypeList;
|
||||
state.tableData.total = res.data.total;
|
||||
});
|
||||
getTypeData()
|
||||
};
|
||||
// 打开新增字典弹窗
|
||||
const onOpenAddDic = () => {
|
||||
editDicRef.value.openDialog();
|
||||
};
|
||||
// 打开修改字典弹窗
|
||||
const onOpenEditDic = (row: TableDataRow) => {
|
||||
const onOpenEditDic = () => {
|
||||
const row = selectedNode.value;
|
||||
editDicRef.value.openDialog(row);
|
||||
};
|
||||
// 删除字典
|
||||
@ -188,7 +119,9 @@ const onRowDel = (row: TableDataRow|null) => {
|
||||
msg = `此操作将永久删除用户:“${row.dictName}”,是否继续?`
|
||||
ids = [row.dictId]
|
||||
}else{
|
||||
ids = state.ids
|
||||
checkedNodes.value.forEach(item=>{
|
||||
ids.push(item.dictId);
|
||||
})
|
||||
}
|
||||
if(ids.length===0){
|
||||
ElMessage.error('请选择要删除的数据。');
|
||||
@ -202,7 +135,8 @@ const onRowDel = (row: TableDataRow|null) => {
|
||||
.then(() => {
|
||||
deleteType(ids).then(()=>{
|
||||
ElMessage.success('删除成功');
|
||||
typeList();
|
||||
getTypeData()
|
||||
checkedNodes.value = []
|
||||
})
|
||||
})
|
||||
.catch(() => {});
|
||||
@ -211,15 +145,47 @@ const onRowDel = (row: TableDataRow|null) => {
|
||||
onMounted(() => {
|
||||
initTableData();
|
||||
});
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
typeList()
|
||||
const filterNode = (value: string, data:any) => {
|
||||
if (!value) return true;
|
||||
return data.dictName.includes(value)
|
||||
};
|
||||
// 多选框选中数据
|
||||
const handleSelectionChange = (selection:TableDataRow[])=> {
|
||||
state.ids = selection.map(item => item.dictId)
|
||||
// 节点单击事件
|
||||
const handleNodeClick = (data:TableDataRow) => {
|
||||
selectedNode.value = data
|
||||
dataViewRef.value.initTableData(data.dictId,data.dictType)
|
||||
};
|
||||
|
||||
const handleCheckChange = (
|
||||
data: TableDataRow,
|
||||
checked: boolean,
|
||||
) => {
|
||||
if(checked){
|
||||
checkedNodes.value.push(data)
|
||||
}else{
|
||||
checkedNodes.value = checkedNodes.value.filter((item:TableDataRow) => {
|
||||
if(item.dictId!==data.dictId){
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
}
|
||||
const expandedOn = ()=>{
|
||||
expanded.value = !expanded.value
|
||||
let treeList = dictTypeData.value as Array<TableDataRow>;
|
||||
for (let i = 0; i < treeList.length; i++) {
|
||||
treeRef.value.store.nodesMap[treeList[i].dictId].expanded = expanded.value;
|
||||
}
|
||||
}
|
||||
watch(filterText, (val) => {
|
||||
treeRef.value!.filter(val)
|
||||
});
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.btm8{margin-bottom: 8px;}
|
||||
.filter-tree{
|
||||
height: calc(100vh - 290px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
@ -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">已绑定QQ:110****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>
|
||||
|
@ -32,10 +32,10 @@
|
||||
<el-form-item label="状态">{{ proxy.getOptionValue(formData.status, statusOptions,'value','label') }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="创建者">{{ formData.createdUser.userNickname }}</el-form-item>
|
||||
<el-form-item label="创建者">{{ formData.createdUser?.userNickname }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="更新者">{{ formData.updatedUser.userNickname }}</el-form-item>
|
||||
<el-form-item label="更新者">{{ formData.updatedUser?.userNickname }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="备注信息">{{ formData.remark }}</el-form-item>
|
||||
@ -51,9 +51,8 @@
|
||||
class="btn-del"
|
||||
type="danger"
|
||||
size="small"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete(null)"
|
||||
><el-icon><ele-Delete /></el-icon>删除</el-button>
|
||||
@click="handleDelete"
|
||||
><el-icon><ele-Delete /></el-icon>清空日志</el-button>
|
||||
<el-divider />
|
||||
<el-table v-loading="logList.loading" :data="logList.data" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
@ -203,31 +202,16 @@ const handleSelectionChange = (selection:Array<SysJobLogData>) => {
|
||||
logList.logIds = selection.map(item => item.id)
|
||||
multiple.value = !selection.length
|
||||
};
|
||||
const handleDelete = (row: SysJobLogData) => {
|
||||
let msg = '你确定要删除所选数据?';
|
||||
let logId:number[] = [] ;
|
||||
let targetName:string='';
|
||||
if(row){
|
||||
msg = `此操作将永久删除数据,是否继续?`
|
||||
logId = [row.id]
|
||||
targetName = row.targetName
|
||||
}else{
|
||||
logId = logList.logIds
|
||||
targetName=state.formData.invokeTarget!
|
||||
}
|
||||
if(logId.length===0){
|
||||
ElMessage.error('请选择要删除的数据。');
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm(msg, '提示', {
|
||||
const handleDelete = () => {
|
||||
ElMessageBox.confirm('你确定要清空日志?', '提示', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
delSysJobLog(logId).then(()=>{
|
||||
delSysJobLog(logList.param.targetName!).then(()=>{
|
||||
ElMessage.success('删除成功');
|
||||
getLogList(targetName);
|
||||
getLogList(logList.param.targetName!);
|
||||
})
|
||||
})
|
||||
.catch(() => {});
|
||||
|
@ -172,12 +172,7 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="字典类型" width="160">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.dictType" clearable filterable placeholder="请选择">
|
||||
<el-option v-for="dict in dictOptions" :key="dict.dictType" :label="dict.dictName" :value="dict.dictType">
|
||||
<span style="float: left">{{ dict.dictName }}</span>
|
||||
<span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictType }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-cascader v-model="scope.row.dictType" :options="dictOptions" :props="typeProps" clearable :show-all-levels="false"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关联表" width="160">
|
||||
@ -205,23 +200,31 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { inject, onBeforeMount, ref} from 'vue';
|
||||
import { getCurrentInstance, inject, onBeforeMount, ref } from 'vue';
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import {DictOpt, TableColumns, TableDataInfo} from '/@/views/system/tools/gen/component/model';
|
||||
import {DictOpt, TableColumns} from '/@/views/system/tools/gen/component/model';
|
||||
import {optionselect} from "/@/api/system/dict/type";
|
||||
import RelationTable from "/@/views/system/tools/gen/component/relationTable.vue";
|
||||
import _ from "lodash";
|
||||
defineOptions({ name: "genTableColumns"})
|
||||
const {proxy} = getCurrentInstance() as any;
|
||||
const relationTableRef = ref();
|
||||
const tableColumnsRef = ref<FormInstance>();
|
||||
const info = inject<any>('tableData');
|
||||
// 表格的高度
|
||||
const tableHeight = ref(document.documentElement.scrollHeight - 300 + 'px');
|
||||
const dictOptions = ref(<DictOpt[]>[])
|
||||
const typeProps = ref({
|
||||
value: 'dictType',
|
||||
label: 'dictName',
|
||||
children: 'children',
|
||||
emitPath: false
|
||||
})
|
||||
onBeforeMount(()=>{
|
||||
//获取字典选项
|
||||
optionselect().then((res:any)=>{
|
||||
dictOptions.value = res.data.dictType??[]
|
||||
const data = res.data.dictType??[]
|
||||
dictOptions.value = proxy.handleTree(data, 'dictId', 'pid', 'children', true)
|
||||
})
|
||||
})
|
||||
const handleChangeConfig = (row:TableColumns)=>{
|
||||
|
@ -102,7 +102,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import {toRefs, reactive, onMounted, ref, defineComponent} from 'vue';
|
||||
import {ElMessageBox, ElMessage, FormInstance} from 'element-plus';
|
||||
import {ElMessageBox, ElMessage, FormInstance,ElLoading } from 'element-plus';
|
||||
import {getTableList, deleteTables, batchGenCode, syncTable} from "/@/api/system/tools/gen";
|
||||
import {TableData,TableDataState} from "/@/views/system/tools/gen/component/model"
|
||||
import importTable from "/@/views/system/tools/gen/component/importTable.vue";
|
||||
@ -220,10 +220,13 @@ const handleGenTable=(row: TableData|null)=>{
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
const loading = ElLoading.service({text:'生成中...'})
|
||||
batchGenCode(ids).then(()=>{
|
||||
ElMessage.success('生成成功');
|
||||
resetMenuSession()
|
||||
tableList();
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
})
|
||||
.catch(() => {});
|
||||
|
@ -102,7 +102,7 @@
|
||||
<script setup lang="ts">
|
||||
import {toRefs, reactive, onMounted, ref, watch, getCurrentInstance} from 'vue';
|
||||
import {ElTree,FormInstance} from 'element-plus';
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import UserList from '/@/views/system/user/component/userList.vue';
|
||||
import {getDeptTree} from '/@/api/system/user';
|
||||
|
||||
|
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 |
@ -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: '西乡街道,隶属于广东省深圳市宝安区,位于宝安区西南部,东接石岩街道,南接新安街道,西至珠江口岸边,北接航城街道。',
|
||||
},
|
||||
];
|
@ -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,
|
||||
},
|
||||
];
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user