├── .env.example
├── .eslintrc.json
├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── index.html
├── package.json
├── postcss.config.js
├── public
└── static
│ └── config.js
├── src
├── App.vue
├── assets
│ ├── 404.png
│ ├── login-left.png
│ └── logo.png
├── components
│ ├── 404
│ │ └── index.vue
│ ├── admin
│ │ ├── buttons
│ │ │ ├── add.vue
│ │ │ ├── destroy.vue
│ │ │ ├── show.vue
│ │ │ └── update.vue
│ │ ├── dialog
│ │ │ └── index.vue
│ │ ├── icons
│ │ │ └── index.vue
│ │ ├── paginate
│ │ │ └── index.vue
│ │ ├── select
│ │ │ └── index.vue
│ │ ├── status
│ │ │ └── index.vue
│ │ ├── table
│ │ │ ├── operate.vue
│ │ │ └── search.vue
│ │ └── upload
│ │ │ ├── index.vue
│ │ │ └── oss.vue
│ ├── breadcrumbs
│ │ └── index.vue
│ ├── catchForm
│ │ ├── CatchForm.vue
│ │ ├── Disabled.vue
│ │ ├── FormItem.vue
│ │ ├── FormRender.vue
│ │ ├── components
│ │ │ ├── Alert
│ │ │ │ └── index.ts
│ │ │ ├── Button
│ │ │ │ ├── Button.vue
│ │ │ │ └── index.ts
│ │ │ ├── Card
│ │ │ │ ├── Card.vue
│ │ │ │ └── index.ts
│ │ │ ├── Cascader
│ │ │ │ ├── Cascader.vue
│ │ │ │ └── index.ts
│ │ │ ├── Checkbox
│ │ │ │ ├── Checkbox.vue
│ │ │ │ └── index.ts
│ │ │ ├── Collapse
│ │ │ │ ├── Collapse.vue
│ │ │ │ └── index.ts
│ │ │ ├── ColorPicker
│ │ │ │ ├── ColorPicker.vue
│ │ │ │ └── index.ts
│ │ │ ├── Custom
│ │ │ │ ├── Custom.vue
│ │ │ │ └── index.ts
│ │ │ ├── DatePicker
│ │ │ │ └── index.ts
│ │ │ ├── Divider
│ │ │ │ ├── Divider.vue
│ │ │ │ └── index.ts
│ │ │ ├── FormList
│ │ │ │ ├── FormList.vue
│ │ │ │ └── index.ts
│ │ │ ├── Gird
│ │ │ │ ├── Grid.vue
│ │ │ │ └── index.ts
│ │ │ ├── IconSelect
│ │ │ │ ├── IconSelect.vue
│ │ │ │ └── index.ts
│ │ │ ├── Inline
│ │ │ │ ├── Inline.vue
│ │ │ │ └── index.ts
│ │ │ ├── Input
│ │ │ │ └── index.ts
│ │ │ ├── InputNumber
│ │ │ │ ├── InputNumber.vue
│ │ │ │ └── index.ts
│ │ │ ├── Password
│ │ │ │ └── index.ts
│ │ │ ├── Radio
│ │ │ │ ├── Radio.vue
│ │ │ │ └── index.ts
│ │ │ ├── Rate
│ │ │ │ └── index.ts
│ │ │ ├── Select
│ │ │ │ ├── Select.vue
│ │ │ │ └── index.ts
│ │ │ ├── Slider
│ │ │ │ └── index.ts
│ │ │ ├── Switch
│ │ │ │ ├── index.ts
│ │ │ │ └── index.vue
│ │ │ ├── TextArea
│ │ │ │ └── index.ts
│ │ │ ├── Title
│ │ │ │ ├── Title.vue
│ │ │ │ └── index.ts
│ │ │ ├── Transfer
│ │ │ │ ├── Transfer.vue
│ │ │ │ └── index.ts
│ │ │ ├── Tree
│ │ │ │ ├── Tree.vue
│ │ │ │ └── index.ts
│ │ │ ├── Upload
│ │ │ │ ├── Upload.vue
│ │ │ │ └── index.ts
│ │ │ ├── UploadFile
│ │ │ │ ├── UploadFile.vue
│ │ │ │ └── index.ts
│ │ │ ├── UploadFiles
│ │ │ │ ├── UploadFiles.vue
│ │ │ │ └── index.ts
│ │ │ ├── UploadImage
│ │ │ │ ├── UploadImage.vue
│ │ │ │ └── index.ts
│ │ │ ├── UploadImages
│ │ │ │ ├── UploadImages.vue
│ │ │ │ └── index.ts
│ │ │ └── index.ts
│ │ ├── config
│ │ │ ├── commonAttr
│ │ │ │ ├── apiAttr.js
│ │ │ │ ├── basicAttr.js
│ │ │ │ ├── highAttr.js
│ │ │ │ ├── index.js
│ │ │ │ ├── linkageAttr.js
│ │ │ │ ├── mergeAttr.js
│ │ │ │ └── optionAttr.js
│ │ │ ├── commonType.ts
│ │ │ └── symbol.ts
│ │ ├── directive
│ │ │ ├── index.js
│ │ │ ├── selectLoadMore.js
│ │ │ └── tableLoadMore.js
│ │ ├── hooks
│ │ │ ├── useRequest.js
│ │ │ └── useSelect.js
│ │ ├── index.ts
│ │ └── support
│ │ │ └── index.ts
│ ├── catchTable
│ │ ├── components
│ │ │ ├── ellipsis
│ │ │ │ └── index.vue
│ │ │ └── switchColumn
│ │ │ │ └── index.vue
│ │ ├── csearch.vue
│ │ ├── ctable.ts
│ │ ├── ctcolumns.tsx
│ │ ├── index.vue
│ │ ├── tcolumns.vue
│ │ ├── types.ts
│ │ └── useSearch.ts
│ ├── editor
│ │ └── index.vue
│ └── icon
│ │ └── index.vue
├── composables
│ ├── curd
│ │ ├── useCreate.ts
│ │ ├── useDestroy.ts
│ │ ├── useEnabled.ts
│ │ ├── useExcelDownload.ts
│ │ ├── useGetList.ts
│ │ ├── useOpen.ts
│ │ └── useShow.ts
│ └── upload.ts
├── directives
│ ├── index.ts
│ └── permission
│ │ └── action.ts
├── enum
│ └── app.ts
├── env.d.ts
├── i18n
│ ├── index.ts
│ └── languages
│ │ ├── en.ts
│ │ └── zh.ts
├── layout
│ ├── components
│ │ ├── Menu
│ │ │ ├── index.vue
│ │ │ ├── item.vue
│ │ │ ├── mask.vue
│ │ │ └── menus.vue
│ │ ├── content.vue
│ │ ├── header
│ │ │ ├── contextMenu.vue
│ │ │ ├── index.vue
│ │ │ ├── lang.vue
│ │ │ ├── logo.vue
│ │ │ ├── menuSearch.vue
│ │ │ ├── notification.vue
│ │ │ ├── profile.vue
│ │ │ ├── tabs.vue
│ │ │ └── theme.vue
│ │ └── sider.vue
│ └── index.vue
├── main.ts
├── public
│ └── tinymce
│ │ ├── icons
│ │ └── default
│ │ │ └── icons.min.js
│ │ ├── langs
│ │ ├── README.md
│ │ └── zh-CN.js
│ │ ├── license.txt
│ │ ├── models
│ │ └── dom
│ │ │ └── model.min.js
│ │ ├── plugins
│ │ ├── advlist
│ │ │ └── plugin.min.js
│ │ ├── anchor
│ │ │ └── plugin.min.js
│ │ ├── autolink
│ │ │ └── plugin.min.js
│ │ ├── autoresize
│ │ │ └── plugin.min.js
│ │ ├── autosave
│ │ │ └── plugin.min.js
│ │ ├── charmap
│ │ │ └── plugin.min.js
│ │ ├── code
│ │ │ └── plugin.min.js
│ │ ├── codesample
│ │ │ └── plugin.min.js
│ │ ├── directionality
│ │ │ └── plugin.min.js
│ │ ├── emoticons
│ │ │ ├── js
│ │ │ │ ├── emojiimages.js
│ │ │ │ ├── emojiimages.min.js
│ │ │ │ ├── emojis.js
│ │ │ │ └── emojis.min.js
│ │ │ └── plugin.min.js
│ │ ├── fullscreen
│ │ │ └── plugin.min.js
│ │ ├── help
│ │ │ └── plugin.min.js
│ │ ├── image
│ │ │ └── plugin.min.js
│ │ ├── importcss
│ │ │ └── plugin.min.js
│ │ ├── insertdatetime
│ │ │ └── plugin.min.js
│ │ ├── link
│ │ │ └── plugin.min.js
│ │ ├── lists
│ │ │ └── plugin.min.js
│ │ ├── media
│ │ │ └── plugin.min.js
│ │ ├── nonbreaking
│ │ │ └── plugin.min.js
│ │ ├── pagebreak
│ │ │ └── plugin.min.js
│ │ ├── preview
│ │ │ └── plugin.min.js
│ │ ├── quickbars
│ │ │ └── plugin.min.js
│ │ ├── save
│ │ │ └── plugin.min.js
│ │ ├── searchreplace
│ │ │ └── plugin.min.js
│ │ ├── table
│ │ │ └── plugin.min.js
│ │ ├── template
│ │ │ └── plugin.min.js
│ │ ├── visualblocks
│ │ │ └── plugin.min.js
│ │ ├── visualchars
│ │ │ └── plugin.min.js
│ │ └── wordcount
│ │ │ └── plugin.min.js
│ │ ├── skins
│ │ ├── content
│ │ │ ├── dark
│ │ │ │ └── content.min.css
│ │ │ ├── default
│ │ │ │ └── content.min.css
│ │ │ ├── document
│ │ │ │ └── content.min.css
│ │ │ ├── tinymce-5-dark
│ │ │ │ └── content.min.css
│ │ │ ├── tinymce-5
│ │ │ │ └── content.min.css
│ │ │ └── writer
│ │ │ │ └── content.min.css
│ │ └── ui
│ │ │ ├── oxide-dark
│ │ │ ├── content.inline.min.css
│ │ │ ├── content.min.css
│ │ │ ├── skin.min.css
│ │ │ └── skin.shadowdom.min.css
│ │ │ ├── oxide
│ │ │ ├── content.inline.min.css
│ │ │ ├── content.min.css
│ │ │ ├── skin.min.css
│ │ │ └── skin.shadowdom.min.css
│ │ │ ├── tinymce-5-dark
│ │ │ ├── content.inline.min.css
│ │ │ ├── content.min.css
│ │ │ ├── skin.min.css
│ │ │ └── skin.shadowdom.min.css
│ │ │ └── tinymce-5
│ │ │ ├── content.inline.min.css
│ │ │ ├── content.min.css
│ │ │ ├── skin.min.css
│ │ │ └── skin.shadowdom.min.css
│ │ ├── themes
│ │ └── silver
│ │ │ └── theme.min.js
│ │ ├── tinymce.d.ts
│ │ └── tinymce.min.js
├── router
│ ├── constantRoutes.ts
│ ├── guard
│ │ └── index.ts
│ └── index.ts
├── stores
│ ├── index.ts
│ └── modules
│ │ ├── app
│ │ └── index.ts
│ │ ├── tabs
│ │ └── index.ts
│ │ └── user
│ │ ├── index.ts
│ │ └── permissions.ts
├── styles
│ ├── element.scss
│ ├── index.scss
│ ├── tailwind.css
│ ├── theme
│ │ ├── dark.scss
│ │ ├── index.scss
│ │ └── light.scss
│ └── var.scss
├── support
│ ├── cache.ts
│ ├── catchAdmin.ts
│ ├── helper.ts
│ ├── http.ts
│ ├── message.ts
│ ├── progress.ts
│ └── request.ts
├── types
│ ├── Menu.ts
│ ├── Permission.ts
│ ├── User.ts
│ ├── responseData.ts
│ └── router.ts
└── views
│ ├── dashboard
│ ├── dependencies.vue
│ ├── index.vue
│ ├── introduce.vue
│ └── project.vue
│ ├── develop
│ ├── generate
│ │ ├── components
│ │ │ ├── codeGen.vue
│ │ │ ├── store.ts
│ │ │ └── structure.vue
│ │ └── index.vue
│ ├── generator
│ │ ├── components
│ │ │ ├── codeGen.vue
│ │ │ ├── structure.ts
│ │ │ └── structure.vue
│ │ └── index.vue
│ ├── module
│ │ ├── create.vue
│ │ ├── index.vue
│ │ └── install.vue
│ └── schema
│ │ ├── addExistSchema.vue
│ │ ├── create.vue
│ │ ├── index.vue
│ │ ├── show.vue
│ │ ├── steps
│ │ ├── schema.vue
│ │ └── structure.vue
│ │ └── store
│ │ └── index.ts
│ ├── login
│ ├── index.vue
│ └── login.ts
│ ├── permissions
│ ├── departments
│ │ ├── form
│ │ │ └── create.vue
│ │ └── index.vue
│ ├── jobs
│ │ ├── form
│ │ │ └── create.vue
│ │ └── index.vue
│ ├── permissions
│ │ ├── form
│ │ │ └── create.vue
│ │ └── index.vue
│ └── roles
│ │ ├── form
│ │ └── create.vue
│ │ └── index.vue
│ ├── system
│ ├── dictionary
│ │ ├── create.vue
│ │ └── index.vue
│ └── dictionaryValues
│ │ ├── create.vue
│ │ └── index.vue
│ └── user
│ ├── center.vue
│ ├── components
│ ├── department.vue
│ ├── loginLog.vue
│ ├── operateLog.vue
│ └── profile.vue
│ ├── create.vue
│ └── index.vue
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wechat.png
/.env.example:
--------------------------------------------------------------------------------
1 | VITE_BASE_URL=
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true
5 | },
6 | "extends": ["plugin:vue/essential", "standard"],
7 | "parserOptions": {
8 | "ecmaVersion": "latest",
9 | "parser": "@typescript-eslint/parser",
10 | "sourceType": "module"
11 | },
12 | "plugins": ["vue", "@typescript-eslint"],
13 | "rules": {
14 | "vue/multi-word-component-names": 0,
15 | "space-before-function-paren": 0,
16 | "vue/no-v-model-argument": "off",
17 | "vue/no-multiple-template-root": "off"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 | yarn.lock
10 | package-lock.json
11 |
12 | node_modules
13 | dist
14 | dist-ssr
15 | *.local
16 | .env
17 | # Editor directories and files
18 | .vscode/*
19 | !.vscode/extensions.json
20 | .idea
21 | .DS_Store
22 | *.suo
23 | *.ntvs*
24 | *.njsproj
25 | *.sln
26 | *.sw?
27 | auto-imports.d.ts
28 | components.d.ts
29 |
30 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "printWidth": 200,
4 | "tabWidth": 2,
5 | "useTabs": false,
6 | "singleQuote": true,
7 | "arrowParens": "avoid",
8 | "trailingComma": "none",
9 | "bracketSpacing": true
10 | }
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-present PanJiaChen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 介绍
2 |
3 | 这是前端项目仓库 v3 版本,目前仓库对接了 [tp](https://gitee.com/catchamin/catchadmin-tp)和[webman](https://gitee.com/catchamin/catchadmin-webman) 项目,这个仓库不再模块化。
4 |
5 | 如果使用的是 v2 版本,请使用 V2 分支
6 |
7 | 感谢支持
8 |
9 | ## 专业版
10 |
11 | [专业版本官方地址](https://catchadmin.com/pro)
12 |
13 | 首先感谢一直以来对 `CatchAdmin` 开源项目的支持和使用。作为一名开源工作者,我一直致力于开发出功能强大且易于使用的后台管理系统,以帮助您简化业务流程和提升工作效率。然而,由于某些原因,我不得不做出一些调整。为了能够继续开发和维护这个项目,我将推出一款付费的后台管理系统,以确保我能够持续为您提供高质量的服务和支持。
14 |
15 | 专业版本不会在开源版本做一些破坏性变更,所以当您从开源版本切换到专业版本,不会有任何开发心智负担。但是使用专业版本会有新的组件来配合您的工作。
16 |
17 | 我深信,付费后台管理系统将为您带来更多的价值和便利,帮助您提升工作效率
18 |
19 | ## 桌面端(付费)
20 |
21 | 如果需要桌面端后台,使用 `Electron` 技术栈。可以联系微信咨询
22 |
23 |
24 |
25 | ## 功能
26 |
27 | - [x] 用户管理 后台用户管理
28 | - [x] 部门管理 配置公司的部门结构,支持树形结构
29 | - [x] 岗位管理 配置后台用户的职务
30 | - [x] 菜单管理 配置系统菜单,按钮等等
31 | - [x] 角色管理 配置用户担当的角色,分配权限
32 | - [x] 操作日志 后台用户操作记录
33 | - [x] 登录日志 后台系统用户的登录记录
34 | - [x] 代码生成 生成 API 端的 CURD 操作
35 | - [x] Schema 管理 生成表结构
36 |
37 | ## 讨论
38 |
39 | - 可以提 `ISSUE`,请按照 `issue` 模板提问
40 | - 加入 Q 群 `302266230` 暗号 `catchadmin`。
41 | - 加微信入群,新建🆕
42 |
43 |
44 |
45 | ## 项目地址
46 |
47 | - [github catchadmin](https://github.com/jaguarjack/catch-admin)
48 |
49 | ## 文档地址
50 |
51 | - [文档地址](https://catchadmin.com/docs/3.0/intro)
52 |
53 | ## 预览
54 |
55 | 
56 | 
57 | 
58 | 
59 |
60 | ## 体验地址
61 |
62 | [demo 地址](https://v3.catchadmin.com)
63 |
64 | - 账户: `catch@admin.com`
65 | - 密码: `catchadmin`
66 |
67 | ## 视频教程(😂记得一键三连哦)
68 |
69 | - [catchadmin 安装](https://www.bilibili.com/video/BV1eY411v71J/)
70 | - [catchadmin 开发之模块创建](https://www.bilibili.com/video/BV1jP41127aW/)
71 | - [catchadmin 之快速开发](https://www.bilibili.com/video/BV1Qh4y1J7eB/)
72 |
73 | ## 感谢🙏
74 |
75 | > 排名不分先后
76 |
77 | - [ThinkPHP](https://thinkphp.cn)
78 | - [Vue](https://cn.vuejs.org/)
79 | - [ElementPlus](https://element-plus.org)
80 | - [JetBrains](https://www.jetbrains.com/)
81 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 后台管理系统
8 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pro",
3 | "private": false,
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "vue-tsc --noEmit && vite build --mode production",
8 | "build:release": "vue-tsc --noEmit && vite build --mode release",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@heroicons/vue": "^2.2.0",
13 | "@tinymce/tinymce-vue": "^5.1.1",
14 | "@vueuse/core": "^11.3.0",
15 | "cos-js-sdk-v5": "^1.8.6",
16 | "echarts": "^5.5.1",
17 | "element-plus": "^2.8.8",
18 | "nprogress": "^0.2.0",
19 | "pinia": "^2.2.6",
20 | "qiniu-js": "^3.4.2",
21 | "terser": "^5.3.3",
22 | "vue": "^3.5.13",
23 | "vue-draggable-plus": "^0.6.0",
24 | "vue-echarts": "^7.0.3",
25 | "vue-i18n": "10.0.6",
26 | "vue-router": "4.4.5",
27 | "vue3-marquee": "^4.2.2"
28 | },
29 | "devDependencies": {
30 | "@iconify-json/logos": "^1.2.3",
31 | "@rollup/plugin-alias": "^5.1.1",
32 | "@types/mockjs": "^1.0.10",
33 | "@types/node": "^22.9.3",
34 | "@types/nprogress": "^0.2.3",
35 | "@typescript-eslint/eslint-plugin": "^8.15.0",
36 | "@typescript-eslint/parser": "^8.15.0",
37 | "@vitejs/plugin-vue": "^5.2.0",
38 | "@vitejs/plugin-vue-jsx": "^4.1.0",
39 | "autoprefixer": "^10.4.20",
40 | "axios": "^1.7.7",
41 | "eslint": "^9.15.0",
42 | "eslint-config-standard": "^17.1.0",
43 | "eslint-plugin-import": "^2.31.0",
44 | "eslint-plugin-n": "^17.14.0",
45 | "eslint-plugin-promise": "^7.1.0",
46 | "eslint-plugin-vue": "^9.31.0",
47 | "mockjs": "^1.1.0",
48 | "postcss": "^8.4.49",
49 | "prettier": "3.3.3",
50 | "sass": "^1.81.0",
51 | "tailwindcss": "^3.4.15",
52 | "typescript": "5.6.2",
53 | "unplugin-auto-import": "^0.18.5",
54 | "unplugin-icons": "^0.20.1",
55 | "unplugin-vue-components": "^0.27.4",
56 | "vite": "^6.0.0",
57 | "vite-plugin-html": "^3.2.2",
58 | "vite-plugin-mock": "^3.0.2",
59 | "vue-tsc": "2.1.6"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {}
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/public/static/config.js:
--------------------------------------------------------------------------------
1 | window.admin_config = {
2 | title: '',
3 | BASE_URL: '',
4 | }
5 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JaguarJack/catch-admin-vue/34776ee77fc604547d295cc7fee871ed71499aa2/src/assets/404.png
--------------------------------------------------------------------------------
/src/assets/login-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JaguarJack/catch-admin-vue/34776ee77fc604547d295cc7fee871ed71499aa2/src/assets/login-left.png
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JaguarJack/catch-admin-vue/34776ee77fc604547d295cc7fee871ed71499aa2/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/404/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
![]()
4 |
5 |
抱歉,您访问的页面不存在
6 |
7 | 回到首页
8 |
9 |
10 |
11 |
12 |
13 |
29 |
--------------------------------------------------------------------------------
/src/components/admin/buttons/add.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ text }}
3 |
4 |
5 |
17 |
--------------------------------------------------------------------------------
/src/components/admin/buttons/destroy.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ text }}
3 |
4 |
5 |
17 |
--------------------------------------------------------------------------------
/src/components/admin/buttons/show.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ text }}
3 |
4 |
5 |
17 |
--------------------------------------------------------------------------------
/src/components/admin/buttons/update.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ text }}
3 |
4 |
5 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/components/admin/paginate/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
24 |
--------------------------------------------------------------------------------
/src/components/admin/select/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
64 |
--------------------------------------------------------------------------------
/src/components/admin/status/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
45 |
--------------------------------------------------------------------------------
/src/components/admin/table/operate.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
18 |
--------------------------------------------------------------------------------
/src/components/admin/table/search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 搜索
9 |
10 |
11 |
12 | 重置
13 |
14 |
15 |
16 |
17 |
18 |
19 |
32 |
33 |
38 |
--------------------------------------------------------------------------------
/src/components/admin/upload/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
67 |
--------------------------------------------------------------------------------
/src/components/admin/upload/oss.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
60 |
--------------------------------------------------------------------------------
/src/components/breadcrumbs/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ item }}
7 |
8 |
9 |
10 |
11 |
58 |
59 |
72 |
--------------------------------------------------------------------------------
/src/components/catchForm/Disabled.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
31 |
--------------------------------------------------------------------------------
/src/components/catchForm/FormRender.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Alert/index.ts:
--------------------------------------------------------------------------------
1 | import { ElAlert } from 'element-plus'
2 | export default {
3 | name: 'alert',
4 | component: ElAlert,
5 | type: 'assist'
6 | }
7 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Button/Button.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ name }}
3 |
4 |
5 |
36 |
37 |
42 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Button/index.ts:
--------------------------------------------------------------------------------
1 | import Button from './Button.vue'
2 |
3 | export default {
4 | name: 'button',
5 | component: Button,
6 | type: 'assist'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Card/Card.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
17 |
18 |
25 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Card/index.ts:
--------------------------------------------------------------------------------
1 | import Card from './Card.vue'
2 |
3 | export default {
4 | name: 'card',
5 | component: Card,
6 | type: 'layout'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Cascader/Cascader.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
56 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Cascader/index.ts:
--------------------------------------------------------------------------------
1 | import Cascader from './Cascader.vue'
2 |
3 | export default {
4 | name: 'cascader',
5 | type: 'basic',
6 | component: Cascader
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Checkbox/Checkbox.vue:
--------------------------------------------------------------------------------
1 |
2 | 暂无选项
3 |
4 |
5 |
6 | {{ item[label] }}
7 |
8 |
9 |
10 | {{ item[label] }}
11 |
12 |
13 |
14 |
15 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Checkbox/index.ts:
--------------------------------------------------------------------------------
1 | import Checkbox from './Checkbox.vue'
2 |
3 | export default {
4 | name: 'checkbox',
5 | type: 'basic',
6 | component: Checkbox
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Collapse/Collapse.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
27 |
28 |
35 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Collapse/index.ts:
--------------------------------------------------------------------------------
1 | import Collapse from './Collapse.vue'
2 |
3 | export default {
4 | name: 'collapse',
5 | component: Collapse,
6 | type: 'layout'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/ColorPicker/ColorPicker.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/ColorPicker/index.ts:
--------------------------------------------------------------------------------
1 | import { ElColorPicker } from 'element-plus'
2 | export default {
3 | name: 'color_picker',
4 | component: ElColorPicker,
5 | type: 'basic'
6 | }
7 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Custom/Custom.vue:
--------------------------------------------------------------------------------
1 |
2 | 请输入全局注册得组件名
3 |
4 |
5 |
6 |
25 |
26 |
31 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Custom/index.ts:
--------------------------------------------------------------------------------
1 | import Custom from './Custom.vue'
2 |
3 | export default {
4 | name: 'custom',
5 | component: Custom,
6 | initialValues: {
7 | label: '自定义组件',
8 | component: 'Custom',
9 | props: {}
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/DatePicker/index.ts:
--------------------------------------------------------------------------------
1 | import { ElDatePicker } from 'element-plus'
2 |
3 | export default {
4 | name: 'date_picker',
5 | component: ElDatePicker,
6 | type: 'basic'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Divider/Divider.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ title }}
3 |
4 |
5 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Divider/index.ts:
--------------------------------------------------------------------------------
1 | import Divider from './Divider.vue'
2 |
3 | export default {
4 | name: 'divider',
5 | component: Divider,
6 | type: 'assist'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/FormList/index.ts:
--------------------------------------------------------------------------------
1 | import FormList from './FormList.vue'
2 |
3 | export default {
4 | name: 'form_list',
5 | component: FormList,
6 | type: 'high'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Gird/Grid.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
26 |
27 |
37 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Gird/index.ts:
--------------------------------------------------------------------------------
1 | import Grid from './Grid.vue'
2 |
3 | export default {
4 | name: 'grid',
5 | type: 'layout',
6 | component: Grid
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/IconSelect/IconSelect.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
22 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/IconSelect/index.ts:
--------------------------------------------------------------------------------
1 | import IconSelect from './IconSelect.vue'
2 |
3 | export default {
4 | name: 'icon_select',
5 | type: 'basic',
6 | component: IconSelect
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Inline/Inline.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
21 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Inline/index.ts:
--------------------------------------------------------------------------------
1 | import Inline from './Inline.vue'
2 |
3 | export default {
4 | name: 'inline',
5 | type: 'layout',
6 | component: Inline
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Input/index.ts:
--------------------------------------------------------------------------------
1 | import { ElInput } from 'element-plus'
2 | import { h } from 'vue'
3 |
4 | export default {
5 | name: 'input',
6 | component: h(ElInput, { showWordLimit: true, autocomplete: 'off' }),
7 | type: 'basic'
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/InputNumber/InputNumber.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ unit }}
5 |
6 |
7 |
8 |
31 |
32 |
40 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/InputNumber/index.ts:
--------------------------------------------------------------------------------
1 | import InputNumber from './InputNumber.vue'
2 |
3 | export default {
4 | name: 'input_number',
5 | type: 'basic',
6 | component: InputNumber
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Password/index.ts:
--------------------------------------------------------------------------------
1 | import { ElInput } from 'element-plus'
2 | import { h } from 'vue'
3 |
4 | export default {
5 | name: 'password',
6 | component: h(ElInput, { type: 'password', showWordLimit: true, autocomplete: 'off' }),
7 | type: 'basic'
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Radio/Radio.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 暂无选项
4 |
5 |
6 |
7 | {{ item[label] }}
8 |
9 |
10 |
11 | {{ item[label] }}
12 |
13 |
14 |
15 |
16 | {{ item[label] }}
17 |
18 |
19 |
20 | {{ item[label] }}
21 |
22 |
23 |
24 |
25 |
26 |
69 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Radio/index.ts:
--------------------------------------------------------------------------------
1 | import Radio from './Radio.vue'
2 |
3 | export default {
4 | name: 'radio',
5 | type: 'basic',
6 | component: Radio
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Rate/index.ts:
--------------------------------------------------------------------------------
1 | import { ElRate } from 'element-plus'
2 |
3 | export default {
4 | name: 'rate',
5 | component: ElRate,
6 | type: 'basic'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Select/Select.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
82 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Select/index.ts:
--------------------------------------------------------------------------------
1 | import Select from './Select.vue'
2 |
3 | export default {
4 | name: 'select',
5 | type: 'basic',
6 | component: Select
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Slider/index.ts:
--------------------------------------------------------------------------------
1 | import { ElSlider } from 'element-plus'
2 |
3 | export default {
4 | name: 'slider',
5 | component: ElSlider,
6 | type: 'basic'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Switch/index.ts:
--------------------------------------------------------------------------------
1 | import { ElSwitch } from 'element-plus'
2 | import cswitch from './index.vue'
3 | export default {
4 | name: 'switch',
5 | component: cswitch,
6 | type: 'basic'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Switch/index.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/TextArea/index.ts:
--------------------------------------------------------------------------------
1 | import { ElInput } from 'element-plus'
2 | import { h } from 'vue'
3 |
4 | export default {
5 | name: 'textarea',
6 | component: h(ElInput, { type: 'textarea', showWordLimit: true, autocomplete: 'off' }),
7 | type: 'basic'
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Title/Title.vue:
--------------------------------------------------------------------------------
1 |
2 | {{
3 | title
4 | }}
5 |
6 |
7 |
24 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Title/index.ts:
--------------------------------------------------------------------------------
1 | import Title from './Title.vue'
2 |
3 | export default {
4 | name: 'title',
5 | component: Title,
6 | type: 'assist'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Transfer/Transfer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
39 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Transfer/index.ts:
--------------------------------------------------------------------------------
1 | import Transfer from './Transfer.vue'
2 |
3 | export default {
4 | name: 'transfer',
5 | type: 'basic',
6 | component: Transfer
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Tree/Tree.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
81 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Tree/index.ts:
--------------------------------------------------------------------------------
1 | import Tree from './Tree.vue'
2 |
3 | export default {
4 | name: 'tree',
5 | type: 'basic',
6 | component: Tree
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Upload/Upload.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ buttonText }}
6 |
7 |
8 |
9 |
10 |
80 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/Upload/index.ts:
--------------------------------------------------------------------------------
1 | import Upload from './Upload.vue'
2 |
3 | export default {
4 | name: 'upload',
5 | component: Upload,
6 | type: 'basic'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/UploadFile/UploadFile.vue:
--------------------------------------------------------------------------------
1 |
52 |
53 |
66 |
67 | {{ filename }}
68 |
69 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/UploadFile/index.ts:
--------------------------------------------------------------------------------
1 | import UploadFile from './UploadFile.vue'
2 |
3 | export default {
4 | name: 'upload_file',
5 | component: UploadFile,
6 | type: 'basic'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/UploadFiles/UploadFiles.vue:
--------------------------------------------------------------------------------
1 |
69 |
70 |
83 |
84 |
89 |
90 |
91 |
{{ getFilename(item) }}
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/UploadFiles/index.ts:
--------------------------------------------------------------------------------
1 | import UploadFiles from './UploadFiles.vue'
2 |
3 | export default {
4 | name: 'upload_files',
5 | component: UploadFiles,
6 | type: 'basic'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/UploadImage/UploadImage.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
20 |
21 |
22 |
72 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/UploadImage/index.ts:
--------------------------------------------------------------------------------
1 | import UploadImage from './UploadImage.vue'
2 |
3 | export default {
4 | name: 'upload_image',
5 | component: UploadImage,
6 | type: 'basic'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/UploadImages/UploadImages.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
![]()
5 |
6 |
7 |
8 |
9 |
10 |
27 |
28 |
29 |
98 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/UploadImages/index.ts:
--------------------------------------------------------------------------------
1 | import UploadImages from './UploadImages.vue'
2 |
3 | export default {
4 | name: 'upload_images',
5 | component: UploadImages,
6 | type: 'basic'
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/catchForm/components/index.ts:
--------------------------------------------------------------------------------
1 | import type { formElement } from '@/components/catchForm/config/commonType'
2 |
3 | const modules = import.meta.glob('./*/index.ts', { eager: true })
4 | const components: { [component: string]: formElement } = {}
5 |
6 | for (const path in modules) {
7 | const data = (modules[path] as { default: formElement }).default
8 | if (data) {
9 | components[data.name] = data
10 | }
11 | }
12 | export default components
13 |
--------------------------------------------------------------------------------
/src/components/catchForm/config/commonAttr/apiAttr.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | label: 'url',
4 | component: 'Input',
5 | name: 'props.api.url',
6 | initialValue: '/current/query/article',
7 | designKey: 'form-UrE8'
8 | },
9 | {
10 | label: '请求方式',
11 | component: 'Radio',
12 | name: 'props.api.method',
13 | props: {
14 | mode: 'static',
15 | autoSelectedFirst: true,
16 | options: [
17 | {
18 | label: 'GET',
19 | value: 'GET'
20 | },
21 | {
22 | label: 'POST',
23 | value: 'POST'
24 | },
25 | {
26 | label: 'PUT',
27 | value: 'PUT'
28 | },
29 | {
30 | label: 'DELETE',
31 | value: 'DELETE'
32 | }
33 | ]
34 | },
35 | designKey: 'form-nOpD'
36 | },
37 | {
38 | label: '请求参数',
39 | component: 'JsonEdit',
40 | name: 'props.api.params',
41 | hidden: '{{ ["POST","PUT"].includes($values.props.api.method) }}',
42 | initialValue: {},
43 | props: {
44 | mode: 'dialog'
45 | }
46 | },
47 | {
48 | label: '请求参数',
49 | component: 'JsonEdit',
50 | name: 'props.api.data',
51 | hidden: '{{ ["GET","DELETE"].includes($values.props.api.method) }}',
52 | initialValue: {},
53 | props: {
54 | mode: 'dialog'
55 | }
56 | },
57 | {
58 | label: '数据路径',
59 | component: 'Input',
60 | name: 'props.api.dataPath',
61 | initialValue: 'data',
62 | designKey: 'form-UrE8'
63 | }
64 | ]
65 |
--------------------------------------------------------------------------------
/src/components/catchForm/config/commonAttr/basicAttr.js:
--------------------------------------------------------------------------------
1 | import { recursionDelete } from '@/components/catchForm/support'
2 |
3 | const basicAttr = (omit = [], moreAttrs = []) => {
4 | const attr = [
5 | { label: '标签', component: 'Input', name: 'label' },
6 | {
7 | label: '唯一标识',
8 | component: 'Input',
9 | name: 'name',
10 | help: "既是唯一标识,也是数据路径。比如输入【props.name】,数据就会保存为 { props: { name:'xxx' } }"
11 | },
12 | { label: '字段说明', component: 'Textarea', name: 'help' },
13 | {
14 | label: '占位提示',
15 | component: 'Input',
16 | name: 'props.placeholder',
17 | designKey: 'form-ekRL'
18 | },
19 | { label: '初始值', component: 'Input', name: 'initialValue' },
20 | {
21 | component: 'Grid',
22 | children: [
23 | { label: '是否必填', component: 'Switch', name: 'required' },
24 | { label: '是否只读', component: 'Switch', name: 'props.readonly' },
25 | { label: '是否禁用', component: 'Switch', name: 'props.disabled' },
26 | { label: '隐藏字段', component: 'Switch', name: 'hidden' },
27 | { label: '隐藏标签', component: 'Switch', name: 'hideLabel' }
28 | ],
29 | props: {
30 | columns: 3,
31 | 'row-gap': 0,
32 | 'column-gap': 20
33 | },
34 | designKey: 'form-R003',
35 | name: 'cNmCuu',
36 | style: {
37 | marginBottom: 0
38 | }
39 | }
40 | ]
41 |
42 | const omitAttrs = recursionDelete(attr, (item) => !omit.includes(item.name))
43 |
44 | return [...omitAttrs, ...moreAttrs]
45 | }
46 |
47 | export default basicAttr
48 |
--------------------------------------------------------------------------------
/src/components/catchForm/config/commonAttr/highAttr.js:
--------------------------------------------------------------------------------
1 | const basicAttr = (omit = []) => {
2 | const attr = [
3 | { label: '自定义class', component: 'Input', name: 'props.class' },
4 | {
5 | label: '自定义style',
6 | component: 'JsonEdit',
7 | name: 'props.style',
8 | help: '与vue的style对象格式一样',
9 | props: {
10 | mode: 'dialog'
11 | }
12 | }
13 | ]
14 |
15 | return attr.filter((item) => !omit.includes(item.name))
16 | }
17 |
18 | export default basicAttr
19 |
--------------------------------------------------------------------------------
/src/components/catchForm/config/commonAttr/index.js:
--------------------------------------------------------------------------------
1 | export { default as basicAttr } from './basicAttr'
2 | export { default as highAttr } from './highAttr'
3 | export { default as apiAttr } from './apiAttr'
4 | export { default as linkageAttr } from './linkageAttr'
5 | export { default as optionAttr } from './optionAttr'
6 | export { default as mergeAttr } from './mergeAttr'
7 |
--------------------------------------------------------------------------------
/src/components/catchForm/config/commonAttr/linkageAttr.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | component: 'Alert',
4 | props: {
5 | type: 'success',
6 | description: '对于配置级的联动,请直接点击下方按钮【编辑配置文本】,通过插值表达式实现',
7 | closable: true,
8 | 'show-icon': true
9 | },
10 | designKey: 'design-MQPU',
11 | name: 'form-Oqi5'
12 | },
13 | {
14 | label: '值联动',
15 | help: '本字段值改变时,修改其他字段的值',
16 | name: 'change',
17 | component: 'FormList',
18 | children: [
19 | {
20 | label: '目标字段',
21 | name: 'target',
22 | component: 'Input',
23 | props: {}
24 | },
25 | {
26 | label: '值',
27 | name: 'value',
28 | component: 'Input',
29 | props: {}
30 | }
31 | ],
32 | props: {
33 | mode: 'card'
34 | }
35 | }
36 | ]
37 |
--------------------------------------------------------------------------------
/src/components/catchForm/config/commonAttr/mergeAttr.js:
--------------------------------------------------------------------------------
1 | const mergeAttr = (attrConfig) => {
2 | const { basic = [], high = [], linkage = [] } = attrConfig
3 |
4 | const attrs = [
5 | {
6 | component: 'Collapse',
7 | name: 'mergeAttr',
8 | children: [
9 | {
10 | title: '常用属性',
11 | name: 'basic',
12 | checked: true,
13 | children: basic
14 | },
15 | {
16 | title: '高级属性',
17 | name: 'high',
18 | children: high
19 | },
20 | {
21 | title: '联动规则',
22 | name: 'linkage',
23 | children: linkage
24 | }
25 | ]
26 | }
27 | ]
28 |
29 | return attrs
30 | }
31 |
32 | export default mergeAttr
33 |
--------------------------------------------------------------------------------
/src/components/catchForm/config/commonAttr/optionAttr.js:
--------------------------------------------------------------------------------
1 | import apiAttr from './apiAttr'
2 |
3 | export default [
4 | {
5 | component: 'Divider',
6 | props: {
7 | title: '选项设置',
8 | contentPosition: 'center'
9 | },
10 | designKey: 'design-gSnX',
11 | name: 'form-xDEe',
12 | style: {
13 | marginTop: '40px'
14 | }
15 | },
16 | {
17 | label: '标签key',
18 | component: 'Input',
19 | name: 'props.labelKey',
20 | designKey: 'form-X6hs'
21 | },
22 | {
23 | label: '值Key',
24 | component: 'Input',
25 | name: 'props.valueKey',
26 | designKey: 'form-STkl'
27 | },
28 | {
29 | label: '数据模式',
30 | component: 'Radio',
31 | name: 'props.mode',
32 | props: {
33 | mode: 'static',
34 | options: [
35 | {
36 | label: '静态',
37 | value: 'static'
38 | },
39 | {
40 | label: '远程',
41 | value: 'remote'
42 | }
43 | ],
44 | optionType: 'button',
45 | space: 0
46 | },
47 | designKey: 'form-PLpj'
48 | },
49 | {
50 | label: '静态选项',
51 | name: 'props.options',
52 | component: 'FormList',
53 | hidden: '{{$values.props.mode!=="static"}}',
54 | children: [
55 | {
56 | label: '选项名',
57 | name: '{{$values.props.labelKey}}',
58 | component: 'Input',
59 | props: {
60 | placeholder: '请输入...'
61 | },
62 | designKey: 'form-LnGh'
63 | // initialValue: "{{ '选项' + ($index+1) }}"
64 | },
65 | {
66 | label: '选项值',
67 | name: '{{$values.props.valueKey}}',
68 | component: 'Input',
69 | props: {},
70 | designKey: 'form-HYtW'
71 | // initialValue: "{{ 'value' + ($index+1) }}"
72 | }
73 | ],
74 | designKey: 'form-Iwpd',
75 | props: {
76 | mode: 'table',
77 | newItemDefaults:
78 | '{{ (index) => ({ [$values.props.labelKey]: `选项${index + 1}`, [$values.props.valueKey]: `value${index + 1}` }) }}'
79 | }
80 | },
81 | {
82 | component: 'Card',
83 | props: {
84 | // header: '远程数据'
85 | },
86 | designKey: 'id-pGeN',
87 | name: 'form-6vzT',
88 | hidden: '{{$values.props.mode==="static"}}',
89 | children: apiAttr
90 | }
91 | ]
92 |
--------------------------------------------------------------------------------
/src/components/catchForm/config/commonType.ts:
--------------------------------------------------------------------------------
1 | type anyObject = { [key: string]: any }
2 |
3 | type formValuesType = anyObject
4 |
5 | type contextType = {
6 | $values: formValuesType
7 | $selectData: formValuesType
8 | $initialValues: formValuesType
9 | [key: string]: any
10 | }
11 |
12 | type changeItemType = {
13 | target: string
14 | value: any
15 | }
16 |
17 | interface formItemType {
18 | label?: string
19 | name: string
20 | component: string
21 | required?: boolean
22 | props?: object
23 | default?: any
24 | help?: string
25 | children?: formItemType[]
26 | hidden?: boolean | string
27 | hideLabel?: boolean
28 | rules?: any[]
29 | class?: string
30 | style?: any
31 | change?: changeItemType[]
32 | footer: formItemType
33 | }
34 |
35 | type formItemsType = formItemType[]
36 |
37 | type schemaType = {
38 | labelWidth: number
39 | labelAlign: string
40 | size: string
41 | footer: Object
42 | class?: string
43 | disabled?: boolean
44 | hideRequiredAsterisk?: boolean
45 | labelBold?: boolean
46 | items: formItemsType
47 | }
48 |
49 | type formElement = {
50 | name: string
51 | component: any
52 | icon: string
53 | type: 'assist' | 'layout' | 'basic' | 'high'
54 | order: number
55 | attr: formItemsType
56 | initialValues: formItemType
57 | modelName: string
58 | }
59 |
60 | type iconSelectConfigType = { component?: any; propKey?: string; iconList?: string[] }
61 |
62 | type $globalType = {
63 | http?: any
64 | getSchema?: (schemaId: string) => Promise
65 | elements?: { [key: string]: formElement }
66 | iconSelectConfig?: iconSelectConfigType
67 | customElements?: { [key: string]: formElement }
68 | }
69 |
70 | export type { anyObject, schemaType, formValuesType, contextType, formItemType, formItemsType, formElement, changeItemType, $globalType, iconSelectConfigType }
71 |
--------------------------------------------------------------------------------
/src/components/catchForm/config/symbol.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable symbol-description */
2 | export const $global = Symbol()
3 | export const $schema = Symbol()
4 | export const $formValues = Symbol()
5 | export const $selectData = Symbol()
6 | export const $formEvents = Symbol()
7 | export const $initialValues = Symbol()
8 | export const $current = Symbol()
9 | export const $methods = Symbol()
10 | export const $hoverKey = Symbol()
11 |
--------------------------------------------------------------------------------
/src/components/catchForm/directive/index.js:
--------------------------------------------------------------------------------
1 | export { default as selectLoadMore } from './selectLoadMore'
2 | export { default as tableLoadMore } from './tableLoadMore'
3 |
--------------------------------------------------------------------------------
/src/components/catchForm/directive/selectLoadMore.js:
--------------------------------------------------------------------------------
1 | import { nextTick } from 'vue'
2 |
3 | const loadMore = (app) => {
4 | app.directive('selectLoadMore', {
5 | mounted: function (el, binding) {
6 | nextTick(() => {
7 | const dropdown = document.querySelector(`.${binding.arg} .el-select-dropdown__wrap`) // 获取下拉框元素
8 |
9 | if (dropdown) {
10 | dropdown.addEventListener('scroll', function () {
11 | // 监听元素触底
12 | const condition = this.scrollHeight - this.scrollTop - 5 <= this.clientHeight
13 | if (condition) {
14 | binding.value()
15 | }
16 | })
17 | }
18 | })
19 | }
20 | })
21 | }
22 |
23 | export default loadMore
24 |
--------------------------------------------------------------------------------
/src/components/catchForm/directive/tableLoadMore.js:
--------------------------------------------------------------------------------
1 | import { nextTick } from 'vue'
2 |
3 | const loadMore = app => {
4 | app.directive('tableLoadMore', {
5 | mounted: function (el, binding) {
6 | nextTick(() => {
7 | const dom = el.querySelector('.el-scrollbar__wrap') // 获取下拉框元素
8 | dom.addEventListener('scroll', function () {
9 | // 监听元素触底
10 | const condition = this.scrollHeight - this.scrollTop - 5 <= this.clientHeight
11 | if (condition) {
12 | binding.value()
13 | }
14 | })
15 | })
16 | }
17 | })
18 | }
19 |
20 | export default loadMore
21 |
--------------------------------------------------------------------------------
/src/components/catchForm/hooks/useRequest.js:
--------------------------------------------------------------------------------
1 | import { ref, watch, inject } from 'vue'
2 | import { isEqual, debounce, throttle } from 'lodash'
3 | import { getDataByPath } from '@/components/catchForm/support'
4 |
5 | const useRequest = ({ api, debounceTime, throttleTime }) => {
6 | const $request = inject('$request')
7 |
8 | const data = ref([])
9 | const loading = ref(false)
10 |
11 | const fetchData = async () => {
12 | loading.value = true
13 |
14 | const res = await $request.get(api)
15 |
16 | const resData = getDataByPath(res, api.dataPath)
17 |
18 | data.value = resData
19 |
20 | loading.value = false
21 | }
22 |
23 | const debounceRemote = debounce(fetchData, debounceTime)
24 | const throttleRemote = throttle(fetchData, throttleTime)
25 |
26 | const run = () => {
27 | if (debounceTime) {
28 | return debounceRemote()
29 | }
30 | if (throttleTime) {
31 | return throttleRemote()
32 | }
33 |
34 | return fetchData()
35 | }
36 |
37 | watch(
38 | () => api,
39 | (newVal, oldVal) => {
40 | if (!isEqual(newVal, oldVal)) {
41 | run()
42 | }
43 | }
44 | )
45 |
46 | return { data, loading }
47 | }
48 |
49 | export default useRequest
50 |
--------------------------------------------------------------------------------
/src/components/catchForm/index.ts:
--------------------------------------------------------------------------------
1 | import type { App } from 'vue'
2 | import CatchForm from './CatchForm.vue'
3 | import { $global } from '@/components/catchForm/config/symbol'
4 | import * as Directives from '@/components/catchForm/directive'
5 |
6 | import type {
7 | anyObject,
8 | schemaType,
9 | formValuesType,
10 | contextType,
11 | formItemType,
12 | formItemsType,
13 | formElement,
14 | changeItemType,
15 | $globalType
16 | } from '@/components/catchForm/config/commonType'
17 | import components from '@/components/catchForm/components'
18 |
19 | /**
20 | * 合并 custom elements
21 | * @param customElements
22 | * @returns
23 | */
24 | const handleMergeElements = (customElements: { [key: string]: formElement }) => {
25 | const mergeElements: { [key: string]: formElement } = {}
26 |
27 | Object.entries(components).forEach(([key, value]) => {
28 | const customData = customElements[key]
29 | if (customData) {
30 | return (mergeElements[key] = {
31 | ...value,
32 | component: customData.component,
33 | modelName: customData.modelName || 'modelValue',
34 | attr: customData.attr || value.attr
35 | })
36 | }
37 |
38 | return (mergeElements[key] = { ...value, modelName: 'modelValue' })
39 | })
40 |
41 | return mergeElements
42 | }
43 |
44 | type $optionsType = {
45 | http?: any
46 | // elements?: { [key: string]: formElement }
47 | // iconSelectConfig?: iconSelectConfigType
48 | customElements?: { [key: string]: formElement }
49 | }
50 |
51 | const install = function (app: App, options: $optionsType = {}) {
52 | const { http, customElements = {} } = options
53 |
54 | app.provide($global, {
55 | http: http,
56 | elements: handleMergeElements(customElements)
57 | })
58 | // 注册指令
59 | Object.values(Directives).forEach(fn => fn(app))
60 | }
61 |
62 | export { CatchForm }
63 |
64 | export type { anyObject, schemaType, formValuesType, contextType, formItemType, formItemsType, formElement, changeItemType, $globalType }
65 |
66 | export function bootstrapCatchForm(app: App, options:Object = {}) {
67 | install(app, options)
68 | app.component('CatchForm', CatchForm)
69 | }
70 |
--------------------------------------------------------------------------------
/src/components/catchTable/components/ellipsis/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ content }}
4 |
5 |
6 |
7 | {{ ellipsis(length) }}
8 |
9 |
10 |
11 |
12 |
35 |
--------------------------------------------------------------------------------
/src/components/catchTable/components/switchColumn/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
63 |
--------------------------------------------------------------------------------
/src/components/catchTable/ctable.ts:
--------------------------------------------------------------------------------
1 | export type columnType = 'expand' | 'selection' | 'index' | 'operate'
2 | export type fixed = 'fiexed' | 'right' | 'left'
3 | export interface Column {
4 | type?: columnType // 类型 expand select index
5 | label?: string
6 | prop?: string
7 | 'min-width'?: string | number
8 | width?: number | string
9 | slot?: 'string'
10 | header: 'string' // 表头插槽名称
11 | align?: string
12 | fixed?: fixed
13 | sortable?: boolean | string
14 | 'sort-method'?: Function
15 | 'sort-by'?: Function
16 | resizable?: boolean
17 | formatter?: Function // function(row, column, cellValue, index)
18 | 'header-align'?: string
19 | 'class-name'?: string
20 | selectable?: Function // function(row, index)
21 | show: boolean
22 | index?: number | Function // 如果设置了 type=index,可以通过传递 index 属性来自定义索引
23 | children?: Array // 多级表头
24 | filter?: Function
25 | ellipsis?: boolean | number // 当文字太多时,可以使用省略文字
26 | switch?: boolean // swith 字段状态切换
27 | switchRefresh?: Function // switch refresh 刷新
28 | // 图片预览
29 | image?: boolean
30 | preview: boolean // 默认不预览
31 | // 标签
32 | tags?: boolean | Array
33 | // 链接🔗
34 | link?: boolean
35 | link_text?: string
36 | // 操作
37 | update?: boolean // 编辑操作
38 | destroy?: boolean // 删除操作
39 | }
40 |
41 | // 分页
42 | export interface paginate {
43 | layout: string
44 | limit: number
45 | page: number
46 | limits: Array
47 | total: number
48 | changePage: Function
49 | changeLimit: Function
50 | }
51 |
52 | // option
53 | export interface Option {
54 | label: string
55 | value: string | number
56 | }
57 | // 搜索 item
58 | export interface SItem {
59 | type: string
60 | name: string
61 | default: any
62 | options: Array