├── .dockerignore
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github
└── workflows
│ └── docker-image.yml
├── .gitignore
├── .postcssrc.js
├── .stylintrc
├── .vscode
├── extensions.json
└── settings.json
├── Dockerfile
├── LICENSE
├── README.md
├── README_CN.md
├── babel.config.js
├── build.sh
├── docker
├── README.md
└── default.conf
├── img
├── crudapiweixin.jpeg
├── customer.png
├── relation.png
├── table.png
└── weixinqun.png
├── jsconfig.json
├── package.json
├── public
├── crudapi-mini.png
├── crudapi.png
├── crudapiweixin.jpeg
├── favicon.ico
├── icons
│ ├── favicon-128x128.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ └── favicon-96x96.png
├── price.png
└── weixinqun.png
├── quasar.conf.js
├── run.sh
└── src
├── App.vue
├── api
├── file.js
├── index.js
├── metadataRelation.js
├── metadataSequence.js
├── metadataTable.js
├── table.js
└── user.js
├── assets
└── quasar-logo-full.svg
├── boot
├── .gitkeep
├── axios.js
├── cfile.js
├── cindexlist.js
├── cpage.js
├── crawDisplayer.js
├── csqleditor.js
├── ctableedit.js
├── ctablelist.js
├── ctablelistedit.js
├── ctablelistread.js
├── ctablenew.js
├── cvaluedialog.js
└── i18n.js
├── components
├── CDownload
│ ├── CDownloadDialog.vue
│ └── index.js
├── CFile
│ ├── CFile.vue
│ └── index.js
├── CIndexList
│ ├── CIndexList.vue
│ └── index.js
├── CPage
│ ├── CPage.vue
│ └── index.js
├── CRawDisplayer
│ ├── CRawDisplayer.vue
│ └── index.js
├── CSqlEditor
│ ├── CSqlEditor.vue
│ └── index.js
├── CTableEdit
│ ├── CTableEdit.vue
│ └── index.js
├── CTableList
│ ├── CTableList.vue
│ └── index.js
├── CTableListEdit
│ ├── CTableListEdit.vue
│ └── index.js
├── CTableListRead
│ ├── CTableListRead.vue
│ ├── CTableListReadDialog.vue
│ └── index.js
├── CTableNew
│ ├── CTableNew.vue
│ └── index.js
├── CValueDialog
│ ├── CValueDialog.vue
│ └── index.js
└── EssentialLink.vue
├── css
├── app.styl
└── quasar.variables.styl
├── i18n
├── en-us
│ └── index.js
└── index.js
├── index.template.html
├── layouts
└── MainLayout.vue
├── models
└── file-md5.js
├── pages
├── About.vue
├── Error403.vue
├── Error404.vue
├── Index.vue
├── Login.vue
├── Setting.vue
├── business
│ └── table
│ │ ├── edit.vue
│ │ ├── import.vue
│ │ ├── list.vue
│ │ ├── multiImport.vue
│ │ └── new.vue
├── form-builder
│ └── index.vue
├── metadata
│ ├── relation
│ │ ├── edit.vue
│ │ ├── graph.vue
│ │ ├── list.vue
│ │ └── new.vue
│ ├── sequence
│ │ ├── edit.vue
│ │ ├── list.vue
│ │ └── new.vue
│ ├── sql
│ │ └── new.vue
│ └── table
│ │ ├── edit.vue
│ │ ├── import.vue
│ │ ├── indexList.vue
│ │ ├── list.vue
│ │ ├── new.vue
│ │ └── reverse.vue
└── tablePermission
│ └── index.vue
├── plugins
└── js-spark-md5.js
├── router
├── index.js
└── routes.js
├── service
├── authService.js
├── fileService.js
├── index.js
├── metadataRelationService.js
├── metadataSequenceService.js
├── metadataTableService.js
├── permissionService.js
├── settingService.js
├── tableService.js
└── userService.js
├── store
├── config
│ ├── actions.js
│ ├── getters.js
│ ├── index.js
│ ├── mutations.js
│ └── state.js
├── index.js
├── module-example
│ ├── actions.js
│ ├── getters.js
│ ├── index.js
│ ├── mutations.js
│ └── state.js
├── store-flag.d.ts
└── user
│ ├── actions.js
│ ├── getters.js
│ ├── index.js
│ ├── mutations.js
│ ├── plugin.js
│ └── state.js
└── utils
├── date.js
└── index.js
/.dockerignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .git
3 | .gitignore
4 | node_modules
5 | dist
6 | .quasar
7 | .vscode
8 | .dockerignore
9 | package-lock.json
10 | Dockerfile
11 | *.md
12 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /dist
2 | /src-bex/www
3 | /src-capacitor
4 | /src-cordova
5 | /.quasar
6 | /node_modules
7 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
3 | // This option interrupts the configuration hierarchy at this file
4 | // Remove this if you have an higher level ESLint config file (it usually happens into a monorepos)
5 | root: true,
6 |
7 | parserOptions: {
8 | parser: 'babel-eslint',
9 | ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
10 | sourceType: 'module' // Allows for the use of imports
11 | },
12 |
13 | env: {
14 | browser: true
15 | },
16 |
17 | // Rules order is important, please avoid shuffling them
18 | extends: [
19 | // Base ESLint recommended rules
20 | // 'eslint:recommended',
21 |
22 |
23 | // Uncomment any of the lines below to choose desired strictness,
24 | // but leave only one uncommented!
25 | // See https://eslint.vuejs.org/rules/#available-rules
26 | 'plugin:vue/essential', // Priority A: Essential (Error Prevention)
27 | // 'plugin:vue/strongly-recommended', // Priority B: Strongly Recommended (Improving Readability)
28 | // 'plugin:vue/recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
29 |
30 | // https://github.com/prettier/eslint-config-prettier#installation
31 | // usage with Prettier, provided by 'eslint-config-prettier'.
32 | 'prettier',
33 |
34 | 'prettier/vue'
35 | ],
36 |
37 | plugins: [
38 | // https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file
39 | // required to lint *.vue files
40 | 'vue',
41 |
42 | // https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674
43 | // Prettier has not been included as plugin to avoid performance impact
44 | // add it as an extension for your IDE
45 | ],
46 |
47 | globals: {
48 | ga: true, // Google Analytics
49 | cordova: true,
50 | __statics: true,
51 | process: true,
52 | Capacitor: true,
53 | chrome: true
54 | },
55 |
56 | // add your custom rules here
57 | rules: {
58 | 'prefer-promise-reject-errors': 'off',
59 |
60 |
61 | // allow debugger during development only
62 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/.github/workflows/docker-image.yml:
--------------------------------------------------------------------------------
1 | name: Docker Image CI
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 |
9 | jobs:
10 |
11 | build:
12 |
13 | runs-on: self-hosted
14 |
15 | steps:
16 | - uses: actions/checkout@v3
17 | - name: Build the Docker image
18 | run: docker build . --file Dockerfile --tag crudapi/crudapi-admin-web:$(date +%s)
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .thumbs.db
3 | node_modules
4 |
5 | # Quasar core related directories
6 | .quasar
7 | /dist
8 |
9 | # Cordova related directories and files
10 | /src-cordova/node_modules
11 | /src-cordova/platforms
12 | /src-cordova/plugins
13 | /src-cordova/www
14 |
15 | # Capacitor related directories and files
16 | /src-capacitor/www
17 | /src-capacitor/node_modules
18 |
19 | # BEX related directories and files
20 | /src-bex/www
21 | /src-bex/js/core
22 |
23 | # Log files
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # Editor directories and files
29 | .idea
30 | *.suo
31 | *.ntvs*
32 | *.njsproj
33 | *.sln
34 |
35 |
36 | package-lock.json
37 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | plugins: [
5 | // to edit target browsers: use "browserslist" field in package.json
6 | require('autoprefixer')
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/.stylintrc:
--------------------------------------------------------------------------------
1 | {
2 | "blocks": "never",
3 | "brackets": "never",
4 | "colons": "never",
5 | "colors": "always",
6 | "commaSpace": "always",
7 | "commentSpace": "always",
8 | "cssLiteral": "never",
9 | "depthLimit": false,
10 | "duplicates": true,
11 | "efficient": "always",
12 | "extendPref": false,
13 | "globalDupe": true,
14 | "indentPref": 2,
15 | "leadingZero": "never",
16 | "maxErrors": false,
17 | "maxWarnings": false,
18 | "mixed": false,
19 | "namingConvention": false,
20 | "namingConventionStrict": false,
21 | "none": "never",
22 | "noImportant": false,
23 | "parenSpace": "never",
24 | "placeholder": false,
25 | "prefixVarsWithDollar": "always",
26 | "quotePref": "single",
27 | "semicolons": "never",
28 | "sortOrder": false,
29 | "stackedProperties": "never",
30 | "trailingWhitespace": "never",
31 | "universal": "never",
32 | "valid": true,
33 | "zeroUnits": "never",
34 | "zIndexNormalize": false
35 | }
36 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "dbaeumer.vscode-eslint",
4 | "esbenp.prettier-vscode",
5 | "octref.vetur"
6 | ],
7 | "unwantedRecommendations": [
8 | "hookyqr.beautify",
9 | "dbaeumer.jshint",
10 | "ms-vscode.vscode-typescript-tslint-plugin"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "vetur.validation.template": false,
3 | "vetur.format.enable": false,
4 | "eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"],
5 |
6 | "vetur.experimental.templateInterpolationService": true
7 | }
8 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | #FROM node:14-alpine as builder
2 | FROM registry.cn-qingdao.aliyuncs.com/dh-mirror/node:14-alpine as builder
3 |
4 | RUN apk add jq
5 |
6 | COPY package.json /crudapi-admin-web/package.json
7 |
8 | WORKDIR /crudapi-admin-web
9 | RUN npm install
10 |
11 | COPY . /crudapi-admin-web/
12 |
13 | WORKDIR /crudapi-admin-web
14 |
15 | RUN npm run build && \
16 | version=`cat package.json | jq .version | sed 's/\"//g'` && \
17 | echo $version && \
18 | mkdir -p /crudapi/dist/crudapi-admin-web/$version && \
19 | cd ./dist/spa && \
20 | tar -zcvf crudapi-admin-web-$version.tar.gz crudapi && \
21 | cp ./crudapi-admin-web-$version.tar.gz /crudapi/dist/crudapi-admin-web/$version && \
22 | rm -rf crudapi-admin-web-$version.tar.gz
23 |
24 | #FROM nginx:latest
25 | FROM registry.cn-qingdao.aliyuncs.com/dh-mirror/nginx:latest
26 |
27 | WORKDIR /crudapi-admin-web
28 |
29 | COPY --from=builder /crudapi-admin-web/dist/spa .
30 | COPY --from=builder /crudapi/dist /crudapi/dist/
31 |
32 | COPY ./docker/default.conf /etc/nginx/conf.d/default.conf
33 |
34 | EXPOSE 80
35 |
36 | COPY run.sh run.sh
37 |
38 | CMD ["/crudapi-admin-web/run.sh"]
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021-present crudapi
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Crudapi Admin Web (crudapi-admin-web)
2 |
3 | ## Language
4 | [中文](README_CN.md)
5 |
6 | ## GIT URL
7 | Name | Type | License | GitHub| Gitee
8 | --- | --- | --- | --- | ---
9 | crudapi-admin-web | Vue Qusar Code | Open Source | [crudapi-admin-web](https://github.com/crudapi/crudapi-admin-web) | [crudapi-admin-web](https://gitee.com/crudapi/crudapi-admin-web)
10 | crudapi-example| Java SDK | Free Forever | [crudapi-example](https://github.com/crudapi/crudapi-example) | [crudapi-example](https://gitee.com/crudapi/crudapi-example)
11 |
12 | ## Install the dependencies
13 | ```bash
14 | npm install
15 | ```
16 |
17 | ## Start the app in development mode (hot-code reloading, error reporting, etc.)
18 | ```bash
19 | npm run dev
20 | ```
21 |
22 | ## Lint the files
23 | ```bash
24 | npm run lint
25 | ```
26 |
27 | ## Build the app for production
28 | ```bash
29 | npm run build
30 | ```
31 |
32 | ## Config
33 | update file quasar.conf.js, set devServer->proxy->target
34 | quasar.conf.js
35 | ```javascript
36 | devServer: {
37 | https: false,
38 | port: 8080,
39 | open: true,
40 | proxy: {
41 | "/api/*": {
42 | target: "http://127.0.0.1:8888",
43 | changeOrigin: true
44 | }
45 | }
46 | }
47 | ```
48 |
49 | ## Docker
50 | ```bash
51 | docker build -t crudapi-admin-web:latest .
52 | docker rm -f crudapi-admin-web
53 | docker run -d -p 80:80 --name crudapi-admin-web crudapi-admin-web:latest
54 | ```
55 | Visit [ http://127.0.0.1/crudapi ](http://127.0.0.1/crudapi)
56 |
57 | ## Documentation
58 |
59 | [https://help.crudapi.cn](https://help.crudapi.cn)
60 |
61 | 1. [ 基于Vue和Quasar的前端SPA项目实战之环境搭建(一)](https://help.crudapi.cn/crudapi-admin-web/helloworld.html)
62 | 2. [ 基于Vue和Quasar的前端SPA项目实战之用户登录(二)](https://help.crudapi.cn/crudapi-admin-web/login.html)
63 | 3. [ 基于Vue和Quasar的前端SPA项目实战之布局菜单(三)](https://help.crudapi.cn/crudapi-admin-web/layout.html)
64 | 4. [ 基于Vue和Quasar的前端SPA项目实战之序列号(四)](https://help.crudapi.cn/crudapi-admin-web/sequence.html)
65 | 5. [ 基于Vue和Quasar的前端SPA项目实战之动态表单(五)](https://help.crudapi.cn/crudapi-admin-web/metadatatable.html)
66 | 6. [ 基于Vue和Quasar的前端SPA项目实战之表关系(六)](https://help.crudapi.cn/crudapi-admin-web/metadatarelation.html)
67 | 7. [ 基于Vue和Quasar的前端SPA项目实战之业务数据(七)](https://help.crudapi.cn/crudapi-admin-web/business.html)
68 | 8. [ 基于Vue和Quasar的前端SPA项目实战之docker部署(八)](https://help.crudapi.cn/crudapi-admin-web/docker.html)
69 | 9. [ 基于Vue和Quasar的前端SPA项目实战之数据导入(九)](https://help.crudapi.cn/crudapi-admin-web/import.html)
70 | 10. [ 基于Vue和Quasar的前端SPA项目实战之文件上传(九)](https://help.crudapi.cn/crudapi-admin-web/fileupload.html)
71 | 11. [ 基于Vue和Quasar的前端SPA项目实战之联合索引(十一)](https://help.crudapi.cn/crudapi-admin-web/unionindex.html)
72 | 12. [ 基于Vue和Quasar的前端SPA项目实战之数据库逆向(十二)](https://help.crudapi.cn/crudapi-admin-web/dbfirst.html)
73 | 13. [ 基于Vue和Quasar的前端SPA项目实战之数据导出(十三)](https://help.crudapi.cn/crudapi-admin-web/export.html)
74 | 14. [ 基于Vue和Quasar的前端SPA项目实战之模块管理(十四)](https://help.crudapi.cn/crudapi-admin-web/module.html)
75 | 15. [ 基于Vue和Quasar的前端SPA项目实战之元数据导出导入(十五)](https://help.crudapi.cn/crudapi-admin-web/metadataexportimport.html)
76 | 16. [ 基于Vue和Quasar的前端SPA项目实战之拖拽表单定制(十六)](https://help.crudapi.cn/crudapi-admin-web/formbuilder.html)
77 |
78 | Ongoing updates...
79 |
80 | ## Demo
81 | Demo url:[https://demo.crudapi.cn/crudapi/](https://demo.crudapi.cn/crudapi/)
82 |
83 | 
84 | Metadata table
85 |
86 | 
87 | Table relation
88 |
89 | 
90 | Bussiness Data
91 |
92 | ## Java SDK development
93 | ### GitHub repo
94 | [https://github.com/crudapi/crudapi-example](https://github.com/crudapi/crudapi-example)
95 |
96 | ### Gitee repo
97 | [https://gitee.com/crudapi/crudapi-example](https://gitee.com/crudapi/crudapi-example)
98 |
99 | ## Contact
100 | #### Email
101 | admin@crudapi.cn
102 |
103 | #### QQ
104 | 1440737304
105 |
106 | #### QQQun
107 | 632034576
108 |
109 | #### Weixin
110 | undefinedneqnull
111 |
112 |
113 |

114 |
115 |
116 | #### WeixinQun
117 |
118 |

119 |
120 |
121 | If you have any questions, please contact us!
122 |
123 | ## License
124 |
125 | Copyright (c) 2021-present crudapi
126 |
127 | [MIT License](http://en.wikipedia.org/wiki/MIT_License)
128 |
--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
1 | # crudapi后台管理WEB (crudapi-admin-web)
2 |
3 | ## 语言
4 | [English](README.md)
5 |
6 | ## GIT地址
7 | 名称 | 类型 | 授权 | GitHub仓库 | Gitee仓库
8 | --- | --- | --- | --- | ---
9 | crudapi-admin-web | Vue Qusar源码 | 开源 | [crudapi-admin-web](https://github.com/crudapi/crudapi-admin-web) | [crudapi-admin-web](https://gitee.com/crudapi/crudapi-admin-web)
10 | crudapi-example| Java集成SDK | 永久免费 | [crudapi-example](https://github.com/crudapi/crudapi-example) | [crudapi-example](https://gitee.com/crudapi/crudapi-example)
11 |
12 | ## 安装npm依赖包
13 | ```bash
14 | npm install
15 | ```
16 |
17 | ## 调试模式运行(代码热加载,错误提示等)
18 | ```bash
19 | npm run dev
20 | ```
21 |
22 | ## 代码静态检查
23 | ```bash
24 | npm run lint
25 | ```
26 |
27 | ## 编译发布
28 | ```bash
29 | npm run build
30 | ```
31 |
32 | ## 修改配置
33 | 修改quasar.conf.js文件中devServer->proxy->target
34 |
35 | ```javascript
36 | devServer: {
37 | https: false,
38 | port: 8080,
39 | open: true,
40 | proxy: {
41 | "/api/*": {
42 | target: "http://127.0.0.1:8888",
43 | changeOrigin: true
44 | }
45 | }
46 | }
47 | ```
48 |
49 | ## Docker部署
50 | ```bash
51 | docker build -t crudapi-admin-web:latest .
52 | docker rm -f crudapi-admin-web
53 | docker run -d -p 80:80 --name crudapi-admin-web crudapi-admin-web:latest
54 | ```
55 | 访问[ http://127.0.0.1/crudapi ](http://127.0.0.1/crudapi)
56 |
57 |
58 | ## 文档
59 |
60 | [https://help.crudapi.cn](https://help.crudapi.cn)
61 |
62 | 1. [ 基于Vue和Quasar的前端SPA项目实战之环境搭建(一)](https://help.crudapi.cn/crudapi-admin-web/helloworld.html)
63 | 2. [ 基于Vue和Quasar的前端SPA项目实战之用户登录(二)](https://help.crudapi.cn/crudapi-admin-web/login.html)
64 | 3. [ 基于Vue和Quasar的前端SPA项目实战之布局菜单(三)](https://help.crudapi.cn/crudapi-admin-web/layout.html)
65 | 4. [ 基于Vue和Quasar的前端SPA项目实战之序列号(四)](https://help.crudapi.cn/crudapi-admin-web/sequence.html)
66 | 5. [ 基于Vue和Quasar的前端SPA项目实战之动态表单(五)](https://help.crudapi.cn/crudapi-admin-web/metadatatable.html)
67 | 6. [ 基于Vue和Quasar的前端SPA项目实战之表关系(六)](https://help.crudapi.cn/crudapi-admin-web/metadatarelation.html)
68 | 7. [ 基于Vue和Quasar的前端SPA项目实战之业务数据(七)](https://help.crudapi.cn/crudapi-admin-web/business.html)
69 | 8. [ 基于Vue和Quasar的前端SPA项目实战之docker部署(八)](https://help.crudapi.cn/crudapi-admin-web/docker.html)
70 | 9. [ 基于Vue和Quasar的前端SPA项目实战之数据导入(九)](https://help.crudapi.cn/crudapi-admin-web/import.html)
71 | 10. [ 基于Vue和Quasar的前端SPA项目实战之文件上传(九)](https://help.crudapi.cn/crudapi-admin-web/fileupload.html)
72 | 11. [ 基于Vue和Quasar的前端SPA项目实战之联合索引(十一)](https://help.crudapi.cn/crudapi-admin-web/unionindex.html)
73 | 12. [ 基于Vue和Quasar的前端SPA项目实战之数据库逆向(十二)](https://help.crudapi.cn/crudapi-admin-web/dbfirst.html)
74 | 13. [ 基于Vue和Quasar的前端SPA项目实战之数据导出(十三)](https://help.crudapi.cn/crudapi-admin-web/export.html)
75 | 14. [ 基于Vue和Quasar的前端SPA项目实战之模块管理(十四)](https://help.crudapi.cn/crudapi-admin-web/module.html)
76 | 15. [ 基于Vue和Quasar的前端SPA项目实战之元数据导出导入(十五)](https://help.crudapi.cn/crudapi-admin-web/metadataexportimport.html)
77 | 16. [ 基于Vue和Quasar的前端SPA项目实战之拖拽表单定制(十六)](https://help.crudapi.cn/crudapi-admin-web/formbuilder.html)
78 |
79 | 持续更新中。。。
80 |
81 | ## 演示
82 | 演示地址:[https://demo.crudapi.cn/crudapi/](https://demo.crudapi.cn/crudapi/)
83 |
84 | 
85 | 表单对应不同的对象
86 |
87 | 
88 | 表关系图显示不同对象之间的关系
89 |
90 | 
91 | 业务数据操作
92 |
93 | ## Java SDK 二次开发
94 | ### GitHub仓库
95 | [https://github.com/crudapi/crudapi-example](https://github.com/crudapi/crudapi-example)
96 |
97 | ### Gitee仓库
98 | [https://gitee.com/crudapi/crudapi-example](https://gitee.com/crudapi/crudapi-example)
99 |
100 |
101 | ## 联系方式
102 | #### 邮箱
103 | admin@crudapi.cn
104 |
105 | #### QQ
106 | 1440737304
107 |
108 | #### QQ群
109 | 632034576
110 |
111 | #### 微信
112 | undefinedneqnull
113 |
114 |
115 |

116 |
117 |
118 | #### 微信群
119 |
120 |

121 |
122 |
123 | 如有任何问题,欢迎咨询和交流!
124 |
125 | ## 授权
126 |
127 | Copyright (c) 2021-present crudapi
128 |
129 | [MIT License](https://baike.baidu.com/item/MIT许可证)
130 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | presets: [
4 | '@quasar/babel-preset-app'
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | export QUASAR_PUBLIC_PATH=mapapi
3 | npm run build
4 |
5 |
--------------------------------------------------------------------------------
/docker/README.md:
--------------------------------------------------------------------------------
1 | ## docker
2 | ```bash
3 | docker build -t crudapi-admin-web:latest .
4 | docker rm -f crudapi-admin-web
5 | docker run -d -p 80:80 --name crudapi-admin-web crudapi-admin-web:latest
6 | ```
7 |
--------------------------------------------------------------------------------
/docker/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name localhost;
4 |
5 | charset 'utf-8';
6 | #access_log /var/log/nginx/host.access.log main;
7 |
8 | #error_page 404 /404.html;
9 |
10 | # redirect server error pages to the static page /50x.html
11 | #
12 | error_page 500 502 503 504 /50x.html;
13 | location = /50x.html {
14 | root /usr/share/nginx/html;
15 | }
16 |
17 | location ~ /api {
18 | proxy_pass http://demo.crudapi.cn;
19 | }
20 |
21 | location / {
22 | root /crudapi-admin-web;
23 | index index.html index.htm;
24 | try_files $uri $uri/ /crudapi/index.html;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/img/crudapiweixin.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/img/crudapiweixin.jpeg
--------------------------------------------------------------------------------
/img/customer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/img/customer.png
--------------------------------------------------------------------------------
/img/relation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/img/relation.png
--------------------------------------------------------------------------------
/img/table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/img/table.png
--------------------------------------------------------------------------------
/img/weixinqun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/img/weixinqun.png
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "src/*": [
6 | "src/*"
7 | ],
8 | "app/*": [
9 | "*"
10 | ],
11 | "components/*": [
12 | "src/components/*"
13 | ],
14 | "layouts/*": [
15 | "src/layouts/*"
16 | ],
17 | "pages/*": [
18 | "src/pages/*"
19 | ],
20 | "assets/*": [
21 | "src/assets/*"
22 | ],
23 | "boot/*": [
24 | "src/boot/*"
25 | ],
26 | "vue$": [
27 | "node_modules/vue/dist/vue.esm.js"
28 | ]
29 | }
30 | },
31 | "exclude": [
32 | "dist",
33 | ".quasar",
34 | "node_modules"
35 | ]
36 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "crudapi-admin-web",
3 | "version": "1.6.2",
4 | "description": "Crudapi Admin Web",
5 | "productName": "crudapi增删改查接口后台管理系统",
6 | "author": "admin@crudapi.cn",
7 | "private": false,
8 | "license": "MIT",
9 | "scripts": {
10 | "dev": "quasar dev",
11 | "build": "quasar build",
12 | "lint": "eslint --ext .js,.vue ./",
13 | "test": "echo \"No test specified\" && exit 0"
14 | },
15 | "dependencies": {
16 | "@antv/g6": "^3.3.6",
17 | "@quasar/extras": "^1.0.0",
18 | "axios": "^0.18.1",
19 | "codemirror": "^5.65.6",
20 | "core-js": "^3.6.5",
21 | "form-data": "^4.0.0",
22 | "quasar": "^1.0.0",
23 | "sql-formatter": "^7.0.4",
24 | "vue-i18n": "^8.0.0",
25 | "vuedraggable": "^2.24.3"
26 | },
27 | "devDependencies": {
28 | "@quasar/app": "^2.0.0",
29 | "babel-eslint": "^10.0.1",
30 | "eslint": "^6.8.0",
31 | "eslint-config-prettier": "^6.9.0",
32 | "eslint-loader": "^3.0.3",
33 | "eslint-plugin-vue": "^6.1.2"
34 | },
35 | "browserslist": [
36 | "ie >= 11",
37 | "last 10 Chrome versions",
38 | "last 10 Firefox versions",
39 | "last 4 Edge versions",
40 | "last 7 Safari versions",
41 | "last 8 Android versions",
42 | "last 8 ChromeAndroid versions",
43 | "last 8 FirefoxAndroid versions",
44 | "last 10 iOS versions",
45 | "last 5 Opera versions"
46 | ],
47 | "engines": {
48 | "node": ">= 10.18.1",
49 | "npm": ">= 6.13.4",
50 | "yarn": ">= 1.21.1"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/public/crudapi-mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/public/crudapi-mini.png
--------------------------------------------------------------------------------
/public/crudapi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/public/crudapi.png
--------------------------------------------------------------------------------
/public/crudapiweixin.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/public/crudapiweixin.jpeg
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/public/favicon.ico
--------------------------------------------------------------------------------
/public/icons/favicon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/public/icons/favicon-128x128.png
--------------------------------------------------------------------------------
/public/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/public/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/public/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/icons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/public/icons/favicon-96x96.png
--------------------------------------------------------------------------------
/public/price.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/public/price.png
--------------------------------------------------------------------------------
/public/weixinqun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/public/weixinqun.png
--------------------------------------------------------------------------------
/quasar.conf.js:
--------------------------------------------------------------------------------
1 | /*
2 | * This file runs in a Node context (it's NOT transpiled by Babel), so use only
3 | * the ES6 features that are supported by your Node version. https://node.green/
4 | */
5 |
6 | // Configuration for your app
7 | // https://quasar.dev/quasar-cli/quasar-conf-js
8 | /* eslint-env node */
9 |
10 | module.exports = function ( ctx ) {
11 | const publicPath = process.env.QUASAR_PUBLIC_PATH || "crudapi";
12 |
13 | return {
14 | // https://quasar.dev/quasar-cli/supporting-ts
15 | supportTS: false,
16 |
17 | // https://quasar.dev/quasar-cli/prefetch-feature
18 | // preFetch: true,
19 |
20 | // app boot file (/src/boot)
21 | // --> boot files are part of "main.js"
22 | // https://quasar.dev/quasar-cli/boot-files
23 | boot: [
24 |
25 | 'i18n',
26 | 'axios',
27 | 'cpage',
28 | 'cfile',
29 | 'csqleditor',
30 | 'ctablenew',
31 | 'ctablelist',
32 | 'ctableedit',
33 | 'ctablelistedit',
34 | 'cindexlist',
35 | 'ctablelistread',
36 | 'crawDisplayer',
37 | 'cvaluedialog'
38 | ],
39 |
40 | // https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
41 | css: [
42 | 'app.styl'
43 | ],
44 |
45 | // https://github.com/quasarframework/quasar/tree/dev/extras
46 | extras: [
47 | // 'ionicons-v4',
48 | // 'mdi-v5',
49 | // 'fontawesome-v5',
50 | // 'eva-icons',
51 | // 'themify',
52 | // 'line-awesome',
53 | // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
54 |
55 | 'roboto-font', // optional, you are not bound to it
56 | 'material-icons', // optional, you are not bound to it
57 | 'material-icons-outlined'
58 | ],
59 |
60 | // Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
61 | build: {
62 | vueRouterMode: 'history', // available values: 'hash', 'history'
63 |
64 | // transpile: false,
65 |
66 | // Add dependencies for transpiling with Babel (Array of string/regex)
67 | // (from node_modules, which are by default not transpiled).
68 | // Applies only if "transpile" is set to true.
69 | // transpileDependencies: [],
70 |
71 | // rtl: false, // https://quasar.dev/options/rtl-support
72 | // preloadChunks: true,
73 | // showProgress: false,
74 | // gzip: true,
75 | // analyze: true,
76 |
77 | // Options below are automatically set depending on the env, set them if you want to override
78 | // extractCSS: false,
79 |
80 | // https://quasar.dev/quasar-cli/handling-webpack
81 | extendWebpack (cfg) {
82 | cfg.module.rules.push({
83 | enforce: 'pre',
84 | test: /\.(js|vue)$/,
85 | loader: 'eslint-loader',
86 | exclude: /node_modules/
87 | })
88 | },
89 | publicPath: `${publicPath}`,
90 | distDir: `dist/${ctx.modeName}/${publicPath}`
91 | },
92 |
93 | // Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-devServer
94 | devServer: {
95 | https: false,
96 | port: 8080,
97 | open: true, // opens browser window automatically
98 | proxy: {
99 | //crudapi demo env
100 | "/api/*": {
101 | target: "https://demo.crudapi.cn",
102 | changeOrigin: true
103 | },
104 | "/download/*": {
105 | target: "https://demo.crudapi.cn",
106 | changeOrigin: true
107 | }
108 | //local env
109 | // "/api/*": {
110 | // target: "http://127.0.0.1:8888",
111 | // changeOrigin: true
112 | // },
113 | // "/download/*": {
114 | // target: "http://127.0.0.1:8888",
115 | // changeOrigin: true
116 | // }
117 | }
118 | },
119 |
120 | // https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-framework
121 | framework: {
122 | iconSet: 'material-icons', // Quasar icon set
123 | lang: 'zh-hans', // Quasar language pack
124 | config: {},
125 |
126 | // Possible values for "importStrategy":
127 | // * 'auto' - (DEFAULT) Auto-import needed Quasar components & directives
128 | // * 'all' - Manually specify what to import
129 | importStrategy: 'auto',
130 |
131 | // For special cases outside of where "auto" importStrategy can have an impact
132 | // (like functional components as one of the examples),
133 | // you can manually specify Quasar components/directives to be available everywhere:
134 | //
135 | // components: [],
136 | // directives: [],
137 |
138 | // Quasar plugins
139 | plugins: [
140 | 'LocalStorage',
141 | 'Notify',
142 | 'Loading',
143 | 'Dialog',
144 | 'SessionStorage'
145 | ]
146 | },
147 |
148 | // animations: 'all', // --- includes all animations
149 | // https://quasar.dev/options/animations
150 | animations: [],
151 |
152 | // https://quasar.dev/quasar-cli/developing-ssr/configuring-ssr
153 | ssr: {
154 | pwa: false
155 | },
156 |
157 | // https://quasar.dev/quasar-cli/developing-pwa/configuring-pwa
158 | pwa: {
159 | workboxPluginMode: 'GenerateSW', // 'GenerateSW' or 'InjectManifest'
160 | workboxOptions: {}, // only for GenerateSW
161 | manifest: {
162 | name: `Crudapi Admin Web App`,
163 | short_name: `Crudapi Admin Web App`,
164 | description: `Crudapi Admin Web`,
165 | display: 'standalone',
166 | orientation: 'portrait',
167 | background_color: '#ffffff',
168 | theme_color: '#027be3',
169 | icons: [
170 | {
171 | src: 'icons/icon-128x128.png',
172 | sizes: '128x128',
173 | type: 'image/png'
174 | },
175 | {
176 | src: 'icons/icon-192x192.png',
177 | sizes: '192x192',
178 | type: 'image/png'
179 | },
180 | {
181 | src: 'icons/icon-256x256.png',
182 | sizes: '256x256',
183 | type: 'image/png'
184 | },
185 | {
186 | src: 'icons/icon-384x384.png',
187 | sizes: '384x384',
188 | type: 'image/png'
189 | },
190 | {
191 | src: 'icons/icon-512x512.png',
192 | sizes: '512x512',
193 | type: 'image/png'
194 | }
195 | ]
196 | }
197 | },
198 |
199 | // Full list of options: https://quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
200 | cordova: {
201 | // noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
202 | },
203 |
204 | // Full list of options: https://quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
205 | capacitor: {
206 | hideSplashscreen: true
207 | },
208 |
209 | // Full list of options: https://quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
210 | electron: {
211 | bundler: 'packager', // 'packager' or 'builder'
212 |
213 | packager: {
214 | // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
215 |
216 | // OS X / Mac App Store
217 | // appBundleId: '',
218 | // appCategoryType: '',
219 | // osxSign: '',
220 | // protocol: 'myapp://path',
221 |
222 | // Windows only
223 | // win32metadata: { ... }
224 | },
225 |
226 | builder: {
227 | // https://www.electron.build/configuration/configuration
228 |
229 | appId: 'crudapi-admin-web'
230 | },
231 |
232 | // More info: https://quasar.dev/quasar-cli/developing-electron-apps/node-integration
233 | nodeIntegration: true,
234 |
235 | extendWebpack (/* cfg */) {
236 | // do something with Electron main process Webpack cfg
237 | // chainWebpack also available besides this extendWebpack
238 | }
239 | }
240 | }
241 | }
242 |
--------------------------------------------------------------------------------
/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | echo "cp crudpi-admin-web"
3 |
4 | cp -R /crudapi/dist/* /crudapi/npm
5 | ls -al /crudapi/npm
6 | nginx -g "daemon off;"
7 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
--------------------------------------------------------------------------------
/src/api/file.js:
--------------------------------------------------------------------------------
1 | import { axiosInstance } from "boot/axios";
2 |
3 | const HEADERS = {
4 | "Content-Type": "multipart/form-data"
5 | };
6 |
7 | const file = {
8 | upload: async function(data, progressCallback) {
9 | console.log("file->upload")
10 | return axiosInstance.post(`/api/file` , data,
11 | {
12 | headers: HEADERS,
13 | onUploadProgress: (progressEvent) => {
14 | if (progressCallback) {
15 | progressCallback(progressEvent)
16 | }
17 | }
18 | });
19 | },
20 | bigUpload: async function(data, progressCallback) {
21 | console.log("file->bigUpload")
22 | return axiosInstance.post(`/api/file/big` , data,
23 | {
24 | headers: HEADERS,
25 | onUploadProgress: (progressEvent) => {
26 | if (progressCallback) {
27 | progressCallback(progressEvent)
28 | }
29 | }
30 | });
31 | }
32 | };
33 |
34 | export { file };
35 |
--------------------------------------------------------------------------------
/src/api/index.js:
--------------------------------------------------------------------------------
1 | export { user } from "./user";
2 | export { metadataTable } from "./metadataTable";
3 | export { metadataSequence } from "./metadataSequence";
4 | export { metadataRelation } from "./metadataRelation";
5 | export { file } from "./file";
6 | export { table } from "./table";
7 |
--------------------------------------------------------------------------------
/src/api/metadataRelation.js:
--------------------------------------------------------------------------------
1 | import { axiosInstance } from "boot/axios";
2 |
3 | const metadataRelation = {
4 | create: function(dataSource, data) {
5 | return axiosInstance.post("/api/metadata/tablerelations",
6 | data,
7 | {
8 | dataSource: dataSource
9 | }
10 | );
11 | },
12 | update: function(dataSource, id, data) {
13 | return axiosInstance.patch("/api/metadata/tablerelations/" + id,
14 | data,
15 | {
16 | dataSource: dataSource
17 | }
18 | );
19 | },
20 | list: function(dataSource, page, rowsPerPage, search, query) {
21 | if (!page) {
22 | page = 1
23 | }
24 |
25 | if (!rowsPerPage) {
26 | rowsPerPage = 999
27 | }
28 |
29 | return axiosInstance.get("/api/metadata/tablerelations",
30 | {
31 | params: {
32 | offset: (page - 1) * rowsPerPage,
33 | limit: rowsPerPage,
34 | search: search,
35 | ...query
36 | },
37 | dataSource: dataSource
38 | }
39 | );
40 | },
41 | count: function(dataSource, search, query) {
42 | return axiosInstance.get("/api/metadata/tablerelations/count",
43 | {
44 | params: {
45 | search: search,
46 | ...query
47 | },
48 | dataSource: dataSource
49 | }
50 | );
51 | },
52 | get: function(dataSource, id) {
53 | return axiosInstance.get("/api/metadata/tablerelations/" + id,
54 | {
55 | params: {
56 | }
57 | }
58 | );
59 | },
60 | getFromTableById: function(dataSource, id) {
61 | return axiosInstance.get("/api/metadata/tablerelations/fromTable/" + id,
62 | {
63 | params: {
64 | },
65 | dataSource: dataSource
66 | }
67 | );
68 | },
69 | getFromTableByName: function(dataSource, name) {
70 | return axiosInstance.get("/api/metadata/tablerelations/fromTable/name/" + name,
71 | {
72 | params: {
73 | },
74 | dataSource: dataSource
75 | }
76 | );
77 | },
78 | delete: function(dataSource, id) {
79 | return axiosInstance.delete("/api/metadata/tablerelations/" + id,
80 | {
81 | dataSource: dataSource
82 | });
83 | },
84 | batchDelete: function(dataSource, ids) {
85 | return axiosInstance.delete("/api/metadata/tablerelations",
86 | {
87 | data: ids,
88 | dataSource: dataSource
89 | }
90 | );
91 | }
92 | };
93 |
94 | export { metadataRelation };
95 |
--------------------------------------------------------------------------------
/src/api/metadataSequence.js:
--------------------------------------------------------------------------------
1 | import { axiosInstance } from "boot/axios";
2 |
3 | const metadataSequence = {
4 | create: function(dataSource, data) {
5 | return axiosInstance.post("/api/metadata/sequences",
6 | data,
7 | {
8 | dataSource: dataSource
9 | }
10 | );
11 | },
12 | update: function(dataSource, id, data) {
13 | return axiosInstance.patch("/api/metadata/sequences/" + id,
14 | data,
15 | {
16 | dataSource: dataSource
17 | }
18 | );
19 | },
20 | list: function(dataSource, page, rowsPerPage, search, query) {
21 | if (!page) {
22 | page = 1
23 | }
24 |
25 | if (!rowsPerPage) {
26 | rowsPerPage = 10
27 | }
28 |
29 | return axiosInstance.get("/api/metadata/sequences",
30 | {
31 | params: {
32 | offset: (page - 1) * rowsPerPage,
33 | limit: rowsPerPage,
34 | search: search,
35 | ...query
36 | },
37 | dataSource: dataSource
38 | }
39 | );
40 | },
41 | count: function(dataSource, search, query) {
42 | return axiosInstance.get("/api/metadata/sequences/count",
43 | {
44 | params: {
45 | search: search,
46 | ...query
47 | },
48 | dataSource: dataSource
49 | }
50 | );
51 | },
52 | get: function(dataSource, id) {
53 | return axiosInstance.get("/api/metadata/sequences/" + id,
54 | {
55 | params: {
56 | },
57 | dataSource: dataSource
58 | }
59 | );
60 | },
61 | delete: function(dataSource, id) {
62 | return axiosInstance.delete("/api/metadata/sequences/" + id,
63 | {
64 | dataSource: dataSource
65 | });
66 | },
67 | batchDelete: function(dataSource, ids) {
68 | return axiosInstance.delete("/api/metadata/sequences",
69 | {
70 | data: ids,
71 | dataSource: dataSource
72 | }
73 | );
74 | }
75 | };
76 |
77 | export { metadataSequence };
78 |
--------------------------------------------------------------------------------
/src/api/metadataTable.js:
--------------------------------------------------------------------------------
1 | import { axiosInstance } from "boot/axios";
2 |
3 | const HEADERS = {
4 | "Content-Type": "multipart/form-data"
5 | };
6 |
7 |
8 | const metadataTable = {
9 | create: function(dataSource, data) {
10 | return axiosInstance.post("/api/metadata/tables",
11 | data,
12 | {
13 | dataSource: dataSource
14 | }
15 | );
16 | },
17 | update: function(dataSource, id, data) {
18 | return axiosInstance.patch("/api/metadata/tables/" + id,
19 | data,
20 | {
21 | dataSource: dataSource
22 | }
23 | );
24 | },
25 | list: function(dataSource, page, rowsPerPage, search, query) {
26 | if (!page) {
27 | page = 1
28 | }
29 |
30 | if (!rowsPerPage) {
31 | rowsPerPage = 10
32 | }
33 |
34 | return axiosInstance.get("/api/metadata/tables",
35 | {
36 | params: {
37 | offset: (page - 1) * rowsPerPage,
38 | limit: rowsPerPage,
39 | search: search,
40 | ...query
41 | },
42 | dataSource: dataSource
43 | //permission: ["ROLE_META_TABLE_R"]
44 | }
45 | );
46 | },
47 | count: function(dataSource, search, query) {
48 | return axiosInstance.get("/api/metadata/tables/count",
49 | {
50 | params: {
51 | search: search,
52 | ...query
53 | },
54 | dataSource: dataSource
55 | }
56 | );
57 | },
58 | get: function(dataSource, id) {
59 | return axiosInstance.get("/api/metadata/tables/" + id,
60 | {
61 | params: {
62 | },
63 | dataSource: dataSource
64 | }
65 | );
66 | },
67 | getByName: function(dataSource, name) {
68 | return axiosInstance.get("/api/metadata/tables/name/" + name,
69 | {
70 | params: {
71 | },
72 | dataSource: dataSource
73 | }
74 | );
75 | },
76 | getMetadata: function(dataSource, name) {
77 | return axiosInstance.get("/api/metadata/tables/metadatas/" + name,
78 | {
79 | params: {
80 | },
81 | dataSource: dataSource
82 | }
83 | );
84 | },
85 | getMetadatas: function(dataSource) {
86 | return axiosInstance.get("/api/metadata/tables/metadatas",
87 | {
88 | params: {
89 | },
90 | dataSource: dataSource
91 | }
92 | );
93 | },
94 | reverse: function(dataSource, tableName) {
95 | return axiosInstance.post("/api/metadata/tables/metadatas/reverse/" + tableName,
96 | {},
97 | {
98 | dataSource: dataSource
99 | });
100 | },
101 | batchReverse: function(dataSource, tableNames) {
102 | return axiosInstance.post("/api/metadata/tables/metadatas/reverse", tableNames,
103 | {
104 | dataSource: dataSource
105 | });
106 | },
107 | repairMeataData: function(dataSource, name, columnNameLsit) {
108 | return axiosInstance.patch("/api/metadata/tables/metadata/" + name,
109 | columnNameLsit,
110 | {
111 | dataSource: dataSource
112 | }
113 | );
114 | },
115 | delete: function(dataSource, id, isDropPhysicalTable) {
116 | return axiosInstance.delete("/api/metadata/tables/" + id, {
117 | params: {
118 | isDropPhysicalTable: isDropPhysicalTable
119 | },
120 | dataSource: dataSource
121 | });
122 | },
123 | batchDelete: function(dataSource, ids, isDropPhysicalTable) {
124 | return axiosInstance.delete("/api/metadata/tables",
125 | {
126 | data: ids,
127 | params: {
128 | isDropPhysicalTable: isDropPhysicalTable
129 | },
130 | dataSource: dataSource
131 | }
132 | );
133 | },
134 | importFile: async function(dataSource, data, progressCallback) {
135 | return axiosInstance.post("/api/metadata/tables/file/import", data,
136 | {
137 | headers: HEADERS,
138 | onUploadProgress: (progressEvent) => {
139 | if (progressCallback) {
140 | progressCallback(progressEvent)
141 | }
142 | },
143 | dataSource: dataSource
144 | });
145 | },
146 | import: async function(dataSource, data) {
147 | return axiosInstance.post("/api/metadata/tables/import", data,
148 | {
149 | dataSource: dataSource
150 | });
151 | },
152 | export: function(dataSource, ids) {
153 | return axiosInstance.post("/api/metadata/tables/export",
154 | ids,
155 | {
156 | dataSource: dataSource
157 | }
158 | );
159 | },
160 | listDataSource: function() {
161 | return axiosInstance.get("/api/metadata/dataSources",
162 | {
163 | params: {
164 | }
165 | }
166 | );
167 | }
168 | };
169 |
170 | export { metadataTable };
171 |
--------------------------------------------------------------------------------
/src/api/table.js:
--------------------------------------------------------------------------------
1 | import { axiosInstance } from "boot/axios";
2 |
3 |
4 | const HEADERS = {
5 | "Content-Type": "multipart/form-data"
6 | };
7 |
8 |
9 | const table = {
10 | create: function(dataSource, tableName, data) {
11 | return axiosInstance.post("/api/business/" + tableName,
12 | data,
13 | {
14 | dataSource: dataSource
15 | }
16 | );
17 | },
18 | update: function(dataSource, tableName, id, data) {
19 | return axiosInstance.patch("/api/business/" + tableName + "/" + id,
20 | data,
21 | {
22 | dataSource: dataSource
23 | }
24 | );
25 | },
26 | list: function(dataSource, tableName, page, rowsPerPage, search, query, filter, select) {
27 | if (!page) {
28 | page = 1
29 | }
30 |
31 | if (!rowsPerPage) {
32 | rowsPerPage = 10
33 | }
34 |
35 | let filterStrEncode;
36 | if (filter) {
37 | let filterStr = JSON.stringify(filter);
38 | filterStrEncode = encodeURIComponent(filterStr);
39 | }
40 |
41 | return axiosInstance.get("/api/business/" + tableName,
42 | {
43 | params: {
44 | offset: (page - 1) * rowsPerPage,
45 | limit: rowsPerPage,
46 | search: search,
47 | ...query,
48 | filter: filterStrEncode,
49 | select: select
50 | },
51 | dataSource: dataSource
52 | }
53 | );
54 | },
55 | listAllByIds: function(dataSource, tableName, ids) {
56 | let idStr = ids.join(",");
57 | return axiosInstance.get("/api/business/" + tableName + "/all",
58 | {
59 | params: {
60 | ids: idStr
61 | },
62 | dataSource: dataSource
63 | }
64 | );
65 | },
66 | count: function(dataSource, tableName, search, query, filter) {
67 | let filterStrEncode;
68 | if (filter) {
69 | let filterStr = JSON.stringify(filter);
70 | filterStrEncode = encodeURIComponent(filterStr);
71 | }
72 |
73 | return axiosInstance.get("/api/business/" + tableName + "/count",
74 | {
75 | params: {
76 | search: search,
77 | ...query,
78 | filter: filterStrEncode
79 | },
80 | dataSource: dataSource
81 | }
82 | );
83 | },
84 | get: function(dataSource, tableName, id) {
85 | return axiosInstance.get("/api/business/" + tableName + "/" + id,
86 | {
87 | params: {
88 | },
89 | dataSource: dataSource
90 | }
91 | );
92 | },
93 | delete: function(dataSource, tableName, id, isSoftDelete) {
94 | return axiosInstance.delete("/api/business/" + tableName + "/" + id,
95 | {
96 | params: {
97 | isSoftDelete: isSoftDelete
98 | },
99 | dataSource: dataSource
100 | });
101 | },
102 | batchDelete: function(dataSource, tableName, ids, isSoftDelete) {
103 | return axiosInstance.delete("/api/business/" + tableName,
104 | {
105 | data: ids,
106 | params: {
107 | isSoftDelete: isSoftDelete
108 | },
109 | dataSource: dataSource
110 | }
111 | );
112 | },
113 | import: async function(dataSource, tableName, data, progressCallback) {
114 | console.log("table->import")
115 | console.log(data)
116 | return axiosInstance.post("/api/business/" + tableName + "/import", data,
117 | {
118 | headers: HEADERS,
119 | onUploadProgress: (progressEvent) => {
120 | if (progressCallback) {
121 | progressCallback(progressEvent)
122 | }
123 | },
124 | dataSource: dataSource
125 | });
126 | },
127 | multiExport: function(dataSource, ids) {
128 | return axiosInstance.post("/api/business/export",
129 | ids,
130 | {
131 | dataSource: dataSource
132 | }
133 | );
134 | },
135 | multiImport: async function(dataSource, data, progressCallback) {
136 | console.log("table->import")
137 | console.log(data)
138 | return axiosInstance.post("/api/business/import", data,
139 | {
140 | headers: HEADERS,
141 | onUploadProgress: (progressEvent) => {
142 | if (progressCallback) {
143 | progressCallback(progressEvent)
144 | }
145 | },
146 | dataSource: dataSource
147 | });
148 | },
149 | getImportTemplate: function(dataSource, tableName) {
150 | return axiosInstance.get("/api/business/" + tableName + "/import/template",
151 | {
152 | params: {
153 | },
154 | dataSource: dataSource
155 | }
156 | );
157 | },
158 | export: function(dataSource, tableName, select, search, query, filter) {
159 | let filterStrEncode;
160 | if (filter) {
161 | let filterStr = JSON.stringify(filter);
162 | filterStrEncode = encodeURIComponent(filterStr);
163 | }
164 | return axiosInstance.post("/api/business/" + tableName + "/export",
165 | {},
166 | {
167 | params: {
168 | select: select,
169 | search: search,
170 | ...query,
171 | filter: filterStrEncode
172 | },
173 | dataSource: dataSource
174 | }
175 | );
176 | },
177 | exportXml: function(dataSource, tableName, select, search, query, filter, isDisplayCaption) {
178 | let filterStrEncode;
179 | if (filter) {
180 | let filterStr = JSON.stringify(filter);
181 | filterStrEncode = encodeURIComponent(filterStr);
182 | }
183 | return axiosInstance.post("/api/business/" + tableName + "/export/xml",
184 | {},
185 | {
186 | params: {
187 | select: select,
188 | search: search,
189 | ...query,
190 | filter: filterStrEncode,
191 | isDisplayCaption: isDisplayCaption
192 | },
193 | dataSource: dataSource
194 | }
195 | );
196 | }
197 | };
198 |
199 | export { table };
200 |
--------------------------------------------------------------------------------
/src/api/user.js:
--------------------------------------------------------------------------------
1 | import { axiosInstance } from "boot/axios";
2 |
3 | const HEADERS = {
4 | "Content-Type": "application/x-www-form-urlencoded"
5 | };
6 |
7 | const user = {
8 | login: function(data) {
9 | return axiosInstance.post("/api/auth/login",
10 | data,
11 | {
12 | headers: HEADERS
13 | }
14 | );
15 | },
16 | logout: function() {
17 | return axiosInstance.get("/api/auth/logout",
18 | {
19 | headers: HEADERS
20 | }
21 | );
22 | },
23 | menu: function(dataSource) {
24 | return axiosInstance.get("/api/users/me/menu",
25 | {
26 | params: {},
27 | dataSource: dataSource
28 | }
29 | );
30 | },
31 | table: function(dataSource) {
32 | return axiosInstance.get("/api/users/me/table",
33 | {
34 | params: {},
35 | dataSource: dataSource
36 | }
37 | );
38 | }
39 | };
40 |
41 | export { user };
42 |
--------------------------------------------------------------------------------
/src/boot/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crudapi/crudapi-admin-web/5f3e6bee0055c3f96955ce64161bf84411241a0f/src/boot/.gitkeep
--------------------------------------------------------------------------------
/src/boot/axios.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import axios from 'axios'
3 | import { Notify } from "quasar";
4 | import qs from "qs";
5 | import Router from "../router/index";
6 | import { permissionService } from "../service";
7 |
8 | Vue.prototype.$axios = axios
9 |
10 | // We create our own axios instance and set a custom base URL.
11 | // Note that if we wouldn't set any config here we do not need
12 | // a named export, as we could just `import axios from 'axios'`
13 | const axiosInstance = axios.create({
14 | baseURL: process.env.API
15 | });
16 |
17 | axiosInstance.defaults.transformRequest = [
18 | function(data, headers) {
19 | // Do whatever you want to transform the data
20 | let contentType = headers["Content-Type"] || headers["content-type"];
21 | if (!contentType) {
22 | contentType = "application/json";
23 | headers["Content-Type"] = "application/json";
24 | }
25 |
26 | if (contentType.indexOf("multipart/form-data") >= 0) {
27 | return data;
28 | } else if (contentType.indexOf("application/x-www-form-urlencoded") >= 0) {
29 | return qs.stringify(data);
30 | }
31 |
32 | return JSON.stringify(data);
33 | }
34 | ];
35 |
36 | // Add a request interceptor
37 | axiosInstance.interceptors.request.use(
38 | function(config) {
39 | if (config.permission && !permissionService.check(config.permission)) {
40 | throw {
41 | message: "403 forbidden"
42 | };
43 | }
44 |
45 | if (config.dataSource) {
46 | console.log("config.dataSource = " + config.dataSource);
47 | config.headers["dataSource"] = config.dataSource;
48 | }
49 |
50 | return config;
51 | },
52 | function(error) {
53 | // Do something with request error
54 | return Promise.reject(error);
55 | }
56 | );
57 |
58 | function login() {
59 | setTimeout(() => {
60 | Router.push({
61 | path: "/login"
62 | });
63 | }, 1000);
64 | }
65 |
66 | // Add a response interceptor
67 | axiosInstance.interceptors.response.use(
68 | function(response) {
69 | // Any status code that lie within the range of 2xx cause this function to trigger
70 | // Do something with response data
71 | return response;
72 | },
73 | function(error) {
74 | // Any status codes that falls outside the range of 2xx cause this function to trigger
75 | // Do something with response error
76 |
77 | if (error.response) {
78 | if (error.response.status === 401) {
79 | Notify.create({
80 | message: error.response.data.message,
81 | type: 'negative'
82 | });
83 | login();
84 | } else if (error.response.data && error.response.data.message) {
85 | Notify.create({
86 | message: error.response.data.message,
87 | type: 'negative'
88 | });
89 | } else {
90 | Notify.create({
91 | message: error.response.statusText || error.response.status,
92 | type: 'negative'
93 | });
94 | }
95 | } else if (error.message.indexOf("timeout") > -1) {
96 | Notify.create({
97 | message: "Network timeout",
98 | type: 'negative'
99 | });
100 | } else if (error.message) {
101 | Notify.create({
102 | message: error.message,
103 | type: 'negative'
104 | });
105 | } else {
106 | Notify.create({
107 | message: "http request error",
108 | type: 'negative'
109 | });
110 | }
111 |
112 | return Promise.reject(error);
113 | }
114 | );
115 |
116 | // for use inside Vue files through this.$axios
117 | Vue.prototype.$axios = axiosInstance
118 |
119 | // Here we define a named export
120 | // that we can later use inside .js files:
121 | export { axiosInstance }
122 |
--------------------------------------------------------------------------------
/src/boot/cfile.js:
--------------------------------------------------------------------------------
1 | import cFile from "../components/CFile";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cFile);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/cindexlist.js:
--------------------------------------------------------------------------------
1 | import cIndexList from "../components/CIndexList";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cIndexList);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/cpage.js:
--------------------------------------------------------------------------------
1 | import cPage from "../components/CPage";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cPage);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/crawDisplayer.js:
--------------------------------------------------------------------------------
1 | import cRawDisplayer from "../components/CRawDisplayer";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cRawDisplayer);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/csqleditor.js:
--------------------------------------------------------------------------------
1 | import cSqlEditor from "../components/CSqlEditor";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cSqlEditor);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/ctableedit.js:
--------------------------------------------------------------------------------
1 | import cTableEdit from "../components/CTableEdit";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cTableEdit);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/ctablelist.js:
--------------------------------------------------------------------------------
1 | import cTableList from "../components/CTableList";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cTableList);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/ctablelistedit.js:
--------------------------------------------------------------------------------
1 | import cTableListEdit from "../components/CTableListEdit";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cTableListEdit);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/ctablelistread.js:
--------------------------------------------------------------------------------
1 | import cTableListRead from "../components/CTableListRead";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cTableListRead);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/ctablenew.js:
--------------------------------------------------------------------------------
1 | import cTableNew from "../components/CTableNew";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cTableNew);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/cvaluedialog.js:
--------------------------------------------------------------------------------
1 | import cValueDialog from "../components/CValueDialog";
2 |
3 | export default async ({ Vue }) => {
4 | Vue.use(cValueDialog);
5 | };
6 |
--------------------------------------------------------------------------------
/src/boot/i18n.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueI18n from 'vue-i18n'
3 | import messages from 'src/i18n'
4 |
5 | Vue.use(VueI18n)
6 |
7 | const i18n = new VueI18n({
8 | locale: 'zh-hans',
9 | fallbackLocale: 'zh-hans',
10 | messages
11 | })
12 |
13 | export default ({ app }) => {
14 | // Set i18n instance on app
15 | app.i18n = i18n
16 | }
17 |
18 | export { i18n }
19 |
--------------------------------------------------------------------------------
/src/components/CDownload/CDownloadDialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
文件已经生成,请点击下载!
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/components/CDownload/index.js:
--------------------------------------------------------------------------------
1 | import CTableListRead from "./CTableListRead.vue";
2 |
3 | const cTableListRead = {
4 | install: function(Vue) {
5 | Vue.component("CTableListRead", CTableListRead);
6 | }
7 | };
8 |
9 | export default cTableListRead;
10 |
--------------------------------------------------------------------------------
/src/components/CFile/CFile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
45 |
46 |
47 |
48 |
51 |
52 |
235 |
--------------------------------------------------------------------------------
/src/components/CFile/index.js:
--------------------------------------------------------------------------------
1 | import CFile from "./CFile.vue";
2 |
3 | const cFile = {
4 | install: function(Vue) {
5 | Vue.component("CFile", CFile);
6 | }
7 | };
8 |
9 | export default cFile;
10 |
--------------------------------------------------------------------------------
/src/components/CIndexList/CIndexList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
19 |
20 |
21 |
22 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
62 |
63 |
64 |
71 |
72 |
73 |
82 |
83 |
84 |
85 |
86 |
87 | {{ props.row.createdDate | dateTimeFormat }}
88 |
89 |
90 | {{ props.row.lastModifiedDate | dateTimeFormat }}
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
104 |
105 |
379 |
--------------------------------------------------------------------------------
/src/components/CIndexList/index.js:
--------------------------------------------------------------------------------
1 | import CIndexList from "./CIndexList.vue";
2 |
3 | const cIndexList = {
4 | install: function(Vue) {
5 | Vue.component("CIndexList", CIndexList);
6 | }
7 | };
8 |
9 | export default cIndexList;
10 |
--------------------------------------------------------------------------------
/src/components/CPage/CPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | 共 {{ pagination.count }} 条记录 第 {{ pagination.page }} /
9 | {{ Math.ceil(pagination.count / pagination.rowsPerPage) }}
10 | 页
12 |
13 |
29 |
30 |
31 |
32 |
39 |
40 |
41 |
42 |
跳至
43 |
44 |
51 |
52 |
53 |
页
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
81 |
82 |
185 |
--------------------------------------------------------------------------------
/src/components/CPage/index.js:
--------------------------------------------------------------------------------
1 | import CPage from "./CPage.vue";
2 |
3 | const cPage = {
4 | install: function(Vue) {
5 | Vue.component("CPage", CPage);
6 | }
7 | };
8 |
9 | export default cPage;
10 |
--------------------------------------------------------------------------------
/src/components/CRawDisplayer/CRawDisplayer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ valueString }}
5 |
6 |
7 |
27 |
32 |
--------------------------------------------------------------------------------
/src/components/CRawDisplayer/index.js:
--------------------------------------------------------------------------------
1 | import CRawDisplayer from "./CRawDisplayer.vue";
2 |
3 | const cRawDisplayer = {
4 | install: function(Vue) {
5 | Vue.component("CRawDisplayer", CRawDisplayer);
6 | }
7 | };
8 |
9 | export default cRawDisplayer;
10 |
--------------------------------------------------------------------------------
/src/components/CSqlEditor/CSqlEditor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
96 |
--------------------------------------------------------------------------------
/src/components/CSqlEditor/index.js:
--------------------------------------------------------------------------------
1 | import CSqlEditor from "./CSqlEditor.vue";
2 |
3 | const cSqlEditor = {
4 | install: function(Vue) {
5 | Vue.component("CSqlEditor", CSqlEditor);
6 | }
7 | };
8 |
9 | export default cSqlEditor;
10 |
--------------------------------------------------------------------------------
/src/components/CTableEdit/index.js:
--------------------------------------------------------------------------------
1 | import CTableEdit from "./CTableEdit.vue";
2 |
3 | const cTableEdit = {
4 | install: function(Vue) {
5 | Vue.component("CTableEdit", CTableEdit);
6 | }
7 | };
8 |
9 | export default cTableEdit;
10 |
--------------------------------------------------------------------------------
/src/components/CTableList/index.js:
--------------------------------------------------------------------------------
1 | import CTableList from "./CTableList.vue";
2 |
3 | const cTableList = {
4 | install: function(Vue) {
5 | Vue.component("CTableList", CTableList);
6 | }
7 | };
8 |
9 | export default cTableList;
10 |
--------------------------------------------------------------------------------
/src/components/CTableListEdit/index.js:
--------------------------------------------------------------------------------
1 | import CTableListEdit from "./CTableListEdit.vue";
2 |
3 | const cTableListEdit = {
4 | install: function(Vue) {
5 | Vue.component("CTableListEdit", CTableListEdit);
6 | }
7 | };
8 |
9 | export default cTableListEdit;
10 |
--------------------------------------------------------------------------------
/src/components/CTableListRead/CTableListReadDialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/components/CTableListRead/index.js:
--------------------------------------------------------------------------------
1 | import CTableListRead from "./CTableListRead.vue";
2 |
3 | const cTableListRead = {
4 | install: function(Vue) {
5 | Vue.component("CTableListRead", CTableListRead);
6 | }
7 | };
8 |
9 | export default cTableListRead;
10 |
--------------------------------------------------------------------------------
/src/components/CTableNew/index.js:
--------------------------------------------------------------------------------
1 | import CTableNew from "./CTableNew.vue";
2 |
3 | const cTableNew = {
4 | install: function(Vue) {
5 | Vue.component("CTableNew", CTableNew);
6 | }
7 | };
8 |
9 | export default cTableNew;
10 |
--------------------------------------------------------------------------------
/src/components/CValueDialog/CValueDialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/components/CValueDialog/index.js:
--------------------------------------------------------------------------------
1 | import CValueDialog from "./CValueDialog.vue";
2 |
3 | const cValueDialog = {
4 | install: function(Vue) {
5 | Vue.component("CValueDialog", CValueDialog);
6 | }
7 | };
8 |
9 | export default cValueDialog;
10 |
--------------------------------------------------------------------------------
/src/components/EssentialLink.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
14 |
15 |
16 | {{ title }}
17 |
18 | {{ caption }}
19 |
20 |
21 |
22 |
23 |
24 |
50 |
--------------------------------------------------------------------------------
/src/css/app.styl:
--------------------------------------------------------------------------------
1 | // app global css in Stylus form
2 | // app global css in Stylus form
3 | .q-field
4 | &__control
5 | height 32px
6 | &__marginal
7 | height 32px
8 | &--auto-height
9 | .q-field__control
10 | height auto
11 | .q-field__control, .q-field__native
12 | min-height 32px
13 |
14 | .bg-drawcolor
15 | background $drawcolor !important
16 |
17 | .bg-layoutcolor
18 | background $layoutcolor !important
19 |
20 | .bg-listcolor
21 | background $listactioncolor !important
22 |
23 | .bg-page
24 | background $pagecolor !important
25 |
26 | .q-tree__node-header-content
27 | height:22px;
28 | font-size:14px;
29 | font-family:PingFangSC-Regular,PingFang SC;
30 | font-weight:400;
31 | color:rgba(51,51,51,1);
32 | line-height:22px;
33 |
34 | .query-cond
35 | font-size:14px;
36 | font-family:PingFangSC-Regular,PingFang SC;
37 | font-weight:400;
38 | color:rgba(0,0,0,0.65);
39 |
40 | .query-input
41 | height:32px;
42 | background:rgba(255,255,255,1);
43 | border-radius:4px;
44 | border:1px solid rgba(238,238,238,1);
45 |
46 | .bg-table-list
47 | background:rgba(255,255,255,1);
48 | border-radius:2px;
49 | border:1px solid rgba(238,238,238,1);
50 |
51 | .q-table
52 | thead
53 | height: 22px;
54 | font-size: 14px;
55 | font-family: PingFangSC-Medium,PingFang SC;
56 | font-weight: 500;
57 | color: rgba(161,161,161,1);
58 | line-height: 22px;
59 | tbody
60 | height:22px;
61 | font-size:14px;
62 | font-family:PingFangSC-Regular,PingFang SC;
63 | font-weight:400;
64 | color:rgba(0,0,0,1);
65 | line-height:22px;
66 |
67 | .home
68 | .q-table
69 | thead
70 | height:20px;
71 | font-size:13px;
72 | font-family:PingFangSC-Regular,PingFang SC;
73 | font-weight:400;
74 | color:rgba(102,102,102,1);
75 | line-height:20px;
76 | tbody
77 | height:20px;
78 | font-size:13px;
79 | font-family:PingFangSC-Regular,PingFang SC;
80 | font-weight:400;
81 | color:rgba(161,161,161,1);
82 | line-height:20px;
83 |
--------------------------------------------------------------------------------
/src/css/quasar.variables.styl:
--------------------------------------------------------------------------------
1 | // Quasar Stylus Variables
2 | // --------------------------------------------------
3 | // To customize the look and feel of this app, you can override
4 | // the Stylus variables found in Quasar's source Stylus files.
5 |
6 | // Check documentation for full list of Quasar variables
7 |
8 | // Your own variables (that are declared here) and Quasar's own
9 | // ones will be available out of the box in your .vue/.styl files
10 |
11 | // It's highly recommended to change the default colors
12 | // to match your app's branding.
13 | // Tip: Use the "Theme Builder" on Quasar's documentation website.
14 |
15 | $primary = #35C8E8
16 | $secondary = #26A69A
17 | $accent = #9C27B0
18 |
19 | $dark = #1D1D1D
20 |
21 | $positive = #21BA45
22 | $negative = #C10015
23 | $info = #31CCEC
24 | $warning = #F2C037
25 |
26 |
27 | $drawcolor ?= #001529
28 | $layoutcolor ?= #25262A
29 | $listactioncolor ?= #EEEEEE
30 | $pagecolor ?= #FBFBFB
31 |
--------------------------------------------------------------------------------
/src/i18n/en-us/index.js:
--------------------------------------------------------------------------------
1 | // This is just an example,
2 | // so you can safely delete all default props below
3 |
4 | export default {
5 | failed: 'Action failed',
6 | success: 'Action was successful'
7 | }
8 |
--------------------------------------------------------------------------------
/src/i18n/index.js:
--------------------------------------------------------------------------------
1 | import enUS from './en-us'
2 |
3 | export default {
4 | 'en-us': enUS
5 | }
6 |
--------------------------------------------------------------------------------
/src/index.template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= productName %>
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/models/file-md5.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import SparkMD5 from '../plugins/js-spark-md5.js'
4 |
5 | export default function (file, chunk, callback) {
6 | var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
7 | file = file,
8 | chunkSize = chunk || 2097152, // Read in chunks of 2MB
9 | chunks = Math.ceil(file.size / chunkSize),
10 | currentChunk = 0,
11 | spark = new SparkMD5.ArrayBuffer(),
12 | fileReader = new FileReader();
13 |
14 | fileReader.onload = function (e) {
15 | console.log('read chunk nr', currentChunk + 1, 'of', chunks);
16 | spark.append(e.target.result); // Append array buffer
17 | currentChunk++;
18 |
19 | if (currentChunk < chunks) {
20 | loadNext();
21 | } else {
22 | callback(null, spark.end());
23 | console.log('finished loading');
24 | }
25 | };
26 |
27 | fileReader.onerror = function () {
28 | callback('oops, something went wrong.');
29 | };
30 |
31 | function loadNext() {
32 | var start = currentChunk * chunkSize,
33 | end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
34 |
35 | fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
36 | }
37 |
38 | loadNext();
39 | };
40 |
41 |
--------------------------------------------------------------------------------
/src/pages/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
简介
4 |
crudapi是crud+api组合,表示增删改查接口,是一款零代码可配置的产品。使用crudapi可以告别枯燥无味的增删改查代码,让您更加专注业务,节约大量成本,从而提高工作效率。crudapi的目标是让处理数据变得更简单,所有人都可以使用!无需编程,通过配置自动生成crud增删改查RESTful API,提供后台Web管理UI。基于主流的开源框架,前端采用Vue + Quasar,后端采用Spring Boot + Jdbc, 数据库支持MySQL、PostgreSQL、SQL Server和Oracle,支持二次开发,包括API和SDK两种方式。
5 |
6 |
Web管理UI
7 |
8 | 基于Material Design风格的UI,界面美观,使用方面。支持元数据的管理和业务数据的增删改查操作!前端Vue代码crudapi-admin-web开源!
前端Vue环境搭建
9 |
10 |
11 |
后台Java服务
12 |
基于Java+Spring boot默认生成标准的RESTful CRUD API,支持标准的POST,PATCH,GET,DELETE等操作,丰富的Swagger API文档.
后台Java环境搭建
13 |
14 |
15 |
联系方式
16 |
17 | QQ群:632034576
18 | QQ:1440737304
19 |
20 |
21 | 添加微信(暗号crudapi),加入crudapi开发者群!
22 |
23 |

24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
65 |
--------------------------------------------------------------------------------
/src/pages/Error403.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 403
6 |
7 |
8 |
9 | Oops. 403 forbidden!
10 |
11 |
12 |
21 |
22 |
23 |
24 |
25 |
30 |
--------------------------------------------------------------------------------
/src/pages/Error404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 404
6 |
7 |
8 |
9 | Oops. Nothing here...
10 |
11 |
12 |
21 |
22 |
23 |
24 |
25 |
30 |
--------------------------------------------------------------------------------
/src/pages/Index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 元数据
6 |
7 |
16 |
17 |
18 |
19 |
21 |
22 | 序列号
23 | 流水号配置
24 |
25 |
26 |
27 |
29 |
30 | 表
31 | 动态表单设计
32 |
33 |
34 |
35 |
37 |
38 | 关系
39 | 表关联管理
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | 业务数据
48 |
49 |
58 |
59 |
60 |
61 |
62 |
63 |
65 |
66 | 批量导入
67 | 导入JSON数据
68 |
69 |
70 |
71 |
72 |
73 | {{item.name}}
74 |
75 |
84 |
93 |
94 |
95 |
96 |
97 |
102 |
103 | {{moduleLine.table.caption}}
104 | {{moduleLine.table.name}}
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
127 |
128 |
238 |
--------------------------------------------------------------------------------
/src/pages/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |

7 |
8 |
9 |
10 |
11 |
欢迎使用{{ config.appName }}
12 |
13 |
14 |
15 |
16 |
64 |
65 |
66 | Copyright © 2020-present crudapi
苏ICP备15043861号-2 All Rights Reserved 版权所有
67 |
首页
68 |
帮助
69 |
70 |
71 |
72 |
73 |
74 |
140 |
141 |
221 |
--------------------------------------------------------------------------------
/src/pages/Setting.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | crudapi-admin-web v1.6.2
6 | Quasar v{{ $q.version }}
7 |
8 |
9 |
10 | 清除浏览器缓存
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
82 |
--------------------------------------------------------------------------------
/src/pages/business/table/edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
21 |
22 |
23 |
24 |
27 |
28 |
129 |
--------------------------------------------------------------------------------
/src/pages/business/table/import.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
158 |
--------------------------------------------------------------------------------
/src/pages/business/table/list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
102 |
--------------------------------------------------------------------------------
/src/pages/business/table/multiImport.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
116 |
--------------------------------------------------------------------------------
/src/pages/business/table/new.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
111 |
--------------------------------------------------------------------------------
/src/pages/metadata/relation/graph.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
19 |
20 |
204 |
--------------------------------------------------------------------------------
/src/pages/metadata/relation/new.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
106 |
107 |
108 |
109 |
115 |
116 |
286 |
--------------------------------------------------------------------------------
/src/pages/metadata/sequence/edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
130 |
131 |
132 |
133 |
139 |
140 |
259 |
--------------------------------------------------------------------------------
/src/pages/metadata/sequence/new.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
114 |
115 |
116 |
117 |
123 |
124 |
239 |
--------------------------------------------------------------------------------
/src/pages/metadata/sql/new.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
40 |
41 |
42 |
43 |
60 |
61 |
154 |
--------------------------------------------------------------------------------
/src/pages/metadata/table/indexList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
30 |
31 |
32 |
33 |
34 |
40 |
41 |
176 |
--------------------------------------------------------------------------------
/src/pages/metadata/table/reverse.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
23 |
24 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
49 |
50 | {{ props.row.id }}
51 |
52 |
53 | {{ props.row.tableSchema }}
54 |
55 |
56 | {{ props.row.tableName }}
57 |
58 |
59 | {{ props.row.comment }}
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
278 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 |
4 | import routes from './routes'
5 | import { authService } from "../service";
6 | import store from "../store";
7 |
8 | Vue.use(VueRouter)
9 |
10 | /*
11 | * If not building with SSR mode, you can
12 | * directly export the Router instantiation;
13 | *
14 | * The function below can be async too; either use
15 | * async/await or return a Promise which resolves
16 | * with the Router instance.
17 | */
18 | const Router = new VueRouter({
19 | scrollBehavior: () => ({ x: 0, y: 0 }),
20 | routes,
21 |
22 | // Leave these as they are and change in quasar.conf.js instead!
23 | // quasar.conf.js -> build -> vueRouterMode
24 | // quasar.conf.js -> build -> publicPath
25 | mode: process.env.VUE_ROUTER_MODE,
26 | base: process.env.VUE_ROUTER_BASE
27 | });
28 |
29 | const whiteList = ["/login", "/403"];
30 |
31 | function hasPermission(router) {
32 | if (whiteList.indexOf(router.path) !== -1) {
33 | return true;
34 | }
35 |
36 | return true;
37 | }
38 |
39 | Router.beforeEach(async (to, from, next) => {
40 | if (window.location.hostname === "demo.crudapi.cn" && _hmt && to.path) {
41 | _hmt.push(["_trackPageview", to.fullPath]);
42 | console.log("上报百度统计", to.fullPath);
43 | }
44 |
45 | let token = authService.getToken();
46 | if (token) {
47 | let userInfo = store.state.user.userInfo;
48 | if (!userInfo.username) {
49 | try {
50 | await store.dispatch("user/getUserInfo");
51 | next();
52 | } catch (e) {
53 | if (whiteList.indexOf(to.path) !== -1) {
54 | next();
55 | } else {
56 | next("/login");
57 | }
58 | }
59 | } else {
60 | if (hasPermission(to)) {
61 | next();
62 | } else {
63 | next({ path: "/403", replace: true });
64 | }
65 | }
66 | } else {
67 | if (whiteList.indexOf(to.path) !== -1) {
68 | next();
69 | } else {
70 | next("/login");
71 | }
72 | }
73 | });
74 |
75 | export default Router;
76 |
--------------------------------------------------------------------------------
/src/router/routes.js:
--------------------------------------------------------------------------------
1 | const routes = [
2 | {
3 | path: "/login",
4 | name: "login",
5 | component: () => import("pages/Login.vue")
6 | },
7 | {
8 | path: "/403",
9 | name: "403",
10 | component: () => import("pages/Error403")
11 | },
12 | {
13 | path: '/',
14 | component: () => import('layouts/MainLayout.vue'),
15 | children: [
16 | { path: '', component: () => import('pages/Index.vue') },
17 | { path: 'dataSource/:dataSource', component: () => import('pages/Index.vue') },
18 | {
19 | name: "about",
20 | path: "about",
21 | meta: { isAllowBack: true },
22 | component: () => import("pages/About.vue")
23 | },
24 | {
25 | name: "setting",
26 | path: "setting",
27 | meta: { isAllowBack: true },
28 | component: () => import("pages/Setting.vue")
29 | },
30 | {
31 | name: "form-builder",
32 | path: "dataSource/:dataSource/metadata/tables/:id/formBuilder",
33 | meta: { isAllowBack: true },
34 | component: () => import("pages/form-builder/index.vue")
35 | },
36 | {
37 | name: "tablePermission",
38 | path: "dataSource/:dataSource/metadata/tables/:id/tablePermission",
39 | meta: { isAllowBack: true },
40 | component: () => import("pages/tablePermission/index.vue")
41 | },
42 | {
43 | name: "sequenceList",
44 | path: "dataSource/:dataSource/metadata/sequences",
45 | meta: { isAllowBack: true },
46 | component: () => import("pages/metadata/sequence/list.vue")
47 | },
48 | {
49 | name: "sequenceNew",
50 | path: "dataSource/:dataSource/metadata/sequences/new",
51 | meta: { isAllowBack: true },
52 | component: () => import("pages/metadata/sequence/new.vue")
53 | },
54 | {
55 | name: "sequenceEdit",
56 | path: "dataSource/:dataSource/metadata/sequences/:id",
57 | meta: { isAllowBack: true },
58 | component: () => import("pages/metadata/sequence/edit.vue")
59 | },
60 | {
61 | name: "sqlNew",
62 | path: "dataSource/:dataSource/metadata/sqls/new",
63 | meta: { isAllowBack: true },
64 | component: () => import("pages/metadata/sql/new.vue")
65 | },
66 | {
67 | name: "tables",
68 | path: "dataSource/:dataSource/metadata/tables",
69 | meta: { isAllowBack: true },
70 | component: () => import("pages/metadata/table/list.vue")
71 | },
72 | {
73 | name: "tableImport",
74 | path: "dataSource/:dataSource/metadata/tables/import",
75 | meta: { isAllowBack: true },
76 | component: () => import("pages/metadata/table/import.vue")
77 | },
78 | {
79 | name: "tableReverse",
80 | path: "dataSource/:dataSource/metadata/tables/reverse",
81 | meta: { isAllowBack: true },
82 | component: () => import("pages/metadata/table/reverse.vue")
83 | },
84 | {
85 | name: "tableNew",
86 | path: "dataSource/:dataSource/metadata/tables/new",
87 | meta: { isAllowBack: true },
88 | component: () => import("pages/metadata/table/new.vue")
89 | },
90 | {
91 | name: "tableEdit",
92 | path: "dataSource/:dataSource/metadata/tables/:id",
93 | meta: { isAllowBack: true },
94 | component: () => import("pages/metadata/table/edit.vue")
95 | },
96 | {
97 | name: "tableIndexs",
98 | path: "dataSource/:dataSource/metadata/tables/:id/indexs",
99 | meta: { isAllowBack: true },
100 | component: () => import("pages/metadata/table/indexList.vue")
101 | },
102 | {
103 | name: "relationGraph",
104 | path: "dataSource/:dataSource/metadata/relations/graph",
105 | meta: { isAllowBack: true },
106 | component: () => import("pages/metadata/relation/graph.vue")
107 | },
108 | {
109 | name: "relations",
110 | path: "dataSource/:dataSource/metadata/relations",
111 | meta: { isAllowBack: true },
112 | component: () => import("pages/metadata/relation/list.vue")
113 | },{
114 | name: "relationNew",
115 | path: "dataSource/:dataSource/metadata/relations/new",
116 | meta: { isAllowBack: true },
117 | component: () => import("pages/metadata/relation/new.vue")
118 | },{
119 | name: "relationEdit",
120 | path: "dataSource/:dataSource/metadata/relations/:id",
121 | meta: { isAllowBack: true },
122 | component: () => import("pages/metadata/relation/edit.vue")
123 | },
124 | {
125 | name: "businessMultiImport",
126 | path: "dataSource/:dataSource/business/import",
127 | meta: { isAllowBack: true },
128 | component: () => import("pages/business/table/multiImport.vue")
129 | },
130 | {
131 | name: "business",
132 | path: "dataSource/:dataSource/business/:tableName",
133 | meta: { isAllowBack: true },
134 | component: () => import("pages/business/table/list.vue")
135 | },
136 | {
137 | name: "businessNew",
138 | path: "dataSource/:dataSource/business/:tableName/new",
139 | meta: { isAllowBack: true },
140 | component: () => import("pages/business/table/new.vue")
141 | },
142 | {
143 | name: "businessImport",
144 | path: "dataSource/:dataSource/business/:tableName/import",
145 | meta: { isAllowBack: true },
146 | component: () => import("pages/business/table/import.vue")
147 | },
148 | {
149 | name: "businessEdit",
150 | path: "dataSource/:dataSource/business/:tableName/:recId",
151 | meta: { isAllowBack: true },
152 | component: () => import("pages/business/table/edit.vue")
153 | }
154 | ]
155 | },
156 |
157 | // Always leave this as last one,
158 | // but you can also remove it
159 | {
160 | path: '*',
161 | component: () => import('pages/Error404.vue')
162 | }
163 | ]
164 |
165 | export default routes
166 |
--------------------------------------------------------------------------------
/src/service/authService.js:
--------------------------------------------------------------------------------
1 | import { LocalStorage } from "quasar";
2 |
3 | const authService = {
4 | getToken: function() {
5 | return LocalStorage.getItem("token");
6 | },
7 | setToken: function(token) {
8 | LocalStorage.set("token", token);
9 | }
10 | };
11 |
12 | export { authService };
13 |
--------------------------------------------------------------------------------
/src/service/fileService.js:
--------------------------------------------------------------------------------
1 | import { file } from "../api";
2 |
3 | const fileService = {
4 | upload: async function (fileObj, progressCallback) {
5 | return file.upload(fileObj, progressCallback).then((res) => {
6 | console.log(res);
7 | return res.data;
8 | })
9 | },
10 | bigUpload: async function (fileObj, progressCallback) {
11 | return file.bigUpload(fileObj, progressCallback).then((res) => {
12 | console.log(res);
13 | return res.data;
14 | })
15 | }
16 | };
17 |
18 | export { fileService };
19 |
--------------------------------------------------------------------------------
/src/service/index.js:
--------------------------------------------------------------------------------
1 | export { settingService } from "./settingService";
2 | export { userService } from "./userService";
3 | export { permissionService } from "./permissionService";
4 | export { authService } from "./authService";
5 | export { metadataTableService } from "./metadataTableService";
6 | export { metadataSequenceService } from "./metadataSequenceService";
7 | export { metadataRelationService } from "./metadataRelationService";
8 | export { tableService } from "./tableService";
9 | export { fileService } from "./fileService";
10 |
--------------------------------------------------------------------------------
/src/service/metadataRelationService.js:
--------------------------------------------------------------------------------
1 | import { metadataRelation } from "../api";
2 |
3 | const metadataRelationService = {
4 | create: async function(dataSource, data) {
5 | var res = await metadataRelation.create(dataSource, data);
6 | return res.data;
7 | },
8 | update: async function(dataSource, id, data) {
9 | var res = await metadataRelation.update(dataSource, id, data);
10 | return res.data;
11 | },
12 | list: async function(dataSource, page, rowsPerPage, search, query) {
13 | var res = await metadataRelation.list(dataSource, page, rowsPerPage, search, query);
14 | return res.data;
15 | },
16 | count: async function(dataSource, search, query) {
17 | var res = await metadataRelation.count(dataSource, search, query);
18 | return res.data;
19 | },
20 | get: async function(dataSource, id) {
21 | var res = await metadataRelation.get(dataSource, id);
22 | return res.data;
23 | },
24 | getByName: async function(dataSource, name) {
25 | var res = await metadataRelation.getFromTableByName(dataSource, name);
26 | return res.data;
27 | },
28 | delete: async function(dataSource, id) {
29 | var res = await metadataRelation.delete(dataSource, id);
30 | return res.data;
31 | },
32 | batchDelete: async function(dataSource, ids) {
33 | var res = await metadataRelation.batchDelete(dataSource, ids);
34 | return res.data;
35 | }
36 | };
37 |
38 | export { metadataRelationService };
39 |
--------------------------------------------------------------------------------
/src/service/metadataSequenceService.js:
--------------------------------------------------------------------------------
1 | import { metadataSequence } from "../api";
2 |
3 | const metadataSequenceService = {
4 | create: async function(dataSource, data) {
5 | var res = await metadataSequence.create(dataSource, data);
6 | return res.data;
7 | },
8 | update: async function(dataSource, id, data) {
9 | var res = await metadataSequence.update(dataSource, id, data);
10 | return res.data;
11 | },
12 | list: async function(dataSource, page, rowsPerPage, search, query) {
13 | var res = await metadataSequence.list(dataSource, page, rowsPerPage, search, query);
14 | return res.data;
15 | },
16 | count: async function(dataSource, search, query) {
17 | var res = await metadataSequence.count(dataSource, search, query);
18 | return res.data;
19 | },
20 | get: async function(dataSource, id) {
21 | var res = await metadataSequence.get(dataSource, id);
22 | return res.data;
23 | },
24 | delete: async function(dataSource, id) {
25 | var res = await metadataSequence.delete(dataSource, id);
26 | return res.data;
27 | },
28 | batchDelete: async function(dataSource, ids) {
29 | var res = await metadataSequence.batchDelete(dataSource, ids);
30 | return res.data;
31 | }
32 | };
33 |
34 | export { metadataSequenceService };
35 |
--------------------------------------------------------------------------------
/src/service/metadataTableService.js:
--------------------------------------------------------------------------------
1 | import { metadataTable } from "../api";
2 |
3 | const metadataTableService = {
4 | create: async function(dataSource, data) {
5 | var res = await metadataTable.create(dataSource, data);
6 | return res.data;
7 | },
8 | update: async function(dataSource, id, data) {
9 | var res = await metadataTable.update(dataSource, id, data);
10 | return res.data;
11 | },
12 | list: async function(dataSource, page, rowsPerPage, search, query) {
13 | var res = await metadataTable.list(dataSource, page, rowsPerPage, search, query);
14 | return res.data;
15 | },
16 | count: async function(dataSource, search, query) {
17 | var res = await metadataTable.count(dataSource, search, query);
18 | return res.data;
19 | },
20 | get: async function(dataSource, id) {
21 | var res = await metadataTable.get(dataSource, id);
22 | return res.data;
23 | },
24 | getByName: async function(dataSource, id) {
25 | var res = await metadataTable.getByName(dataSource, id);
26 | return res.data;
27 | },
28 | getMetadata: async function(dataSource, name) {
29 | var res = await metadataTable.getMetadata(dataSource, name);
30 | return res.data;
31 | },
32 | getMetadatas: async function(dataSource) {
33 | var res = await metadataTable.getMetadatas(dataSource);
34 | return res.data;
35 | },
36 | reverse: async function(dataSource, tableName) {
37 | var res = await metadataTable.reverse(dataSource, tableName);
38 | return res.data;
39 | },
40 | batchReverse: async function(dataSource, tableNames) {
41 | var res = await metadataTable.batchReverse(dataSource,tableNames);
42 | return res.data;
43 | },
44 | repairMeataData: async function(dataSource, name, columnNameLsit) {
45 | var res = await metadataTable.repairMeataData(dataSource,name, columnNameLsit);
46 | return res.data;
47 | },
48 | delete: async function(dataSource, id, isDropPhysicalTable) {
49 | var res = await metadataTable.delete(dataSource,id, isDropPhysicalTable);
50 | return res.data;
51 | },
52 | batchDelete: async function(dataSource, ids, isDropPhysicalTable) {
53 | var res = await metadataTable.batchDelete(dataSource,ids, isDropPhysicalTable);
54 | return res.data;
55 | },
56 | importFile: async function (dataSource, fileObj, progressCallback) {
57 | return metadataTable.import(dataSource, fileObj, progressCallback).then((res) => {
58 | console.log(res);
59 | return res.data;
60 | })
61 | },
62 | import: async function (dataSource, data) {
63 | var res = await metadataTable.import(dataSource, data);
64 | return res.data;
65 | },
66 | export: async function(dataSource, ids) {
67 | var res = await metadataTable.export(dataSource, ids);
68 | return res.data;
69 | },
70 | listDataSource: async function() {
71 | var res = await metadataTable.listDataSource();
72 | return res.data;
73 | }
74 | };
75 |
76 | export { metadataTableService };
77 |
--------------------------------------------------------------------------------
/src/service/permissionService.js:
--------------------------------------------------------------------------------
1 | import { LocalStorage } from "quasar";
2 |
3 | const permissionService = {
4 | get: function() {
5 | return LocalStorage.getItem("permission");
6 | },
7 | set: function(data) {
8 | LocalStorage.set("permission", data);
9 | },
10 | isSuperAdmin: function() {
11 | let data = this.get();
12 | if (!data) {
13 | return false;
14 | }
15 |
16 | return data.isSuperAdmin;
17 | },
18 | check: function(needPermissions) {
19 | if (needPermissions && needPermissions.length > 0) {
20 | let data = this.get();
21 | if (!data) {
22 | return false;
23 | }
24 |
25 | let isSuperAdmin = data.isSuperAdmin;
26 | if (isSuperAdmin) {
27 | return true;
28 | }
29 |
30 | if (!data.permissions) {
31 | return false;
32 | }
33 |
34 | let permissions = data.permissions;
35 | let hasPermission = permissions.some(s => {
36 | return needPermissions.indexOf(s.authority) > -1;
37 | });
38 |
39 | return hasPermission;
40 | }
41 | return true;
42 | }
43 | };
44 |
45 | export { permissionService };
46 |
--------------------------------------------------------------------------------
/src/service/settingService.js:
--------------------------------------------------------------------------------
1 | import { LocalStorage, SessionStorage} from "quasar";
2 |
3 | const settingService = {
4 | clear: function() {
5 | LocalStorage.clear();
6 | SessionStorage.clear();
7 | }
8 | };
9 |
10 | export { settingService };
11 |
--------------------------------------------------------------------------------
/src/service/tableService.js:
--------------------------------------------------------------------------------
1 | import { table } from "../api";
2 |
3 | const tableService = {
4 | create: async function(dataSource, tableName, data) {
5 | var res = await table.create(dataSource, tableName, data);
6 | return res.data;
7 | },
8 | update: async function(dataSource, tableName, id, data) {
9 | var res = await table.update(dataSource, tableName, id, data);
10 | return res.data;
11 | },
12 | count: async function(dataSource, tableName, search, query, filter) {
13 | var res = await table.count(dataSource, tableName, search, query, filter);
14 | return res.data;
15 | },
16 | list: async function(dataSource, tableName, page, rowsPerPage, search, query, filter, select) {
17 | var res = await table.list(dataSource, tableName, page, rowsPerPage, search, query, filter, select);
18 | return res.data;
19 | },
20 | listByIds: async function(dataSource, tableName, ids) {
21 | var res = await table.listAllByIds(dataSource, tableName, ids);
22 | return res.data;
23 | },
24 | get: async function(dataSource, tableName, id) {
25 | var res = await table.get(dataSource, tableName, id);
26 | return res.data;
27 | },
28 | delete: async function(dataSource, tableName, id, isSoftDelete) {
29 | var res = await table.delete(dataSource, tableName, id, isSoftDelete);
30 | return res.data;
31 | },
32 | batchDelete: async function(dataSource, tableName, ids, isSoftDelete) {
33 | var res = await table.batchDelete(dataSource, tableName, ids, isSoftDelete);
34 | return res.data;
35 | },
36 | import: async function (dataSource, tableName, fileObj, progressCallback) {
37 | return table.import(dataSource, tableName, fileObj, progressCallback).then((res) => {
38 | console.log(res);
39 | return res.data;
40 | })
41 | },
42 | multiImport: async function (dataSource, fileObj, progressCallback) {
43 | return table.multiImport(dataSource, fileObj, progressCallback).then((res) => {
44 | console.log(res);
45 | return res.data;
46 | })
47 | },
48 | multiExport: async function(dataSource, ids) {
49 | var res = await table.multiExport(dataSource, ids);
50 | return res.data;
51 | },
52 | getImportTemplate: async function(dataSource, tableName) {
53 | var res = await table.getImportTemplate(dataSource, tableName);
54 | return res.data;
55 | },
56 | export: async function(dataSource, tableName, select, search, query, filter) {
57 | var res = await table.export(dataSource, tableName, select, search, query, filter);
58 | return res.data;
59 | },
60 |
61 | exportXml: async function(dataSource, tableName, select, search, query, filter, isDisplayCaption) {
62 | var res = await table.exportXml(dataSource, tableName, select, search, query, filter, isDisplayCaption);
63 | return res.data;
64 | }
65 | };
66 |
67 | export { tableService };
68 |
--------------------------------------------------------------------------------
/src/service/userService.js:
--------------------------------------------------------------------------------
1 | import { user} from "../api";
2 | import { LocalStorage } from "quasar";
3 |
4 | const userService = {
5 | login: async function(data) {
6 | var res = await user.login(data);
7 | return res.data;
8 | },
9 | logout: async function() {
10 | var res = await user.logout();
11 | return res.data;
12 | },
13 | menu: async function(dataSource) {
14 | var res = await user.menu(dataSource);
15 | return res.data;
16 | },
17 | table: async function(dataSource) {
18 | var res = await user.table(dataSource);
19 | return res.data;
20 | },
21 | getUserInfo: async function() {
22 | return LocalStorage.getItem("userInfo") || {};
23 | },
24 | setUserInfo: function(userInfo) {
25 | LocalStorage.set("userInfo", userInfo);
26 | }
27 | };
28 |
29 | export { userService };
30 |
--------------------------------------------------------------------------------
/src/store/config/actions.js:
--------------------------------------------------------------------------------
1 | /*
2 | export function someAction (context) {
3 | }
4 | */
5 |
--------------------------------------------------------------------------------
/src/store/config/getters.js:
--------------------------------------------------------------------------------
1 | /*
2 | export function someGetter (state) {
3 | }
4 | */
5 |
--------------------------------------------------------------------------------
/src/store/config/index.js:
--------------------------------------------------------------------------------
1 | import state from "./state";
2 | import * as getters from "./getters";
3 | import * as mutations from "./mutations";
4 | import * as actions from "./actions";
5 |
6 | export default {
7 | namespaced: true,
8 | state,
9 | getters,
10 | mutations,
11 | actions
12 | };
13 |
--------------------------------------------------------------------------------
/src/store/config/mutations.js:
--------------------------------------------------------------------------------
1 | export const updateIsAllowBack = (state, isAllowBack) => {
2 | state.isAllowBack = isAllowBack;
3 | };
4 |
--------------------------------------------------------------------------------
/src/store/config/state.js:
--------------------------------------------------------------------------------
1 | export default {
2 | isAllowBack: false
3 | };
4 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | // import example from './module-example'
5 |
6 | import config from "./config";
7 | import user from "./user";
8 |
9 | import { plugin as userPlugin } from "./user";
10 |
11 |
12 | Vue.use(Vuex)
13 |
14 | /*
15 | * If not building with SSR mode, you can
16 | * directly export the Store instantiation;
17 | *
18 | * The function below can be async too; either use
19 | * async/await or return a Promise which resolves
20 | * with the Store instance.
21 | */
22 |
23 | const Store = new Vuex.Store({
24 | modules: {
25 | config,
26 | user
27 | },
28 |
29 | plugins: [userPlugin],
30 |
31 | // enable strict mode (adds overhead!)
32 | // for dev mode only
33 | strict: process.env.DEBUGGING
34 | });
35 |
36 | export default Store;
37 |
--------------------------------------------------------------------------------
/src/store/module-example/actions.js:
--------------------------------------------------------------------------------
1 | export function someAction (/* context */) {
2 | }
3 |
--------------------------------------------------------------------------------
/src/store/module-example/getters.js:
--------------------------------------------------------------------------------
1 | export function someGetter (/* state */) {
2 | }
3 |
--------------------------------------------------------------------------------
/src/store/module-example/index.js:
--------------------------------------------------------------------------------
1 | import state from './state'
2 | import * as getters from './getters'
3 | import * as mutations from './mutations'
4 | import * as actions from './actions'
5 |
6 | export default {
7 | namespaced: true,
8 | getters,
9 | mutations,
10 | actions,
11 | state
12 | }
13 |
--------------------------------------------------------------------------------
/src/store/module-example/mutations.js:
--------------------------------------------------------------------------------
1 | export function someMutation (/* state */) {
2 | }
3 |
--------------------------------------------------------------------------------
/src/store/module-example/state.js:
--------------------------------------------------------------------------------
1 | export default function () {
2 | return {
3 | //
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/store/store-flag.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // THIS FEATURE-FLAG FILE IS AUTOGENERATED,
3 | // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
4 | import "quasar/dist/types/feature-flag";
5 |
6 | declare module "quasar/dist/types/feature-flag" {
7 | interface QuasarFeatureFlags {
8 | store: true;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/store/user/actions.js:
--------------------------------------------------------------------------------
1 | import { userService } from "../../service";
2 | import { permissionService } from "../../service";
3 |
4 | export const login = ({ commit }, userInfo) => {
5 | return new Promise((resolve, reject) => {
6 | userService
7 | .login(userInfo)
8 | .then(data => {
9 | //session方式登录,其实不需要token,这里为了JWT登录预留,用username代替。
10 | //通过Token是否为空判断本地有没有登录过,方便后续处理。
11 | commit("updateToken", data.principal.username);
12 |
13 | const newUserInfo = {
14 | username: data.principal.username,
15 | realname: data.principal.realname || data.principal.username,
16 | avatar: "",
17 | authorities: data.principal.authorities || [],
18 | roles: data.principal.roles || []
19 | };
20 | commit("updateUserInfo", newUserInfo);
21 |
22 | let permissions = data.authorities || [];
23 | let isSuperAdmin = false;
24 | if (permissions.findIndex(t => t.authority === "ROLE_SUPER_ADMIN") >= 0) {
25 | isSuperAdmin = true;
26 | }
27 |
28 | permissionService.set({
29 | permissions: permissions,
30 | isSuperAdmin: isSuperAdmin
31 | });
32 |
33 | resolve(newUserInfo);
34 | })
35 | .catch(error => {
36 | reject(error);
37 | });
38 | });
39 | };
40 |
41 | export const logout = ({ commit }) => {
42 | return new Promise((resolve, reject) => {
43 | userService
44 | .logout()
45 | .then(() => {
46 | resolve();
47 | })
48 | .catch(error => {
49 | console.error(error);
50 | resolve();
51 | })
52 | .finally(() => {
53 | commit("updateToken", "");
54 | commit("updateUserInfo", {
55 | username: "",
56 | realname: "",
57 | avatar: "",
58 | authorities: [],
59 | roles: []
60 | });
61 |
62 | permissionService.set({
63 | permissions: [],
64 | isSuperAdmin: false
65 | });
66 | });
67 | });
68 | };
69 |
70 | export const getUserInfo = ({ commit }) => {
71 | return new Promise((resolve, reject) => {
72 | userService
73 | .getUserInfo()
74 | .then(data => {
75 | commit("updateUserInfo", data);
76 | resolve();
77 | })
78 | .catch(error => {
79 | reject(error);
80 | });
81 | });
82 | };
83 |
--------------------------------------------------------------------------------
/src/store/user/getters.js:
--------------------------------------------------------------------------------
1 | /*
2 | export function someGetter (state) {
3 | }
4 | */
5 |
--------------------------------------------------------------------------------
/src/store/user/index.js:
--------------------------------------------------------------------------------
1 | import state from "./state";
2 | import * as getters from "./getters";
3 | import * as mutations from "./mutations";
4 | import * as actions from "./actions";
5 | import { plugin } from "./plugin";
6 |
7 | export { plugin };
8 |
9 | export default {
10 | namespaced: true,
11 | state,
12 | getters,
13 | mutations,
14 | actions
15 | };
16 |
--------------------------------------------------------------------------------
/src/store/user/mutations.js:
--------------------------------------------------------------------------------
1 | export const updateToken = (state, token) => {
2 | state.token = token;
3 | };
4 |
5 | export const updateUserInfo = (state, userInfo) => {
6 | state.userInfo = userInfo;
7 | };
8 |
9 |
--------------------------------------------------------------------------------
/src/store/user/plugin.js:
--------------------------------------------------------------------------------
1 | import { authService } from "../../service";
2 | import { userService } from "../../service";
3 |
4 | const plugin = store => {
5 | // 当 store 初始化后调用
6 | store.subscribe(mutation => {
7 | // 每次 mutation 之后调用
8 | // mutation 的格式为 { type, payload }
9 | if (mutation.type === "user/updateToken") {
10 | authService.setToken(mutation.payload);
11 | } else if (mutation.type === "user/updateUserInfo") {
12 | userService.setUserInfo(mutation.payload);
13 | }
14 | });
15 | };
16 |
17 | export { plugin };
18 |
--------------------------------------------------------------------------------
/src/store/user/state.js:
--------------------------------------------------------------------------------
1 | import { authService } from "../../service";
2 |
3 | export default {
4 | token: authService.getToken(),
5 | userInfo: {
6 | username: "",
7 | realname: "",
8 | avatar: "",
9 | authorities: [],
10 | roles: ""
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/src/utils/date.js:
--------------------------------------------------------------------------------
1 | import { date as qDate } from "quasar";
2 |
3 | const DATE_TIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
4 | const DATE_FORMAT = "YYYY-MM-DD";
5 | const TIME_FORMAT = "HH:mm:ss";
6 |
7 | export function covertToQDateTime(date) {
8 | return qDate.formatDate(date, DATE_TIME_FORMAT);
9 | }
10 |
11 | export function covertToQDate(date) {
12 | return qDate.formatDate(date, DATE_FORMAT);
13 | }
14 |
15 | export function covertToQTime(date) {
16 | return qDate.formatDate(date, TIME_FORMAT);
17 | }
18 |
19 | export function getToday() {
20 | return this.covertToQDateTime(Date.now());
21 | }
22 |
23 | export function dateTimeFormat(value) {
24 | if (!value) {
25 | return "";
26 | }
27 |
28 |
29 | let formattedString = this.covertToQDateTime(new Date(value));
30 |
31 | return formattedString;
32 | }
33 |
34 | export function timeFormat(value) {
35 | if (!value) {
36 | return "";
37 | }
38 |
39 | if ((value + "").indexOf(":") > 0) {
40 | return value;
41 | }
42 |
43 | let formattedString = this.covertToQTime(new Date(value));
44 |
45 | return formattedString;
46 | }
47 |
48 | export function dateFormat(value) {
49 | if (!value) {
50 | return "";
51 | }
52 |
53 | let formattedString = this.covertToQDate(new Date(value));
54 |
55 | return formattedString;
56 | }
57 |
58 | export default {
59 | covertToQDateTime,
60 | covertToQDate,
61 | covertToQTime,
62 | getToday,
63 | dateTimeFormat,
64 | dateFormat,
65 | timeFormat
66 | };
67 |
--------------------------------------------------------------------------------
/src/utils/index.js:
--------------------------------------------------------------------------------
1 | import date from "./date.js";
2 |
3 | export { date };
4 |
--------------------------------------------------------------------------------