yarn deploy
39 | ```
40 |
41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
42 |
--------------------------------------------------------------------------------
/docs/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3 | };
4 |
--------------------------------------------------------------------------------
/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg
--------------------------------------------------------------------------------
/docs/blog/2021-08-26-welcome/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: welcome
3 | title: Welcome
4 | authors: [slorber, yangshun]
5 | tags: [facebook, hello, docusaurus]
6 | ---
7 |
8 | [Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog).
9 |
10 | Simply add Markdown files (or folders) to the `blog` directory.
11 |
12 | Regular blog authors can be added to `authors.yml`.
13 |
14 | The blog post date can be extracted from filenames, such as:
15 |
16 | - `2019-05-30-welcome.md`
17 | - `2019-05-30-welcome/index.md`
18 |
19 | A blog post folder can be convenient to co-locate blog post images:
20 |
21 | 
22 |
23 | The blog supports tags as well!
24 |
25 | **And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config.
26 |
--------------------------------------------------------------------------------
/docs/blog/2022-06-27-first.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: 首篇
3 | title: Hello World
4 | authors:
5 | name: Owls
6 | title: Owls研发团队
7 | # url: https://github.com/wgao19
8 | # image_url: https://github.com/wgao19.png
9 | tags: [hello, world]
10 | ---
11 |
12 | #### Hello World
13 | 欢迎光临!
14 |
--------------------------------------------------------------------------------
/docs/blog/2022-07-25-introduce/architecture-en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/blog/2022-07-25-introduce/architecture-en.png
--------------------------------------------------------------------------------
/docs/blog/2022-07-25-introduce/rollback.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/blog/2022-07-25-introduce/rollback.png
--------------------------------------------------------------------------------
/docs/blog/2022-07-25-introduce/rules.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/blog/2022-07-25-introduce/rules.png
--------------------------------------------------------------------------------
/docs/blog/authors.yml:
--------------------------------------------------------------------------------
1 | qingfeng:
2 | name: qingfeng,mingbai
3 | title: Maintainer of owls
4 | url: https://github.com/nooncall/owls
5 | image_url: https://github.com/qingfeng777.png
6 |
7 | endi:
8 | name: Endilie Yacop Sucipto
9 | title: Maintainer of Docusaurus
10 | url: https://github.com/endiliey
11 | image_url: https://github.com/endiliey.png
12 |
13 | yangshun:
14 | name: Yangshun Tay
15 | title: Front End Engineer @ Facebook
16 | url: https://github.com/yangshun
17 | image_url: https://github.com/yangshun.png
18 |
19 | slorber:
20 | name: Sébastien Lorber
21 | title: Docusaurus maintainer
22 | url: https://sebastienlorber.com
23 | image_url: https://github.com/slorber.png
24 |
--------------------------------------------------------------------------------
/docs/develop/community/community.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '社区'
3 | sidebar_position: 6
4 | ---
5 |
6 | ### 微信群
7 | 目前主要在微信群中沟通。
8 |
9 | #### 开发者微信群:
10 |
11 | 
12 |
13 | ### 其他
14 | 或者添加开发者微信:grsixk
15 |
--------------------------------------------------------------------------------
/docs/develop/community/owls-wechat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/develop/community/owls-wechat.jpg
--------------------------------------------------------------------------------
/docs/develop/contribution.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '贡献指南'
3 | title: 贡献指南
4 | sidebar_position: 5
5 | ---
6 |
7 | Hi! 首先感谢您对Owls的兴趣。
8 |
9 | Owls 是一套为快安全、规范准备的一整套前后端分离架构式的后端系统管理平台, 旨在简化、标准化DBA、研发等同学对数据库、MQ、缓存等系统的使用和管理。
10 |
11 | Owls 的成长离不开大家的支持,如果你愿意为 Owls 贡献代码或提供建议,请阅读以下内容。
12 |
13 | #### Issue 规范
14 | - 稍大的功能模块设计需要在文档目录(server/docs/design)中,参照[模板](../design/template)添加设计说明,并进行review。
15 |
16 | - issue 仅用于提交 Bug 或 Feature 以及设计相关的内容。
17 |
18 | - 在提交 issue 之前,请搜索相关内容是否已被提出。
19 |
20 | #### Pull Request 规范
21 | - 请先 fork 一份到自己的项目下,不要直接在仓库下建分支。
22 |
23 | - commit 信息要以`[模块名]: 描述信息` 的形式填写,例如 `[readme] update xxx msg`。
24 |
25 | - 如果是修复 bug,请在 PR 中给出描述信息。
26 |
27 | - 合并代码需要一人进行 review 后 approve,方可合并。
28 |
--------------------------------------------------------------------------------
/docs/develop/db-tables-and-init.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '库表使用'
3 | title: 库表使用
4 | sidebar_position: 6
5 | ---
6 |
7 | 1, 数据库
8 |
9 | 数据库目前主要是使用的是mysql,如果是一个新库,会在初始化的时候进行选择、输入相关数据库连接信息。
10 |
11 | 如果读取配置文件,发现是一个已经有数据的库,则无法再进行初始化,已有用户可直接登录。
12 |
13 | 2, 表
14 |
15 | 一般,表在数据库初始化的时候自动创建,无需手动建表。
16 |
17 | 如果是开发时,需要临时增加一个表
18 |
19 | a. 可以清除数据库重新初始化
20 | b. 可以临时手动建表,不影响后续重新部署时的自动初始化。
21 |
22 | 3, 表中数据的初始化
23 |
24 | 表中数据的初始化在`source`目录下,初始化数据库时,会将一些基础数据写入到DB。
25 |
26 | 比如UI上菜单相关数据的初始化在这里:
27 | `source/system/menu.go`
--------------------------------------------------------------------------------
/docs/develop/design/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "设计文档",
3 | "position": 4,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "设计文档列表。"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/develop/design/db-auth.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '数据权限'
3 | title: 数据权限
4 | sidebar_position: 4
5 | ---
6 |
7 | ## 数据权限管理
8 |
9 | #### 版本记录
10 |
11 | 日期 |内容|撰写人
12 | |---|---|---|
13 | 2022/04/26| V1.0 初版| 刘胜杰
14 |
15 | ## 人员
16 | - 需求提出: 刘胜杰
17 | - 研发: 刘胜杰
18 | - 抄送:
19 |
20 | ## 问题
21 | 查询数据需要权限控制,以保护数据安全
22 |
23 | ## 目标
24 | - 实现权限申请及审批流程
25 | - 数据查询及任务提交添加权限控制
26 | - 支持后续可能出现的,更多的数据系统的权限管理
27 |
28 | ## 设计
29 |
30 | ### 整体设计
31 | 普通用户提交请求对库-表的权限申请,管理员进行审批及普通用户的权限删除
32 |
33 | ### 详细设计
34 |
35 | #### 页面
36 | - 权限申请及审批列表。
37 | - 人员权限列表-库类型-所拥有的db列表等。
38 |
39 | #### 表
40 | 审批task表
41 |
42 | 是否可与sql审核用同一个表?是否所有的审批流程用同样的表及类似的流程?
43 | 用同一个表,逻辑会交织到一起,不便于处理不同情况。
44 | 用不同的表,可能会同样的逻辑写多遍,浪费。
45 |
46 | 可以优先考虑用同一个表。
47 |
48 | taskID
49 | UserId
50 | DataType
51 | Cluster
52 | DB
53 |
54 | 权限表
55 |
56 | UserId
57 | DataType
58 | Cluster
59 | DB []string
60 |
61 | ## 排期
62 |
63 | - [x] 后端接口ready @刘胜杰 2020-5-3
64 | - [x] 前端页面ready 并调通管理 2020-5-5
65 | - [x] sql审核db list经权限过滤 2022-5-7
--------------------------------------------------------------------------------
/docs/develop/design/db-data-read.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '数据读取'
3 | title: 数据读取
4 | sidebar_position: 3
5 | ---
6 |
7 | ## 数据权限管理
8 |
9 | #### 版本记录
10 |
11 | 日期 |内容|撰写人
12 | |---|---|---|
13 | 2022/05/09| V1.0 初版| 刘胜杰
14 |
15 | ## 人员
16 | - 需求提出: 刘胜杰
17 | - 研发: 刘胜杰
18 | - 抄送:
19 |
20 | ## 问题
21 | 需提供数据查询功能
22 |
23 | ## 目标
24 | - 提供数据查询功能
25 | - 数据查询受权限控制
26 |
27 | ## 设计
28 |
29 | ### 整体设计
30 | 用户选择集群,数据库;
31 | 展示提示性的sql语句,提示表结构信息;
32 | 而后由用户在文本框中输入sql进行查询;
33 | 结果以动态表格展示。
34 |
35 | ### 详细设计
36 |
37 | #### 页面
38 | - 数据查询页,第一行为信息选择,集群,数据库选择;第二行展示提示性sql及输入文本框;第三行展示返回的数据表。
39 | - 集群、数据库的选择受权限控制。
40 | - 数据查询如无limit,自动添加20的limit。
41 | - 数据查询提前验证是否匹配索引,如不完全匹配,则警告并询问是否继续。
42 | - 数据查询行为,记录到操作记录。
43 |
44 | #### 表
45 | 无新增表
46 |
47 | #### 后端
48 | - 一个执行用户输入的接口。
49 | - 确保执行的是读sql。
50 | - 返回数据,二维数组?
51 |
52 |
53 | ## 排期
54 |
55 | - [x] 后端接口ready @刘胜杰 2020-5-13
56 | - [x] 前端页面ready 并调通管理 2020-5-15
57 | - [x] db list经权限过滤 2022-5-17
--------------------------------------------------------------------------------
/docs/develop/design/redis-write.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'redis-write'
3 | title: redis-write
4 | sidebar_position: 5
5 | ---
6 | ## redis读写
7 |
8 | #### 版本记录
9 |
10 | 日期 |内容|撰写人
11 | |---|---|---|
12 | 2023/02/09| V1.0 初版| 刘胜杰
13 |
14 | ## 人员
15 | - 需求提出:刘胜杰
16 | - 研发: 刘胜杰
17 | - 抄送:
18 |
19 | ## 问题
20 |
21 | 支持redis的数据查询、命令执行
22 |
23 | ## 目标
24 |
25 | - 支持数据查询
26 | - 支持写命令审批、执行
27 | - 读写命令,支持白名单、影响范围限制等
28 |
29 | ## 设计
30 | ### 整体设计
31 |
32 | - 读数据
33 | - 限制范围内,直接执行读取并返回结果
34 | - 写数据
35 | - 生成任务、通过审批后可执行
36 | - 一个任务内科包含多条命令
37 | - 集群管理复用DB集群管理,增加Type字段,支持UI检索
38 |
39 |
40 | ### 详细设计
41 |
42 | - 在白名单的基础上,支持范围限制
43 | - 读白名单
44 |
45 | 命令|说明|范围
46 | |---|---|---|
47 | get |
48 | mget |
49 | hget |
50 | hmget |
51 | lrange |限制影响数据量|1000
52 | zrange |限制影响数据量|1000
53 | sismember ||
54 | scard ||
55 | zcard ||
56 | hscan ||
57 | ttl ||
58 | type ||
59 | hlen ||
60 | exists ||
61 | sscan ||
62 |
63 | - 写白名单
64 |
65 | 命令|说明|范围
66 | |---|---|---|
67 | set ||
68 | mset ||
69 | hset ||
70 | hmset ||
71 | hdel ||
72 | del ||
73 | zrem ||
74 | srem ||
75 | sadd ||
76 | zadd ||
77 | incrby ||
78 | - ……
79 |
80 | 排期
81 |
82 | - [x] 暂无[人员][日期]
83 | - [ ] Milestone 2
84 | - [ ] ……
--------------------------------------------------------------------------------
/docs/develop/design/template.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '模板'
3 | title: 模板
4 | sidebar_position: 6
5 | ---
6 | ## 标题
7 |
8 | #### 版本记录
9 |
10 | 日期 |内容|撰写人
11 | |---|---|---|
12 | 2022/01/04| V1.0 初版| 李不凡
13 |
14 | ## 人员
15 | - 需求提出:
16 | - 研发:
17 | - 抄送:
18 |
19 | ## 问题
20 | (请描述遇到的问题、对业务的影响等)
21 |
22 | ## 目标
23 | (请描述期望达到的状态、解决的问题、创造的价值等)
24 |
25 | ## 设计
26 | ### 整体设计
27 | ### 详细设计
28 |
29 | - 子任务A
30 | - 子任务B
31 | - ……
32 |
33 | 排期
34 |
35 | - [x] Milestone 1 (描述达到状态)[人员][日期]
36 | - [ ] Milestone 2
37 | - [ ] ……
--------------------------------------------------------------------------------
/docs/develop/design/user-login.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '登录'
3 | title: 登录
4 | sidebar_position: 2
5 | ---
6 | ## 标题
7 |
8 | #### 版本记录
9 |
10 | 日期 |内容|撰写人
11 | |---|---|---|
12 | 2022/06/05| V1.0 初版| 刘胜杰
13 |
14 | ## 人员
15 | - 需求提出:
16 | - 研发: 刘胜杰 &
17 | - 抄送:
18 |
19 | ## 问题
20 | 解决不用场景下的用户接入,用户登录问题
21 |
22 | ## 目标
23 | 提供多种方式,支持不同场景下用户接入需求
24 | 1,支持ldap接入方式
25 | 2,支持注册登录方式
26 | 3,设计好用户接口,使得方便接入企业内部用户系统
27 |
28 | ## 设计
29 | - 以配置切换不同的用户模式
30 | 根据配置值,注入不同的用户登录实现,
31 | 并根据配置值展示登陆页面的是否有‘注册’按钮
32 | - 梳理现有的用户系统,设计登陆相关的接口
33 | 需改造现有的登陆实现,
34 | - 支持ldap接入用户登录
35 | 现有部分ldap代码,需要接入改造并测试
36 | - 支持注册登录方式
37 | 登陆已经存在,需添加注册功能
38 | 目前管理员可以修改用户密码,需支持用户修改自己的密码
39 |
40 | ## 排期
41 |
42 | - [x] 支持ldap 2022-06中
43 | - [x] 支持注册登录方式 2022-06下
44 | - [ ] 整理接入内部用户系统的文档
--------------------------------------------------------------------------------
/docs/develop/intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '介绍'
3 | title: 介绍
4 | sidebar_position: 1
5 | ---
6 |
7 | ### 模块说明
8 |
9 | 此模块为研发相关的文档,包括项目本地启动、编译、部署更新、设计文档等内容。
10 |
11 | 用户文档请查阅其他部分。
--------------------------------------------------------------------------------
/docs/develop/roadmap.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 2
3 | title: Roadmap
4 | ---
5 |
6 | ## 说明
7 | 开发计划会优先考虑用户提出的需求,欢迎在issue或者社区微信群里提出需求。
8 |
9 | ### 中短期计划
10 |
11 | * 完善文档
12 | * 支持mysql使用ghost改表
13 | * 收集展示库表状态信息
14 | * redis缓存管理
15 |
16 |
17 | ### 长期计划
18 |
19 | * MQ管理
20 | * ......
21 |
22 | ### 需求
23 |
24 | * 支持SqlServer,PG
25 | * 支持ClickHouse
--------------------------------------------------------------------------------
/docs/docs/tutorial-basics/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Tutorial - Basics",
3 | "position": 2,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "5 minutes to learn the most important Docusaurus concepts."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/docs/tutorial-basics/congratulations.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 6
3 | ---
4 |
5 | # Congratulations!
6 |
7 | You have just learned the **basics of Docusaurus** and made some changes to the **initial template**.
8 |
9 | Docusaurus has **much more to offer**!
10 |
11 | Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**.
12 |
13 | Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610)
14 |
15 | ## What's next?
16 |
17 | - Read the [official documentation](https://docusaurus.io/).
18 | - Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout)
19 | - Add a [search bar](https://docusaurus.io/docs/search)
20 | - Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase)
21 | - Get involved in the [Docusaurus Community](https://docusaurus.io/community/support)
22 |
--------------------------------------------------------------------------------
/docs/docs/tutorial-basics/create-a-blog-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 3
3 | ---
4 |
5 | # Create a Blog Post
6 |
7 | Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed...
8 |
9 | ## Create your first Post
10 |
11 | Create a file at `blog/2021-02-28-greetings.md`:
12 |
13 | ```md title="blog/2021-02-28-greetings.md"
14 | ---
15 | slug: greetings
16 | title: Greetings!
17 | authors:
18 | - name: Joel Marcey
19 | title: Co-creator of Docusaurus 1
20 | url: https://github.com/JoelMarcey
21 | image_url: https://github.com/JoelMarcey.png
22 | - name: Sébastien Lorber
23 | title: Docusaurus maintainer
24 | url: https://sebastienlorber.com
25 | image_url: https://github.com/slorber.png
26 | tags: [greetings]
27 | ---
28 |
29 | Congratulations, you have made your first post!
30 |
31 | Feel free to play around and edit this post as much you like.
32 | ```
33 |
34 | A new blog post is now available at `http://localhost:3000/blog/greetings`.
35 |
--------------------------------------------------------------------------------
/docs/docs/tutorial-basics/create-a-document.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 2
3 | ---
4 |
5 | # Create a Document
6 |
7 | Documents are **groups of pages** connected through:
8 |
9 | - a **sidebar**
10 | - **previous/next navigation**
11 | - **versioning**
12 |
13 | ## Create your first Doc
14 |
15 | Create a markdown file at `docs/hello.md`:
16 |
17 | ```md title="docs/hello.md"
18 | # Hello
19 |
20 | This is my **first Docusaurus document**!
21 | ```
22 |
23 | A new document is now available at `http://localhost:3000/docs/hello`.
24 |
25 | ## Configure the Sidebar
26 |
27 | Docusaurus automatically **creates a sidebar** from the `docs` folder.
28 |
29 | Add metadata to customize the sidebar label and position:
30 |
31 | ```md title="docs/hello.md" {1-4}
32 | ---
33 | sidebar_label: 'Hi!'
34 | sidebar_position: 3
35 | ---
36 |
37 | # Hello
38 |
39 | This is my **first Docusaurus document**!
40 | ```
41 |
42 | It is also possible to create your sidebar explicitly in `sidebars.js`:
43 |
44 | ```js title="sidebars.js"
45 | module.exports = {
46 | tutorialSidebar: [
47 | {
48 | type: 'category',
49 | label: 'Tutorial',
50 | // highlight-next-line
51 | items: ['hello'],
52 | },
53 | ],
54 | };
55 | ```
56 |
--------------------------------------------------------------------------------
/docs/docs/tutorial-basics/create-a-page.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 1
3 | ---
4 |
5 | # Create a Page
6 |
7 | Add **Markdown or React** files to `src/pages` to create a **standalone page**:
8 |
9 | - `src/pages/index.js` -> `localhost:3000/`
10 | - `src/pages/foo.md` -> `localhost:3000/foo`
11 | - `src/pages/foo/bar.js` -> `localhost:3000/foo/bar`
12 |
13 | ## Create your first React Page
14 |
15 | Create a file at `src/pages/my-react-page.js`:
16 |
17 | ```jsx title="src/pages/my-react-page.js"
18 | import React from 'react';
19 | import Layout from '@theme/Layout';
20 |
21 | export default function MyReactPage() {
22 | return (
23 |
24 | My React page
25 | This is a React page
26 |
27 | );
28 | }
29 | ```
30 |
31 | A new page is now available at `http://localhost:3000/my-react-page`.
32 |
33 | ## Create your first Markdown Page
34 |
35 | Create a file at `src/pages/my-markdown-page.md`:
36 |
37 | ```mdx title="src/pages/my-markdown-page.md"
38 | # My Markdown page
39 |
40 | This is a Markdown page
41 | ```
42 |
43 | A new page is now available at `http://localhost:3000/my-markdown-page`.
44 |
--------------------------------------------------------------------------------
/docs/docs/tutorial-basics/deploy-your-site.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 5
3 | ---
4 |
5 | # Deploy your site
6 |
7 | Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**).
8 |
9 | It builds your site as simple **static HTML, JavaScript and CSS files**.
10 |
11 | ## Build your site
12 |
13 | Build your site **for production**:
14 |
15 | ```bash
16 | npm run build
17 | ```
18 |
19 | The static files are generated in the `build` folder.
20 |
21 | ## Deploy your site
22 |
23 | Test your production build locally:
24 |
25 | ```bash
26 | npm run serve
27 | ```
28 |
29 | The `build` folder is now served at `http://localhost:3000/`.
30 |
31 | You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**).
32 |
--------------------------------------------------------------------------------
/docs/docs/tutorial-extras/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Tutorial - Extras",
3 | "position": 3,
4 | "link": {
5 | "type": "generated-index"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/docs/docs/tutorial-extras/img/docsVersionDropdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/docs/tutorial-extras/img/docsVersionDropdown.png
--------------------------------------------------------------------------------
/docs/docs/tutorial-extras/img/localeDropdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/docs/tutorial-extras/img/localeDropdown.png
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "owls",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "docusaurus": "docusaurus",
7 | "start": "docusaurus start",
8 | "build": "docusaurus build",
9 | "swizzle": "docusaurus swizzle",
10 | "deploy": "docusaurus deploy",
11 | "clear": "docusaurus clear",
12 | "serve": "docusaurus serve",
13 | "write-translations": "docusaurus write-translations",
14 | "write-heading-ids": "docusaurus write-heading-ids"
15 | },
16 | "dependencies": {
17 | "@docusaurus/core": "2.0.0-beta.21",
18 | "@docusaurus/preset-classic": "2.0.0-beta.21",
19 | "@mdx-js/react": "^1.6.22",
20 | "clsx": "^1.1.1",
21 | "prism-react-renderer": "^1.3.3",
22 | "react": "^17.0.2",
23 | "react-dom": "^17.0.2"
24 | },
25 | "devDependencies": {
26 | "@docusaurus/module-type-aliases": "2.0.0-beta.21"
27 | },
28 | "browserslist": {
29 | "production": [
30 | ">0.5%",
31 | "not dead",
32 | "not op_mini all"
33 | ],
34 | "development": [
35 | "last 1 chrome version",
36 | "last 1 firefox version",
37 | "last 1 safari version"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/docs/sidebars.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Creating a sidebar enables you to:
3 | - create an ordered group of docs
4 | - render a sidebar for each doc of that group
5 | - provide next/previous navigation
6 |
7 | The sidebars can be generated from the filesystem, or explicitly defined here.
8 |
9 | Create as many sidebars as you want.
10 | */
11 |
12 | // @ts-check
13 |
14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
15 | const sidebars = {
16 | // By default, Docusaurus generates a sidebar from the docs folder structure
17 | tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],
18 |
19 | // But you can create a sidebar manually
20 | /*
21 | tutorialSidebar: [
22 | {
23 | type: 'category',
24 | label: 'Tutorial',
25 | items: ['hello'],
26 | },
27 | ],
28 | */
29 | };
30 |
31 | module.exports = sidebars;
32 |
--------------------------------------------------------------------------------
/docs/src/components/HomepageFeatures/styles.module.css:
--------------------------------------------------------------------------------
1 | .features {
2 | display: flex;
3 | align-items: center;
4 | padding: 2rem 0;
5 | width: 100%;
6 | }
7 |
8 | .featureSvg {
9 | height: 200px;
10 | width: 200px;
11 | }
12 |
--------------------------------------------------------------------------------
/docs/src/css/custom.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Any CSS included here will be global. The classic template
3 | * bundles Infima by default. Infima is a CSS framework designed to
4 | * work well for content-centric websites.
5 | */
6 |
7 | /* You can override the default Infima variables here. */
8 | :root {
9 | --ifm-color-primary: #2e8555;
10 | --ifm-color-primary-dark: #29784c;
11 | --ifm-color-primary-darker: #277148;
12 | --ifm-color-primary-darkest: #205d3b;
13 | --ifm-color-primary-light: #33925d;
14 | --ifm-color-primary-lighter: #359962;
15 | --ifm-color-primary-lightest: #3cad6e;
16 | --ifm-code-font-size: 95%;
17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
18 | }
19 |
20 | /* For readability concerns, you should choose a lighter palette in dark mode. */
21 | [data-theme='dark'] {
22 | --ifm-color-primary: #25c2a0;
23 | --ifm-color-primary-dark: #21af90;
24 | --ifm-color-primary-darker: #1fa588;
25 | --ifm-color-primary-darkest: #1a8870;
26 | --ifm-color-primary-light: #29d5b0;
27 | --ifm-color-primary-lighter: #32d8b4;
28 | --ifm-color-primary-lightest: #4fddbf;
29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
30 | }
31 |
--------------------------------------------------------------------------------
/docs/src/pages/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import Link from '@docusaurus/Link';
4 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
5 | import Layout from '@theme/Layout';
6 | import HomepageFeatures from '@site/src/components/HomepageFeatures';
7 |
8 | import styles from './index.module.css';
9 |
10 | function HomepageHeader() {
11 | const {siteConfig} = useDocusaurusContext();
12 | return (
13 |
26 | );
27 | }
28 |
29 | export default function Home() {
30 | const {siteConfig} = useDocusaurusContext();
31 | return (
32 |
35 |
36 |
37 |
38 |
39 |
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/docs/src/pages/index.module.css:
--------------------------------------------------------------------------------
1 | /**
2 | * CSS files with the .module.css suffix will be treated as CSS modules
3 | * and scoped locally.
4 | */
5 |
6 | .heroBanner {
7 | padding: 4rem 0;
8 | text-align: center;
9 | position: relative;
10 | overflow: hidden;
11 | }
12 |
13 | @media screen and (max-width: 996px) {
14 | .heroBanner {
15 | padding: 2rem;
16 | }
17 | }
18 |
19 | .buttons {
20 | display: flex;
21 | align-items: center;
22 | justify-content: center;
23 | }
24 |
--------------------------------------------------------------------------------
/docs/src/pages/markdown-page.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Markdown page example
3 | ---
4 |
5 | # Markdown page example
6 |
7 | You don't need React to write simple standalone pages.
8 |
--------------------------------------------------------------------------------
/docs/static/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/static/.nojekyll
--------------------------------------------------------------------------------
/docs/static/img/docusaurus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/static/img/docusaurus.png
--------------------------------------------------------------------------------
/docs/static/img/favicon-owl.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/static/img/favicon-owl.ico
--------------------------------------------------------------------------------
/docs/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/docs/static/img/favicon.ico
--------------------------------------------------------------------------------
/docs/user_guide/auth.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '权限'
3 | title: 权限管理
4 | sidebar_position: 3
5 | ---
6 |
7 | ### 权限实现
8 |
9 | 权限控制采用[Casbin](https://casbin.org/docs/zh-CN/overview)框架,使用的RBAC模型,默认会初始化一个admin角色和一个user角色,分别对应于[用户](./%E7%94%A8%E6%88%B7)中的admin用户和普通用户。
10 |
11 | 如需创建新的角色,可直接在`超级管理员/角色管理`页面创建新的角色并勾选赋予其权限即可。
--------------------------------------------------------------------------------
/docs/user_guide/db/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "TiDB/Mysql",
3 | "position": 4,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "database about。"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/user_guide/db/intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '介绍'
3 | title: 介绍
4 | sidebar_position: 1
5 | ---
6 |
7 | ### 对应功能模块
8 | 此模块介绍DB工单提交、数据读取相关的内容。对应的菜单是TiDB/Mysql。
9 |
10 | 如需查看安装、用户、权限等相关的文档介绍,请查阅[用户手册](../intro)文档。
--------------------------------------------------------------------------------
/docs/user_guide/db/read-sql.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '读数据'
3 | title: 数据读取
4 | sidebar_position: 1
5 | ---
6 |
7 | ### 前置依赖
8 |
9 | DB模块查询的数据源来自于此模块下`集群管理`中管理的集群,需要首先添加正确的集群信息,然后才能查询到数据。
10 |
11 | ### 权限控制
12 |
13 | 如不开启权限控制,则所有用户都可以查询所有集群中的数据。如果开启权限控制,则需要首先申请获取对应的DB权限,才能查询其数据。数据库权限的申请、审批都是在`权限`菜单中完成。
14 |
15 | **权限控制是否开启由`server/config.yaml`配置文件中的`db-filter/read-need-auth`字段控制,默认为false,即不开启。**
16 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/user_guide/db/write-sql.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '写工单'
3 | title: 提交写sql
4 | sidebar_position: 2
5 | ---
6 |
7 | ### 前置依赖
8 |
9 | 写工单的提交和执行,同样依赖于此模块下`集群管理`中管理的集群,需要首先添加正确的集群信息,然后才能使用工单流程。
10 |
11 | ### 审批流程
12 |
13 | 用户提交写请求工单后,可由拥有审批、执行页面权限(比如说admin)的用户进行审批和执行。
14 |
15 | 提交工单时,可以把多条sql复制到输入框中,以分号分隔。系统会自动拆分为多条子任务。
16 |
17 | 单次提交sql数量有限制,默认值为100,可以修改server/config.yaml配置文件中db-filter/num-once-limit值来控制。
18 |
19 | 执行DML语句会触发数据备份,默认备份失败也会继续执行,可以修改server/config.yaml配置文件中db-filter/exec-no-backup值来控制是否继续。
20 |
21 | **注意,大批量的写请求建议通过DBA手动备份后执行**,通过系统执行大批量的写请求,可能会备份失败。
22 |
23 |
--------------------------------------------------------------------------------
/docs/user_guide/intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '介绍'
3 | title: 介绍
4 | sidebar_position: 0
5 | ---
6 |
7 | ## 对应功能模块
8 | 此模块介绍安装、部署、用户、权限相关的内容。
9 |
10 | 如需查看数据库工单提交、数据查询相关的文档介绍,请查阅[DB文档](db/intro)。
11 | ## 软件介绍
12 |
13 | Owls是一个基于 [vue](https://vuejs.org) 和 [go](https://go.dev/) 开发的全栈前后端分离的数据交互管理平台,集成jwt鉴权,sql审批(sql查询,mq管理、redis使用管理、etcd管理等)。帮助您更方便、更规范的管理中间件系统,守护数据系统,提高系统稳定性,避免人为操作失误导致的故障,提高效率,解放创造力。
14 |
15 | ## 在线示例
16 |
17 | [在线预览](http://owls.nooncall.cn:8778/owls): http://owls.nooncall.cn:8778/owls
18 |
19 | 测试用户名:admin
20 |
21 | 密码:aaaaaa
22 |
23 | ## 仓库地址
24 |
25 | Github(科学上网):https://github.com/nooncall/owls
26 | Gitee(国内访问): https://gitee.com/nooncall/owls
27 |
--------------------------------------------------------------------------------
/docs/user_guide/quick-start.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '快速开始'
3 | title: 快速开始
4 | sidebar_position: 1
5 | ---
6 |
7 | ### Docker安装
8 |
9 | 如果使用准备好的DB,则可以直接执行:
10 |
11 | docker run -p 8778:8778 -d mingbai/owls:latest
12 |
13 | 如无,则创建docker网桥,然后分别docker启动mysql、owls的容器:
14 |
15 | docker network create owls
16 |
17 | docker run -d --network=owls --name=mysql -e MYSQL_ROOT_PASSWORD=aaaaaa mysql:5.7
18 |
19 | docker run -p 8778:8778 -d --network=owls mingbai/owls:latest
20 |
21 | ### 集群内安装
22 |
23 | kubectl apply -n argo -f https://github.com/nooncall/owls/tree/master/docs/user_guide/deployment.yaml
24 |
25 |
26 | ### 初始化
27 |
28 | 登陆页面点击初始化按钮,根据我们上面的安装步骤,数据库的地址应该写`mysql`(或自行准备的DB地址),密码`aaaaaa`,其他默认即可。
29 |
30 | ### 本地文档
31 |
32 | 访问: `http://localhost:8778/docs`
33 |
34 | ### Enjoy
35 | 现在访问`http://localhost:8778`即可尝试使用系统提供的功能了 。
36 |
37 | 默认创建的用户有两个,`admin`和`user` 密码都是`aaaaaa` 。
38 |
39 | 正式使用的系统,还是建议使用独立的、持久化的数据库,可以选择Mysql或者TiDB。
--------------------------------------------------------------------------------
/docs/user_guide/sidebarsCommunity.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | module.exports = {
9 | community: [
10 | {
11 | type: 'autogenerated',
12 | dirName: '.',
13 | },
14 | {
15 | type: 'link',
16 | href: '/develop/community',
17 | label: '社区',
18 | },
19 | ],
20 | };
21 |
--------------------------------------------------------------------------------
/docs/user_guide/user.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: '用户'
3 | title: 用户管理
4 | sidebar_position: 2
5 | ---
6 |
7 | ### 初始化用户
8 |
9 | 执行初始化时,会初始化一个`admin`用户,一个`user`用户,其密码是在配置文件server/config.yaml中配置的,默认为`aaaaaa`
10 |
11 | ### 新用户接入方式
12 |
13 | 新用户接入支持两种方式,由server/config.yaml配置文件中的login/model控制,registry为注册登录模式,ldap为接入LDAP的方式。默认值为registry。
14 |
15 | #### 注册-登陆
16 |
17 | 配置为注册登录模式,会在用户页面显示`注册`按钮,点击即可进行注册,新注册的用户默认为普通用户权限,如需调整调整权限,可由admin用户创建并赋予其新的角色。
18 |
19 | #### LDAP接入用户
20 |
21 | LDAP模式需要正确填写server/config.yaml配置文件中login/ldap下的配置。配置正确后可接入LDAP系统,使用LDAP账号密码登陆系统。新登陆的用户默认同样为普通用户权限。
--------------------------------------------------------------------------------
/go/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:alpine as builder
2 |
3 | WORKDIR /go/src/github.com/nooncall/owls/go
4 | COPY . .
5 |
6 | RUN go env -w GO111MODULE=on \
7 | && go env -w GOPROXY=https://goproxy.cn,direct \
8 | && go env -w CGO_ENABLED=0 \
9 | && go env \
10 | && go mod tidy \
11 | && go build -o server .
12 |
13 | FROM alpine:latest
14 |
15 | LABEL MAINTAINER="SliverHorn@sliver_horn@qq.com"
16 |
17 | WORKDIR /go/src/github.com/nooncall/owls/go
18 |
19 | COPY --from=0 /go/src/github.com/nooncall/owls/go/server ./
20 | COPY --from=0 /go/src/github.com/nooncall/owls/go/resource ./resource/
21 | COPY --from=0 /go/src/github.com/nooncall/owls/go/config.docker.yaml ./
22 |
23 | EXPOSE 8888
24 | ENTRYPOINT ./server -c config.docker.yaml
25 |
--------------------------------------------------------------------------------
/go/api/v1/autocode/enter.go:
--------------------------------------------------------------------------------
1 | package autocode
2 |
3 | type ApiGroup struct {
4 | // Code generated by github.com/nooncall/owls/go Begin; DO NOT EDIT.
5 | AutoCodeExampleApi
6 | // Code generated by github.com/nooncall/owls/go End; DO NOT EDIT.
7 | }
8 |
--------------------------------------------------------------------------------
/go/api/v1/enter.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "github.com/nooncall/owls/go/api/v1/auth"
5 | "github.com/nooncall/owls/go/api/v1/autocode"
6 | "github.com/nooncall/owls/go/api/v1/example"
7 | "github.com/nooncall/owls/go/api/v1/redis"
8 | "github.com/nooncall/owls/go/api/v1/system"
9 | "github.com/nooncall/owls/go/api/v1/task"
10 | "github.com/nooncall/owls/go/api/v1/tidb_or_mysql"
11 | )
12 |
13 | type ApiGroup struct {
14 | SystemApiGroup system.ApiGroup
15 | ExampleApiGroup example.ApiGroup
16 | AutoCodeApiGroup autocode.ApiGroup
17 | TiDBOrMysqlGroup tidb_or_mysql.ApiGroup
18 | Redis redis.ApiGroup
19 | Task task.TaskApi
20 | Auth auth.AuthApi
21 | }
22 |
23 | var ApiGroupApp = new(ApiGroup)
24 |
25 | type ListData struct {
26 | Total int64 `json:"total"`
27 | List interface{} `json:"list"`
28 | Page int `json:"page"`
29 | PageSize int `json:"pageSize"`
30 | }
31 |
--------------------------------------------------------------------------------
/go/api/v1/example/enter.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import "github.com/nooncall/owls/go/service"
4 |
5 | type ApiGroup struct {
6 | ExcelApi
7 | CustomerApi
8 | }
9 |
10 | var (
11 | excelService = service.ServiceGroupApp.ExampleServiceGroup.ExcelService
12 | customerService = service.ServiceGroupApp.ExampleServiceGroup.CustomerService
13 | fileUploadAndDownloadService = service.ServiceGroupApp.ExampleServiceGroup.FileUploadAndDownloadService
14 | )
15 |
--------------------------------------------------------------------------------
/go/api/v1/redis/enter.go:
--------------------------------------------------------------------------------
1 | package redis
2 |
3 | type ApiGroup struct {
4 | ReadApi
5 | }
6 |
--------------------------------------------------------------------------------
/go/api/v1/system/sys_jwt_blacklist.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/nooncall/owls/go/global"
6 | "github.com/nooncall/owls/go/model/common/response"
7 | "github.com/nooncall/owls/go/model/system"
8 | "go.uber.org/zap"
9 | )
10 |
11 | type JwtApi struct{}
12 |
13 | // @Tags Jwt
14 | // @Summary jwt加入黑名单
15 | // @Security ApiKeyAuth
16 | // @accept application/json
17 | // @Produce application/json
18 | // @Success 200 {object} response.Response{msg=string} "jwt加入黑名单"
19 | // @Router /jwt/jsonInBlacklist [post]
20 | func (j *JwtApi) JsonInBlacklist(c *gin.Context) {
21 | token := c.Request.Header.Get("x-token")
22 | jwt := system.JwtBlacklist{Jwt: token}
23 | if err := jwtService.JsonInBlacklist(jwt); err != nil {
24 | global.GVA_LOG.Error("jwt作废失败!", zap.Error(err))
25 | response.FailWithMessage("jwt作废失败", c)
26 | } else {
27 | response.OkWithMessage("jwt作废成功", c)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/go/api/v1/tidb_or_mysql/common.go:
--------------------------------------------------------------------------------
1 | package tidb_or_mysql
2 |
3 | type Resp struct {
4 | Code int `json:"code"`
5 | Message string `json:"message"`
6 | Data interface{} `json:"data"`
7 | }
8 |
9 | type ListData struct {
10 | Total int64 `json:"total"`
11 | List interface{} `json:"list"`
12 | More bool `json:"more"`
13 | Offset int `json:"offset"`
14 | Page int `json:"page"`
15 | PageSize int `json:"pageSize"`
16 | }
17 |
--------------------------------------------------------------------------------
/go/api/v1/tidb_or_mysql/enter.go:
--------------------------------------------------------------------------------
1 | package tidb_or_mysql
2 |
3 | type ApiGroup struct {
4 | AdminApi
5 | BackupApi
6 | ClusterApi
7 | RuleApi
8 | TaskApi
9 | ReadApi
10 | }
11 |
--------------------------------------------------------------------------------
/go/api/v1/tidb_or_mysql/read.go:
--------------------------------------------------------------------------------
1 | package tidb_or_mysql
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/gin-gonic/gin"
7 |
8 | "github.com/nooncall/owls/go/model/common/response"
9 | "github.com/nooncall/owls/go/service/tidb_or_mysql/task"
10 | )
11 |
12 | type ReadApi struct{}
13 |
14 | func (readApi *ReadApi) ReadData(ctx *gin.Context) {
15 | f := "ReadData() -->"
16 |
17 | var req task.SqlParam
18 | if err := ctx.BindJSON(&req); err != nil {
19 | response.FailWithMessage(fmt.Sprintf("%s, parse param failed :%s ", f, err.Error()), ctx)
20 | return
21 | }
22 |
23 | rollBackData, err := task.ReadData(&req)
24 | if err != nil {
25 | response.FailWithMessage(fmt.Sprintf("%s: read failed, err: %s", f, err.Error()), ctx)
26 | return
27 | }
28 |
29 | response.OkWithData(rollBackData, ctx)
30 | }
31 |
32 | func (readApi *ReadApi) GetTableInfo(ctx *gin.Context) {
33 | f := "GetTableInfo()-->"
34 | var req task.SqlParam
35 | if err := ctx.BindJSON(&req); err != nil {
36 | response.FailWithMessage(fmt.Sprintf("%s, parse param failed :%s ", f, err.Error()), ctx)
37 | return
38 | }
39 |
40 | info, err := task.GetTableInfo(&req)
41 | if err != nil {
42 | response.FailWithMessage(fmt.Sprintf("%s: get table info failed, err: %s", f, err.Error()), ctx)
43 | return
44 | }
45 | response.OkWithData(info, ctx)
46 | }
47 |
--------------------------------------------------------------------------------
/go/cmd/owls/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/nooncall/owls/go/core"
5 | "github.com/nooncall/owls/go/global"
6 | "github.com/nooncall/owls/go/initialize"
7 | "github.com/nooncall/owls/go/service/tidb_or_mysql/injection"
8 | "github.com/nooncall/owls/go/utils/logger"
9 | "go.uber.org/zap"
10 | )
11 |
12 | //go:generate go env -w GO111MODULE=on
13 | //go:generate go env -w GOPROXY=https://goproxy.cn,direct
14 | //go:generate go mod tidy
15 | //go:generate go mod download
16 |
17 | // @title Swagger Example API
18 | // @version 0.0.1
19 | // @description This is a sample Server pets
20 | // @securityDefinitions.apikey ApiKeyAuth
21 | // @in header
22 | // @name x-token
23 | // @BasePath /
24 | func main() {
25 | global.GVA_VP = core.Viper() // 初始化Viper
26 | global.GVA_LOG = core.Zap() // 初始化zap日志库
27 | zap.ReplaceGlobals(global.GVA_LOG)
28 | global.GVA_DB = initialize.Gorm() // gorm连接数据库
29 | if global.GVA_DB != nil {
30 | initialize.RegisterTables(global.GVA_DB) // 初始化表
31 | // 程序结束前关闭数据库链接
32 | db, _ := global.GVA_DB.DB()
33 | defer db.Close()
34 | }
35 |
36 | injection.Injection()
37 | logger.InitLog(global.GVA_CONFIG.DBFilter.LogDir, "owl.log", global.GVA_CONFIG.DBFilter.LogLevel)
38 |
39 | core.RunWindowsServer()
40 | }
41 |
--------------------------------------------------------------------------------
/go/config/auto_code.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Autocode struct {
4 | TransferRestart bool `mapstructure:"transfer-restart" json:"transferRestart" yaml:"transfer-restart"`
5 | Root string `mapstructure:"root" json:"root" yaml:"root"`
6 | Server string `mapstructure:"server" json:"server" yaml:"server"`
7 | SApi string `mapstructure:"server-api" json:"serverApi" yaml:"server-api"`
8 | SInitialize string `mapstructure:"server-initialize" json:"serverInitialize" yaml:"server-initialize"`
9 | SModel string `mapstructure:"server-model" json:"serverModel" yaml:"server-model"`
10 | SRequest string `mapstructure:"server-request" json:"serverRequest" yaml:"server-request"`
11 | SRouter string `mapstructure:"server-router" json:"serverRouter" yaml:"server-router"`
12 | SService string `mapstructure:"server-service" json:"serverService" yaml:"server-service"`
13 | Web string `mapstructure:"web" json:"web" yaml:"web"`
14 | WApi string `mapstructure:"web-api" json:"webApi" yaml:"web-api"`
15 | WForm string `mapstructure:"web-form" json:"webForm" yaml:"web-form"`
16 | WTable string `mapstructure:"web-table" json:"webTable" yaml:"web-table"`
17 | }
18 |
--------------------------------------------------------------------------------
/go/config/captcha.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Captcha struct {
4 | KeyLong int `mapstructure:"key-long" json:"keyLong" yaml:"key-long"` // 验证码长度
5 | ImgWidth int `mapstructure:"img-width" json:"imgWidth" yaml:"img-width"` // 验证码宽度
6 | ImgHeight int `mapstructure:"img-height" json:"imgHeight" yaml:"img-height"` // 验证码高度
7 | }
8 |
--------------------------------------------------------------------------------
/go/config/casbin.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Casbin struct {
4 | ModelPath string `mapstructure:"model-path" json:"modelPath" yaml:"model-path"` // 存放casbin模型的相对路径
5 | }
6 |
--------------------------------------------------------------------------------
/go/config/cors.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type CORS struct {
4 | Mode string `mapstructure:"mode" json:"mode" yaml:"mode"`
5 | Whitelist []CORSWhitelist `mapstructure:"whitelist" json:"whitelist" yaml:"whitelist"`
6 | }
7 |
8 | type CORSWhitelist struct {
9 | AllowOrigin string `mapstructure:"allow-origin" json:"allow-origin" yaml:"allow-origin"`
10 | AllowMethods string `mapstructure:"allow-methods" json:"allow-methods" yaml:"allow-methods"`
11 | AllowHeaders string `mapstructure:"allow-headers" json:"allow-headers" yaml:"allow-headers"`
12 | ExposeHeaders string `mapstructure:"expose-headers" json:"expose-headers" yaml:"expose-headers"`
13 | AllowCredentials bool `mapstructure:"allow-credentials" json:"allow-credentials" yaml:"allow-credentials"`
14 | }
15 |
--------------------------------------------------------------------------------
/go/config/email.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Email struct {
4 | To string `mapstructure:"to" json:"to" yaml:"to"` // 收件人:多个以英文逗号分隔
5 | Port int `mapstructure:"port" json:"port" yaml:"port"` // 端口
6 | From string `mapstructure:"from" json:"from" yaml:"from"` // 收件人
7 | Host string `mapstructure:"host" json:"host" yaml:"host"` // 服务器地址
8 | IsSSL bool `mapstructure:"is-ssl" json:"isSSL" yaml:"is-ssl"` // 是否SSL
9 | Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥
10 | Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"` // 昵称
11 | }
12 |
--------------------------------------------------------------------------------
/go/config/excel.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Excel struct {
4 | Dir string `mapstructure:"dir" json:"dir" yaml:"dir"`
5 | }
6 |
--------------------------------------------------------------------------------
/go/config/gorm_mysql.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Mysql struct {
4 | Path string `mapstructure:"path" json:"path" yaml:"path"` // 服务器地址
5 | Port string `mapstructure:"port" json:"port" yaml:"port"` // 端口
6 | Config string `mapstructure:"config" json:"config" yaml:"config"` // 高级配置
7 | Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"` // 数据库名
8 | Username string `mapstructure:"username" json:"username" yaml:"username"` // 数据库用户名
9 | Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码
10 | MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"` // 空闲中的最大连接数
11 | MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"` // 打开到数据库的最大连接数
12 | LogMode string `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"` // 是否开启Gorm全局日志
13 | LogZap bool `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"` // 是否通过zap写入日志文件
14 | }
15 |
16 | func (m *Mysql) Dsn() string {
17 | return m.Username + ":" + m.Password + "@tcp(" + m.Path + ":" + m.Port + ")/" + m.Dbname + "?" + m.Config
18 | }
19 |
20 | func (m *Mysql) GetLogMode() string {
21 | return m.LogMode
22 | }
23 |
--------------------------------------------------------------------------------
/go/config/jwt.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type JWT struct {
4 | SigningKey string `mapstructure:"signing-key" json:"signingKey" yaml:"signing-key"` // jwt签名
5 | ExpiresTime int64 `mapstructure:"expires-time" json:"expiresTime" yaml:"expires-time"` // 过期时间
6 | BufferTime int64 `mapstructure:"buffer-time" json:"bufferTime" yaml:"buffer-time"` // 缓冲时间
7 | Issuer string `mapstructure:"issuer" json:"issuer" yaml:"issuer"` // 签发者
8 | }
9 |
--------------------------------------------------------------------------------
/go/config/oss_aliyun.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type AliyunOSS struct {
4 | Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
5 | AccessKeyId string `mapstructure:"access-key-id" json:"accessKeyId" yaml:"access-key-id"`
6 | AccessKeySecret string `mapstructure:"access-key-secret" json:"accessKeySecret" yaml:"access-key-secret"`
7 | BucketName string `mapstructure:"bucket-name" json:"bucketName" yaml:"bucket-name"`
8 | BucketUrl string `mapstructure:"bucket-url" json:"bucketUrl" yaml:"bucket-url"`
9 | BasePath string `mapstructure:"base-path" json:"basePath" yaml:"base-path"`
10 | }
11 |
--------------------------------------------------------------------------------
/go/config/oss_aws.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type AwsS3 struct {
4 | Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
5 | Region string `mapstructure:"region" json:"region" yaml:"region"`
6 | Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
7 | S3ForcePathStyle bool `mapstructure:"s3-force-path-style" json:"s3ForcePathStyle" yaml:"s3-force-path-style"`
8 | DisableSSL bool `mapstructure:"disable-ssl" json:"disableSSL" yaml:"disable-ssl"`
9 | SecretID string `mapstructure:"secret-id" json:"secretID" yaml:"secret-id"`
10 | SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"`
11 | BaseURL string `mapstructure:"base-url" json:"baseURL" yaml:"base-url"`
12 | PathPrefix string `mapstructure:"path-prefix" json:"pathPrefix" yaml:"path-prefix"`
13 | }
14 |
--------------------------------------------------------------------------------
/go/config/oss_huawei.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type HuaWeiObs struct {
4 | Path string `mapstructure:"path" json:"path" yaml:"path"`
5 | Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
6 | Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
7 | AccessKey string `mapstructure:"access-key" json:"accessKey" yaml:"access-key"`
8 | SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"`
9 | }
10 |
--------------------------------------------------------------------------------
/go/config/oss_local.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Local struct {
4 | Path string `mapstructure:"path" json:"path" yaml:"path"` // 本地文件路径
5 | }
6 |
--------------------------------------------------------------------------------
/go/config/oss_qiniu.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Qiniu struct {
4 | Zone string `mapstructure:"zone" json:"zone" yaml:"zone"` // 存储区域
5 | Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` // 空间名称
6 | ImgPath string `mapstructure:"img-path" json:"imgPath" yaml:"img-path"` // CDN加速域名
7 | UseHTTPS bool `mapstructure:"use-https" json:"useHttps" yaml:"use-https"` // 是否使用https
8 | AccessKey string `mapstructure:"access-key" json:"accessKey" yaml:"access-key"` // 秘钥AK
9 | SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"` // 秘钥SK
10 | UseCdnDomains bool `mapstructure:"use-cdn-domains" json:"useCdnDomains" yaml:"use-cdn-domains"` // 上传是否使用CDN上传加速
11 | }
12 |
--------------------------------------------------------------------------------
/go/config/oss_tencent.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type TencentCOS struct {
4 | Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
5 | Region string `mapstructure:"region" json:"region" yaml:"region"`
6 | SecretID string `mapstructure:"secret-id" json:"secretID" yaml:"secret-id"`
7 | SecretKey string `mapstructure:"secret-key" json:"secretKey" yaml:"secret-key"`
8 | BaseURL string `mapstructure:"base-url" json:"baseURL" yaml:"base-url"`
9 | PathPrefix string `mapstructure:"path-prefix" json:"pathPrefix" yaml:"path-prefix"`
10 | }
11 |
--------------------------------------------------------------------------------
/go/config/redis.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Redis struct {
4 | DB int `mapstructure:"db" json:"db" yaml:"db"` // redis的哪个数据库
5 | Addr string `mapstructure:"addr" json:"addr" yaml:"addr"` // 服务器地址:端口
6 | Password string `mapstructure:"password" json:"password" yaml:"password"` // 密码
7 | }
8 |
--------------------------------------------------------------------------------
/go/config/system.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type System struct {
4 | Env string `mapstructure:"env" json:"env" yaml:"env"` // 环境值
5 | Addr int `mapstructure:"addr" json:"addr" yaml:"addr"` // 端口值
6 | DbType string `mapstructure:"db-type" json:"dbType" yaml:"db-type"` // 数据库类型:mysql(默认)|sqlite|sqlserver|postgresql
7 | OssType string `mapstructure:"oss-type" json:"ossType" yaml:"oss-type"` // Oss类型
8 | UseMultipoint bool `mapstructure:"use-multipoint" json:"useMultipoint" yaml:"use-multipoint"` // 多点登录拦截
9 | UseRedis bool `mapstructure:"use-redis" json:"useRedis" yaml:"use-redis"` // 使用redis
10 | LimitCountIP int `mapstructure:"iplimit-count" json:"iplimitCount" yaml:"iplimit-count"`
11 | LimitTimeIP int `mapstructure:"iplimit-time" json:"iplimitTime" yaml:"iplimit-time"`
12 | ShowSql bool `json:"show_sql"`
13 | }
14 |
--------------------------------------------------------------------------------
/go/config/timer.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Timer struct {
4 | Start bool `mapstructure:"start" json:"start" yaml:"start"` // 是否启用
5 | Spec string `mapstructure:"spec" json:"spec" yaml:"spec"` // CRON表达式
6 | Detail []Detail `mapstructure:"detail" json:"detail" yaml:"detail"`
7 | }
8 |
9 | type Detail struct {
10 | TableName string `mapstructure:"tableName" json:"tableName" yaml:"tableName"` // 需要清理的表名
11 | CompareField string `mapstructure:"compareField" json:"compareField" yaml:"compareField"` // 需要比较时间的字段
12 | Interval string `mapstructure:"interval" json:"interval" yaml:"interval"` // 时间间隔
13 | }
14 |
--------------------------------------------------------------------------------
/go/config/zap.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Zap struct {
4 | Level string `mapstructure:"level" json:"level" yaml:"level"` // 级别
5 | Format string `mapstructure:"format" json:"format" yaml:"format"` // 输出
6 | Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"` // 日志前缀
7 | Director string `mapstructure:"director" json:"director" yaml:"director"` // 日志文件夹
8 | ShowLine bool `mapstructure:"show-line" json:"showLine" yaml:"showLine"` // 显示行
9 | EncodeLevel string `mapstructure:"encode-level" json:"encodeLevel" yaml:"encode-level"` // 编码级
10 | StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktraceKey" yaml:"stacktrace-key"` // 栈名
11 | LogInConsole bool `mapstructure:"log-in-console" json:"logInConsole" yaml:"log-in-console"` // 输出控制台
12 | }
13 |
--------------------------------------------------------------------------------
/go/core/server_other.go:
--------------------------------------------------------------------------------
1 | //go:build !windows
2 | // +build !windows
3 |
4 | package core
5 |
6 | import (
7 | "time"
8 |
9 | "github.com/fvbock/endless"
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | func initServer(address string, router *gin.Engine) server {
14 | s := endless.NewServer(address, router)
15 | s.ReadHeaderTimeout = 20 * time.Second
16 | s.WriteTimeout = 20 * time.Second
17 | s.MaxHeaderBytes = 1 << 20
18 | return s
19 | }
20 |
--------------------------------------------------------------------------------
/go/core/server_win.go:
--------------------------------------------------------------------------------
1 | //go:build windows
2 | // +build windows
3 |
4 | package core
5 |
6 | import (
7 | "net/http"
8 | "time"
9 |
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | func initServer(address string, router *gin.Engine) server {
14 | return &http.Server{
15 | Addr: address,
16 | Handler: router,
17 | ReadTimeout: 20 * time.Second,
18 | WriteTimeout: 20 * time.Second,
19 | MaxHeaderBytes: 1 << 20,
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/go/global/model.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | import (
4 | "time"
5 |
6 | "gorm.io/gorm"
7 | )
8 |
9 | type GVA_MODEL struct {
10 | ID uint `gorm:"primarykey"` // 主键ID
11 | CreatedAt time.Time // 创建时间
12 | UpdatedAt time.Time // 更新时间
13 | DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` // 删除时间
14 | }
15 |
--------------------------------------------------------------------------------
/go/initialize/internal/logger.go:
--------------------------------------------------------------------------------
1 | package internal
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/nooncall/owls/go/global"
7 | "gorm.io/gorm/logger"
8 | )
9 |
10 | type writer struct {
11 | logger.Writer
12 | }
13 |
14 | // NewWriter writer 构造函数
15 | // Author [SliverHorn](https://github.com/SliverHorn)
16 | func NewWriter(w logger.Writer) *writer {
17 | return &writer{Writer: w}
18 | }
19 |
20 | // Printf 格式化打印日志
21 | // Author [SliverHorn](https://github.com/SliverHorn)
22 | func (w *writer) Printf(message string, data ...interface{}) {
23 | var logZap bool
24 | switch global.GVA_CONFIG.System.DbType {
25 | case "mysql":
26 | logZap = global.GVA_CONFIG.Mysql.LogZap
27 | case "pgsql":
28 | logZap = global.GVA_CONFIG.Pgsql.LogZap
29 | }
30 | if logZap {
31 | global.GVA_LOG.Info(fmt.Sprintf(message+"\n", data...))
32 | } else {
33 | w.Writer.Printf(message, data...)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/go/initialize/plugin.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | //"github.com/nooncall/owls/go/plugin/email" // 本地插件仓库地址模式
5 | "github.com/gin-gonic/gin"
6 | "github.com/nooncall/owls/go/plugin/example_plugin"
7 | "github.com/nooncall/owls/go/utils/plugin"
8 | )
9 |
10 | func PluginInit(group *gin.RouterGroup, Plugin ...plugin.Plugin) {
11 | for i := range Plugin {
12 | PluginGroup := group.Group(Plugin[i].RouterPath())
13 | Plugin[i].Register(PluginGroup)
14 | }
15 | }
16 |
17 | func InstallPlugin(PublicGroup *gin.RouterGroup, PrivateGroup *gin.RouterGroup) {
18 | // 添加开放权限的插件 示例
19 | PluginInit(PublicGroup, example_plugin.ExamplePlugin)
20 | }
21 |
--------------------------------------------------------------------------------
/go/initialize/validator.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import "github.com/nooncall/owls/go/utils"
4 |
5 | func init() {
6 | _ = utils.RegisterRule("PageVerify",
7 | utils.Rules{
8 | "Page": {utils.NotEmpty()},
9 | "PageSize": {utils.NotEmpty()},
10 | },
11 | )
12 | _ = utils.RegisterRule("IdVerify",
13 | utils.Rules{
14 | "Id": {utils.NotEmpty()},
15 | },
16 | )
17 | _ = utils.RegisterRule("AuthorityIdVerify",
18 | utils.Rules{
19 | "AuthorityId": {utils.NotEmpty()},
20 | },
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/go/middleware/casbin_rbac.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/nooncall/owls/go/global"
6 | "github.com/nooncall/owls/go/model/common/response"
7 | "github.com/nooncall/owls/go/service"
8 | "github.com/nooncall/owls/go/utils"
9 | )
10 |
11 | var casbinService = service.ServiceGroupApp.SystemServiceGroup.CasbinService
12 |
13 | // 拦截器
14 | func CasbinHandler() gin.HandlerFunc {
15 | return func(c *gin.Context) {
16 | waitUse, _ := utils.GetClaims(c)
17 | // 获取请求的PATH
18 | obj := c.Request.URL.Path
19 | // 获取请求方法
20 | act := c.Request.Method
21 | // 获取用户的角色
22 | sub := waitUse.AuthorityId
23 | e := casbinService.Casbin()
24 | // 判断策略中是否存在
25 | success, _ := e.Enforce(sub, obj, act)
26 | if global.GVA_CONFIG.System.Env == "develop" || success {
27 | c.Next()
28 | } else {
29 | c.Next()
30 | return
31 | // todo, handle this.
32 | response.FailWithDetailed(gin.H{}, "权限不足", c)
33 | c.Abort()
34 | return
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/go/middleware/loadtls.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/gin-gonic/gin"
7 | "github.com/unrolled/secure"
8 | )
9 |
10 | // 用https把这个中间件在router里面use一下就好
11 |
12 | func LoadTls() gin.HandlerFunc {
13 | return func(c *gin.Context) {
14 | middleware := secure.New(secure.Options{
15 | SSLRedirect: true,
16 | SSLHost: "localhost:443",
17 | })
18 | err := middleware.Process(c.Writer, c.Request)
19 | if err != nil {
20 | // 如果出现错误,请不要继续
21 | fmt.Println(err)
22 | return
23 | }
24 | // 继续往下处理
25 | c.Next()
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/go/middleware/need_init.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/nooncall/owls/go/global"
6 | "github.com/nooncall/owls/go/model/common/response"
7 | )
8 |
9 | // 处理跨域请求,支持options访问
10 | func NeedInit() gin.HandlerFunc {
11 | return func(c *gin.Context) {
12 | if global.GVA_DB == nil {
13 | response.OkWithDetailed(gin.H{
14 | "needInit": true,
15 | }, "前往初始化数据库", c)
16 | c.Abort()
17 | } else {
18 | c.Next()
19 | }
20 | // 处理请求
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/go/model/autocode/autocodeExample.go:
--------------------------------------------------------------------------------
1 | // 自动生成模板SysDictionaryDetail
2 | package autocode
3 |
4 | import (
5 | "github.com/nooncall/owls/go/global"
6 | )
7 |
8 | // 如果含有time.Time 请自行import time包
9 | type AutoCodeExample struct {
10 | global.GVA_MODEL
11 | AutoCodeExampleField string `json:"autoCodeExampleField" form:"autoCodeExampleField" gorm:"column:auto_code_example_field;comment:仅作示例条目无实际作用"` // 展示值
12 | }
13 |
--------------------------------------------------------------------------------
/go/model/autocode/request/autocodeExample.go:
--------------------------------------------------------------------------------
1 | // 自动生成模板SysDictionaryDetail
2 | package request
3 |
4 | import (
5 | "github.com/nooncall/owls/go/model/autocode"
6 | "github.com/nooncall/owls/go/model/common/request"
7 | )
8 |
9 | // 如果含有time.Time 请自行import time包
10 | type AutoCodeExampleSearch struct {
11 | autocode.AutoCodeExample
12 | request.PageInfo
13 | }
14 |
--------------------------------------------------------------------------------
/go/model/common/request/common.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | // PageInfo Paging common input parameter structure
4 | type PageInfo struct {
5 | Page int `json:"page" form:"page"` // 页码
6 | PageSize int `json:"pageSize" form:"pageSize"` // 每页大小
7 | }
8 |
9 | type SortPageInfo struct {
10 | PageInfo
11 | OrderKey string `json:"orderKey"` // 排序
12 | Key string `json:"key"`
13 | Desc bool `json:"desc"` // 排序方式:升序false(默认)|降序true
14 | Operator string `json:"operator"`
15 | Type string `json:"type"`
16 | }
17 |
18 | // GetById Find by id structure
19 | type GetById struct {
20 | ID int `json:"id" form:"id"` // 主键ID
21 | }
22 |
23 | func (r *GetById) Uint() uint {
24 | return uint(r.ID)
25 | }
26 |
27 | type IdsReq struct {
28 | Ids []int `json:"ids" form:"ids"`
29 | }
30 |
31 | // GetAuthorityId Get role by id structure
32 | type GetAuthorityId struct {
33 | AuthorityId string `json:"authorityId" form:"authorityId"` // 角色ID
34 | }
35 |
36 | type Empty struct{}
37 |
--------------------------------------------------------------------------------
/go/model/common/response/common.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type PageResult struct {
4 | List interface{} `json:"list"`
5 | Total int64 `json:"total"`
6 | Page int `json:"page"`
7 | PageSize int `json:"pageSize"`
8 | }
9 |
--------------------------------------------------------------------------------
/go/model/common/response/response.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type Response struct {
10 | Code int `json:"code"`
11 | Data interface{} `json:"data"`
12 | Msg string `json:"msg"`
13 | }
14 |
15 | const (
16 | ERROR = 7
17 | SUCCESS = 0
18 | )
19 |
20 | func Result(code int, data interface{}, msg string, c *gin.Context) {
21 | // 开始时间
22 | c.JSON(http.StatusOK, Response{
23 | code,
24 | data,
25 | msg,
26 | })
27 | }
28 |
29 | func Ok(c *gin.Context) {
30 | Result(SUCCESS, map[string]interface{}{}, "操作成功", c)
31 | }
32 |
33 | func OkWithMessage(message string, c *gin.Context) {
34 | Result(SUCCESS, map[string]interface{}{}, message, c)
35 | }
36 |
37 | func OkWithData(data interface{}, c *gin.Context) {
38 | Result(SUCCESS, data, "操作成功", c)
39 | }
40 |
41 | func OkWithDetailed(data interface{}, message string, c *gin.Context) {
42 | Result(SUCCESS, data, message, c)
43 | }
44 |
45 | func Fail(c *gin.Context) {
46 | Result(ERROR, map[string]interface{}{}, "操作失败", c)
47 | }
48 |
49 | func FailWithMessage(message string, c *gin.Context) {
50 | Result(ERROR, map[string]interface{}{}, message, c)
51 | }
52 |
53 | func FailWithDetailed(data interface{}, message string, c *gin.Context) {
54 | Result(ERROR, data, message, c)
55 | }
56 |
--------------------------------------------------------------------------------
/go/model/example/exa_breakpoint_continue.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | )
6 |
7 | // file struct, 文件结构体
8 | type ExaFile struct {
9 | global.GVA_MODEL
10 | FileName string
11 | FileMd5 string
12 | FilePath string
13 | ExaFileChunk []ExaFileChunk
14 | ChunkTotal int
15 | IsFinish bool
16 | }
17 |
18 | // file chunk struct, 切片结构体
19 | type ExaFileChunk struct {
20 | global.GVA_MODEL
21 | ExaFileID uint
22 | FileChunkNumber int
23 | FileChunkPath string
24 | }
25 |
--------------------------------------------------------------------------------
/go/model/example/exa_customer.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | "github.com/nooncall/owls/go/model/system"
6 | )
7 |
8 | type ExaCustomer struct {
9 | global.GVA_MODEL
10 | CustomerName string `json:"customerName" form:"customerName" gorm:"comment:客户名"` // 客户名
11 | CustomerPhoneData string `json:"customerPhoneData" form:"customerPhoneData" gorm:"comment:客户手机号"` // 客户手机号
12 | SysUserID uint `json:"sysUserId" form:"sysUserId" gorm:"comment:管理ID"` // 管理ID
13 | SysUserAuthorityID string `json:"sysUserAuthorityID" form:"sysUserAuthorityID" gorm:"comment:管理角色ID"` // 管理角色ID
14 | SysUser system.SysUser `json:"sysUser" form:"sysUser" gorm:"comment:管理详情"` // 管理详情
15 | }
16 |
--------------------------------------------------------------------------------
/go/model/example/exa_excel.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import "github.com/nooncall/owls/go/model/system"
4 |
5 | type ExcelInfo struct {
6 | FileName string `json:"fileName"` // 文件名
7 | InfoList []system.SysBaseMenu `json:"infoList"`
8 | }
9 |
--------------------------------------------------------------------------------
/go/model/example/exa_file_upload_download.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | )
6 |
7 | type ExaFileUploadAndDownload struct {
8 | global.GVA_MODEL
9 | Name string `json:"name" gorm:"comment:文件名"` // 文件名
10 | Url string `json:"url" gorm:"comment:文件地址"` // 文件地址
11 | Tag string `json:"tag" gorm:"comment:文件标签"` // 文件标签
12 | Key string `json:"key" gorm:"comment:编号"` // 编号
13 | }
14 |
--------------------------------------------------------------------------------
/go/model/example/response/exa_breakpoint_continue.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/nooncall/owls/go/model/example"
4 |
5 | type FilePathResponse struct {
6 | FilePath string `json:"filePath"`
7 | }
8 |
9 | type FileResponse struct {
10 | File example.ExaFile `json:"file"`
11 | }
12 |
--------------------------------------------------------------------------------
/go/model/example/response/exa_customer.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/nooncall/owls/go/model/example"
4 |
5 | type ExaCustomerResponse struct {
6 | Customer example.ExaCustomer `json:"customer"`
7 | }
8 |
--------------------------------------------------------------------------------
/go/model/example/response/exa_file_upload_download.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/nooncall/owls/go/model/example"
4 |
5 | type ExaFileResponse struct {
6 | File example.ExaFileUploadAndDownload `json:"file"`
7 | }
8 |
--------------------------------------------------------------------------------
/go/model/system/request/jwt.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/golang-jwt/jwt/v4"
5 | uuid "github.com/satori/go.uuid"
6 | )
7 |
8 | // Custom claims structure
9 | type CustomClaims struct {
10 | BaseClaims
11 | BufferTime int64
12 | jwt.StandardClaims
13 | }
14 |
15 | type BaseClaims struct {
16 | UUID uuid.UUID
17 | ID uint
18 | Username string
19 | NickName string
20 | AuthorityId string
21 | }
22 |
--------------------------------------------------------------------------------
/go/model/system/request/sys_api.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/nooncall/owls/go/model/common/request"
5 | "github.com/nooncall/owls/go/model/system"
6 | )
7 |
8 | // api分页条件查询及排序结构体
9 | type SearchApiParams struct {
10 | system.SysApi
11 | request.PageInfo
12 | OrderKey string `json:"orderKey"` // 排序
13 | Desc bool `json:"desc"` // 排序方式:升序false(默认)|降序true
14 | }
15 |
--------------------------------------------------------------------------------
/go/model/system/request/sys_authority_btn.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | type SysAuthorityBtnReq struct {
4 | MenuID uint `json:"menuID"`
5 | AuthorityId string `json:"authorityId"`
6 | Selected []uint `json:"selected"`
7 | }
8 |
--------------------------------------------------------------------------------
/go/model/system/request/sys_auto_history.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import "github.com/nooncall/owls/go/model/common/request"
4 |
5 | type SysAutoHistory struct {
6 | request.PageInfo
7 | }
8 |
--------------------------------------------------------------------------------
/go/model/system/request/sys_casbin.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | // Casbin info structure
4 | type CasbinInfo struct {
5 | Path string `json:"path"` // 路径
6 | Method string `json:"method"` // 方法
7 | }
8 |
9 | // Casbin structure for input parameters
10 | type CasbinInReceive struct {
11 | AuthorityId string `json:"authorityId"` // 权限id
12 | CasbinInfos []CasbinInfo `json:"casbinInfos"`
13 | }
14 |
15 | func DefaultCasbin() []CasbinInfo {
16 | return []CasbinInfo{
17 | {Path: "/menu/getMenu", Method: "POST"},
18 | {Path: "/jwt/jsonInBlacklist", Method: "POST"},
19 | {Path: "/base/login", Method: "POST"},
20 | {Path: "/user/admin_register", Method: "POST"},
21 | {Path: "/user/changePassword", Method: "POST"},
22 | {Path: "/user/setUserAuthority", Method: "POST"},
23 | {Path: "/user/setUserInfo", Method: "PUT"},
24 | {Path: "/user/getUserInfo", Method: "GET"},
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/go/model/system/request/sys_dictionary.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/nooncall/owls/go/model/common/request"
5 | "github.com/nooncall/owls/go/model/system"
6 | )
7 |
8 | type SysDictionarySearch struct {
9 | system.SysDictionary
10 | request.PageInfo
11 | }
12 |
--------------------------------------------------------------------------------
/go/model/system/request/sys_dictionary_detail.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/nooncall/owls/go/model/common/request"
5 | "github.com/nooncall/owls/go/model/system"
6 | )
7 |
8 | type SysDictionaryDetailSearch struct {
9 | system.SysDictionaryDetail
10 | request.PageInfo
11 | }
12 |
--------------------------------------------------------------------------------
/go/model/system/request/sys_menu.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | "github.com/nooncall/owls/go/model/system"
6 | )
7 |
8 | // Add menu authority info structure
9 | type AddMenuAuthorityInfo struct {
10 | Menus []system.SysBaseMenu `json:"menus"`
11 | AuthorityId string `json:"authorityId"` // 角色ID
12 | }
13 |
14 | func DefaultMenu() []system.SysBaseMenu {
15 | return []system.SysBaseMenu{{
16 | GVA_MODEL: global.GVA_MODEL{ID: 1},
17 | ParentId: "0",
18 | Path: "dashboard",
19 | Name: "dashboard",
20 | Component: "view/dashboard/index.vue",
21 | Sort: 1,
22 | Meta: system.Meta{
23 | Title: "仪表盘",
24 | Icon: "setting",
25 | },
26 | }}
27 | }
28 |
--------------------------------------------------------------------------------
/go/model/system/request/sys_operation_record.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/nooncall/owls/go/model/common/request"
5 | "github.com/nooncall/owls/go/model/system"
6 | )
7 |
8 | type SysOperationRecordSearch struct {
9 | system.SysOperationRecord
10 | request.PageInfo
11 | }
12 |
--------------------------------------------------------------------------------
/go/model/system/response/sys_api.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/nooncall/owls/go/model/system"
4 |
5 | type SysAPIResponse struct {
6 | Api system.SysApi `json:"api"`
7 | }
8 |
9 | type SysAPIListResponse struct {
10 | Apis []system.SysApi `json:"apis"`
11 | }
12 |
--------------------------------------------------------------------------------
/go/model/system/response/sys_authority.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/nooncall/owls/go/model/system"
4 |
5 | type SysAuthorityResponse struct {
6 | Authority system.SysAuthority `json:"authority"`
7 | }
8 |
9 | type SysAuthorityCopyResponse struct {
10 | Authority system.SysAuthority `json:"authority"`
11 | OldAuthorityId string `json:"oldAuthorityId"` // 旧角色ID
12 | }
13 |
--------------------------------------------------------------------------------
/go/model/system/response/sys_authority_btn.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type SysAuthorityBtnRes struct {
4 | Selected []uint `json:"selected"`
5 | }
6 |
--------------------------------------------------------------------------------
/go/model/system/response/sys_auto_code.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type Db struct {
4 | Database string `json:"database" gorm:"column:database"`
5 | }
6 |
7 | type Table struct {
8 | TableName string `json:"tableName" gorm:"column:table_name"`
9 | }
10 |
11 | type Column struct {
12 | DataType string `json:"dataType" gorm:"column:data_type"`
13 | ColumnName string `json:"columnName" gorm:"column:column_name"`
14 | DataTypeLong string `json:"dataTypeLong" gorm:"column:data_type_long"`
15 | ColumnComment string `json:"columnComment" gorm:"column:column_comment"`
16 | }
17 |
--------------------------------------------------------------------------------
/go/model/system/response/sys_auto_code_history.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "time"
4 |
5 | type AutoCodeHistory struct {
6 | ID uint `json:"ID" gorm:"column:id"`
7 | CreatedAt time.Time `json:"CreatedAt" gorm:"column:created_at"`
8 | UpdatedAt time.Time `json:"UpdatedAt" gorm:"column:updated_at"`
9 | TableName string `json:"tableName" gorm:"column:table_name"`
10 | StructName string `json:"structName" gorm:"column:struct_name"`
11 | StructCNName string `json:"structCNName" gorm:"column:struct_cn_name"`
12 | Flag int `json:"flag" gorm:"column:flag"`
13 | }
14 |
--------------------------------------------------------------------------------
/go/model/system/response/sys_captcha.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type SysCaptchaResponse struct {
4 | CaptchaId string `json:"captchaId"`
5 | PicPath string `json:"picPath"`
6 | CaptchaLength int `json:"captchaLength""`
7 | }
8 |
--------------------------------------------------------------------------------
/go/model/system/response/sys_casbin.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import (
4 | "github.com/nooncall/owls/go/model/system/request"
5 | )
6 |
7 | type PolicyPathResponse struct {
8 | Paths []request.CasbinInfo `json:"paths"`
9 | }
10 |
--------------------------------------------------------------------------------
/go/model/system/response/sys_menu.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/nooncall/owls/go/model/system"
4 |
5 | type SysMenusResponse struct {
6 | Menus []system.SysMenu `json:"menus"`
7 | }
8 |
9 | type SysBaseMenusResponse struct {
10 | Menus []system.SysBaseMenu `json:"menus"`
11 | }
12 |
13 | type SysBaseMenuResponse struct {
14 | Menu system.SysBaseMenu `json:"menu"`
15 | }
16 |
--------------------------------------------------------------------------------
/go/model/system/response/sys_system.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/nooncall/owls/go/config"
4 |
5 | type SysConfigResponse struct {
6 | Config config.Server `json:"config"`
7 | }
8 |
--------------------------------------------------------------------------------
/go/model/system/response/sys_user.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import (
4 | "github.com/nooncall/owls/go/model/system"
5 | )
6 |
7 | type SysUserResponse struct {
8 | User system.SysUser `json:"user"`
9 | }
10 |
11 | type LoginResponse struct {
12 | User system.SysUser `json:"user"`
13 | Token string `json:"token"`
14 | ExpiresAt int64 `json:"expiresAt"`
15 | }
16 |
--------------------------------------------------------------------------------
/go/model/system/sys_api.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | )
6 |
7 | type SysApi struct {
8 | global.GVA_MODEL
9 | Path string `json:"path" gorm:"comment:api路径"` // api路径
10 | Description string `json:"description" gorm:"comment:api中文描述"` // api中文描述
11 | ApiGroup string `json:"apiGroup" gorm:"comment:api组"` // api组
12 | Method string `json:"method" gorm:"default:POST;comment:方法"` // 方法:创建POST(默认)|查看GET|更新PUT|删除DELETE
13 | }
14 |
--------------------------------------------------------------------------------
/go/model/system/sys_authority.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type SysAuthority struct {
8 | CreatedAt time.Time // 创建时间
9 | UpdatedAt time.Time // 更新时间
10 | DeletedAt *time.Time `sql:"index"`
11 | AuthorityId string `json:"authorityId" gorm:"not null;unique;primary_key;comment:角色ID;size:90"` // 角色ID
12 | AuthorityName string `json:"authorityName" gorm:"comment:角色名"` // 角色名
13 | ParentId string `json:"parentId" gorm:"comment:父角色ID"` // 父角色ID
14 | DataAuthorityId []SysAuthority `json:"dataAuthorityId" gorm:"many2many:sys_data_authority_id"`
15 | Children []SysAuthority `json:"children" gorm:"-"`
16 | SysBaseMenus []SysBaseMenu `json:"menus" gorm:"many2many:sys_authority_menus;"`
17 | Users []SysUser `json:"-" gorm:"many2many:sys_user_authority;"`
18 | DefaultRouter string `json:"defaultRouter" gorm:"comment:默认菜单;default:dashboard"` // 默认菜单(默认dashboard)
19 | }
20 |
--------------------------------------------------------------------------------
/go/model/system/sys_authority_btn.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | type SysAuthorityBtn struct {
4 | AuthorityId string `gorm:"comment:角色ID"`
5 | SysMenuID uint `gorm:"comment:菜单ID"`
6 | SysBaseMenuBtnID uint `gorm:"comment:菜单按钮ID"`
7 | SysBaseMenuBtn SysBaseMenuBtn ` gorm:"comment:按钮详情"`
8 | }
9 |
--------------------------------------------------------------------------------
/go/model/system/sys_authority_menu.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | type SysMenu struct {
4 | SysBaseMenu
5 | MenuId string `json:"menuId" gorm:"comment:菜单ID"`
6 | AuthorityId string `json:"-" gorm:"comment:角色ID"`
7 | Children []SysMenu `json:"children" gorm:"-"`
8 | Parameters []SysBaseMenuParameter `json:"parameters" gorm:"foreignKey:SysBaseMenuID;references:MenuId"`
9 | Btns map[string]string `json:"btns" gorm:"-"`
10 | }
11 |
12 | func (s SysMenu) TableName() string {
13 | return "authority_menu"
14 | }
15 |
--------------------------------------------------------------------------------
/go/model/system/sys_dictionary.go:
--------------------------------------------------------------------------------
1 | // 自动生成模板SysDictionary
2 | package system
3 |
4 | import (
5 | "github.com/nooncall/owls/go/global"
6 | )
7 |
8 | // 如果含有time.Time 请自行import time包
9 | type SysDictionary struct {
10 | global.GVA_MODEL
11 | Name string `json:"name" form:"name" gorm:"column:name;comment:字典名(中)"` // 字典名(中)
12 | Type string `json:"type" form:"type" gorm:"column:type;comment:字典名(英)"` // 字典名(英)
13 | Status *bool `json:"status" form:"status" gorm:"column:status;comment:状态"` // 状态
14 | Desc string `json:"desc" form:"desc" gorm:"column:desc;comment:描述"` // 描述
15 | SysDictionaryDetails []SysDictionaryDetail `json:"sysDictionaryDetails" form:"sysDictionaryDetails"`
16 | }
17 |
--------------------------------------------------------------------------------
/go/model/system/sys_dictionary_detail.go:
--------------------------------------------------------------------------------
1 | // 自动生成模板SysDictionaryDetail
2 | package system
3 |
4 | import (
5 | "github.com/nooncall/owls/go/global"
6 | )
7 |
8 | // 如果含有time.Time 请自行import time包
9 | type SysDictionaryDetail struct {
10 | global.GVA_MODEL
11 | Label string `json:"label" form:"label" gorm:"column:label;comment:展示值"` // 展示值
12 | Value int `json:"value" form:"value" gorm:"column:value;comment:字典值"` // 字典值
13 | Status *bool `json:"status" form:"status" gorm:"column:status;comment:启用状态"` // 启用状态
14 | Sort int `json:"sort" form:"sort" gorm:"column:sort;comment:排序标记"` // 排序标记
15 | SysDictionaryID int `json:"sysDictionaryID" form:"sysDictionaryID" gorm:"column:sys_dictionary_id;comment:关联标记"` // 关联标记
16 | }
17 |
--------------------------------------------------------------------------------
/go/model/system/sys_jwt_blacklist.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | )
6 |
7 | type JwtBlacklist struct {
8 | global.GVA_MODEL
9 | Jwt string `gorm:"type:text;comment:jwt"`
10 | }
11 |
--------------------------------------------------------------------------------
/go/model/system/sys_menu_btn.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import "github.com/nooncall/owls/go/global"
4 |
5 | type SysBaseMenuBtn struct {
6 | global.GVA_MODEL
7 | Name string `json:"name" gorm:"comment:按钮关键key"`
8 | Desc string `json:"desc" gorm:"按钮备注"`
9 | SysBaseMenuID uint `json:"sysBaseMenuID" gorm:"comment:菜单ID"`
10 | }
11 |
--------------------------------------------------------------------------------
/go/model/system/sys_system.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/nooncall/owls/go/config"
5 | )
6 |
7 | // 配置文件结构体
8 | type System struct {
9 | Config config.Server `json:"config"`
10 | }
11 |
--------------------------------------------------------------------------------
/go/model/system/sys_user_authority.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | type SysUseAuthority struct {
4 | SysUserId uint `gorm:"column:sys_user_id"`
5 | SysAuthorityAuthorityId string `gorm:"column:sys_authority_authority_id"`
6 | }
7 |
8 | func (s *SysUseAuthority) TableName() string {
9 | return "sys_user_authority"
10 | }
11 |
--------------------------------------------------------------------------------
/go/packfile/notUsePackFile.go:
--------------------------------------------------------------------------------
1 | //go:build !packfile
2 | // +build !packfile
3 |
4 | package packfile
5 |
--------------------------------------------------------------------------------
/go/packfile/usePackFile.go:
--------------------------------------------------------------------------------
1 | //go:build packfile
2 | // +build packfile
3 |
4 | package packfile
5 |
6 | import (
7 | "fmt"
8 | "io/ioutil"
9 | "os"
10 | "path/filepath"
11 | "strings"
12 | )
13 |
14 | //go:generate go-bindata -o=staticFile.go -pkg=packfile -tags=packfile ../resource/... ../config.yaml
15 |
16 | func writeFile(path string, data []byte) {
17 | // 如果文件夹不存在,预先创建文件夹
18 | if lastSeparator := strings.LastIndex(path, "/"); lastSeparator != -1 {
19 | dirPath := path[:lastSeparator]
20 | if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) {
21 | os.MkdirAll(dirPath, os.ModePerm)
22 | }
23 | }
24 |
25 | // 已存在的文件,不应该覆盖重写,可能在前端更改了配置文件等
26 | if _, err := os.Stat(path); os.IsNotExist(err) {
27 | if err2 := ioutil.WriteFile(path, data, os.ModePerm); err2 != nil {
28 | fmt.Printf("Write file failed: %s\n", path)
29 | }
30 | } else {
31 | fmt.Printf("File exist, skip: %s\n", path)
32 | }
33 | }
34 |
35 | func init() {
36 | for key := range _bindata {
37 | filePath, _ := filepath.Abs(strings.TrimPrefix(key, "."))
38 | data, err := Asset(key)
39 | if err != nil {
40 | // Asset was not found.
41 | fmt.Printf("Fail to find: %s\n", filePath)
42 | } else {
43 | writeFile(filePath, data)
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/go/plugin/email/api/enter.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | type ApiGroup struct {
4 | EmailApi
5 | }
6 |
7 | var ApiGroupApp = new(ApiGroup)
8 |
--------------------------------------------------------------------------------
/go/plugin/email/config/email.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Email struct {
4 | To string `mapstructure:"to" json:"to" yaml:"to"` // 收件人:多个以英文逗号分隔 例:a@qq.com b@qq.com 正式开发中请把此项目作为参数使用
5 | From string `mapstructure:"from" json:"from" yaml:"from"` // 发件人 你自己要发邮件的邮箱
6 | Host string `mapstructure:"host" json:"host" yaml:"host"` // 服务器地址 例如 smtp.qq.com 请前往QQ或者你要发邮件的邮箱查看其smtp协议
7 | Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥 用于登录的密钥 最好不要用邮箱密码 去邮箱smtp申请一个用于登录的密钥
8 | Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"` // 昵称 发件人昵称 通常为自己的邮箱
9 | Port int `mapstructure:"port" json:"port" yaml:"port"` // 端口 请前往QQ或者你要发邮件的邮箱查看其smtp协议 大多为 465
10 | IsSSL bool `mapstructure:"is-ssl" json:"isSSL" yaml:"is-ssl"` // 是否SSL 是否开启SSL
11 | }
12 |
--------------------------------------------------------------------------------
/go/plugin/email/global/gloabl.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | import "github.com/nooncall/owls/go/plugin/email/config"
4 |
5 | var GlobalConfig = new(config.Email)
6 |
--------------------------------------------------------------------------------
/go/plugin/email/main.go:
--------------------------------------------------------------------------------
1 | package email
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/nooncall/owls/go/plugin/email/global"
6 | "github.com/nooncall/owls/go/plugin/email/router"
7 | )
8 |
9 | type emailPlugin struct{}
10 |
11 | func CreateEmailPlug(To, From, Host, Secret, Nickname string, Port int, IsSSL bool) *emailPlugin {
12 | global.GlobalConfig.To = To
13 | global.GlobalConfig.From = From
14 | global.GlobalConfig.Host = Host
15 | global.GlobalConfig.Secret = Secret
16 | global.GlobalConfig.Nickname = Nickname
17 | global.GlobalConfig.Port = Port
18 | global.GlobalConfig.IsSSL = IsSSL
19 | return &emailPlugin{}
20 | }
21 |
22 | func (*emailPlugin) Register(group *gin.RouterGroup) {
23 | router.RouterGroupApp.InitEmailRouter(group)
24 | }
25 |
26 | func (*emailPlugin) RouterPath() string {
27 | return "email"
28 | }
29 |
--------------------------------------------------------------------------------
/go/plugin/email/model/response/email.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type Email struct {
4 | To string `json:"to"` // 邮件发送给谁
5 | Subject string `json:"subject"` // 邮件标题
6 | Body string `json:"body"` // 邮件内容
7 | }
8 |
--------------------------------------------------------------------------------
/go/plugin/email/router/enter.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | type RouterGroup struct {
4 | EmailRouter
5 | }
6 |
7 | var RouterGroupApp = new(RouterGroup)
8 |
--------------------------------------------------------------------------------
/go/plugin/email/router/sys_email.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/nooncall/owls/go/middleware"
6 | "github.com/nooncall/owls/go/plugin/email/api"
7 | )
8 |
9 | type EmailRouter struct{}
10 |
11 | func (s *EmailRouter) InitEmailRouter(Router *gin.RouterGroup) {
12 | emailRouter := Router.Use(middleware.OperationRecord())
13 | EmailApi := api.ApiGroupApp.EmailApi.EmailTest
14 | SendEmail := api.ApiGroupApp.EmailApi.SendEmail
15 | {
16 | emailRouter.POST("emailTest", EmailApi) // 发送测试邮件
17 | emailRouter.POST("sendEmail", SendEmail) // 发送邮件
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/go/plugin/email/service/enter.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | type ServiceGroup struct {
4 | EmailService
5 | }
6 |
7 | var ServiceGroupApp = new(ServiceGroup)
8 |
--------------------------------------------------------------------------------
/go/plugin/email/service/sys_email.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/nooncall/owls/go/plugin/email/utils"
5 | )
6 |
7 | type EmailService struct{}
8 |
9 | //@author: [maplepie](https://github.com/maplepie)
10 | //@function: EmailTest
11 | //@description: 发送邮件测试
12 | //@return: err error
13 |
14 | func (e *EmailService) EmailTest() (err error) {
15 | subject := "test"
16 | body := "test"
17 | err = utils.EmailTest(subject, body)
18 | return err
19 | }
20 |
21 | //@author: [maplepie](https://github.com/maplepie)
22 | //@function: EmailTest
23 | //@description: 发送邮件测试
24 | //@return: err error
25 | //@params to string 收件人
26 | //@params subject string 标题(主题)
27 | //@params body string 邮件内容
28 |
29 | func (e *EmailService) SendEmail(to, subject, body string) (err error) {
30 | err = utils.Email(to, subject, body)
31 | return err
32 | }
33 |
--------------------------------------------------------------------------------
/go/plugin/example_plugin/main.go:
--------------------------------------------------------------------------------
1 | package example_plugin
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | var ExamplePlugin = new(pluginExample)
8 |
9 | type pluginExample struct{}
10 |
11 | func (*pluginExample) Register(group *gin.RouterGroup) {
12 | //如需细分权限 可以在此处use中间件 gva项目包名已改为github模式
13 | //所以整个plugin可以直接独立到外层开启为新的项目 然后用包的形式导入也是可以完整运行的
14 | // 例:
15 | /*
16 | group.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler()).GET("hello", func(context *gin.Context) {
17 | context.JSON(200, "hello world")
18 | })
19 | */
20 | group.GET("hello", func(context *gin.Context) {
21 | context.JSON(200, "hello world")
22 | })
23 | }
24 |
25 | func (*pluginExample) RouterPath() string {
26 | return "group"
27 | }
28 |
--------------------------------------------------------------------------------
/go/resource/excel/ExcelExport.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/go/resource/excel/ExcelExport.xlsx
--------------------------------------------------------------------------------
/go/resource/excel/ExcelImport.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/go/resource/excel/ExcelImport.xlsx
--------------------------------------------------------------------------------
/go/resource/excel/ExcelTemplate.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/go/resource/excel/ExcelTemplate.xlsx
--------------------------------------------------------------------------------
/go/resource/page/css/parser-example.69e16e51.css:
--------------------------------------------------------------------------------
1 | .test-form[data-v-77b1aafa]{margin:15px auto;width:800px;padding:15px}
--------------------------------------------------------------------------------
/go/resource/page/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/go/resource/page/favicon.ico
--------------------------------------------------------------------------------
/go/resource/page/js/tinymce-example.5a756246.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["tinymce-example"],{a5aa:function(e,t,n){"use strict";n.r(t);var a=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[n("Tinymce",{attrs:{height:300,placeholder:"在这里输入文字"},model:{value:e.defaultValue,callback:function(t){e.defaultValue=t},expression:"defaultValue"}})],1)},c=[],u=n("31c6"),l={components:{Tinymce:u["a"]},props:{},data:function(){return{defaultValue:"配置文档参阅:http://tinymce.ax-z.cn
"}},computed:{},watch:{},created:function(){},mounted:function(){},methods:{}},o=l,i=n("5d22"),d=Object(i["a"])(o,a,c,!1,null,null,null);t["default"]=d.exports}}]);
--------------------------------------------------------------------------------
/go/resource/page/libs/monaco-editor/vs/base/browser/ui/codicons/codicon/codicon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/go/resource/page/libs/monaco-editor/vs/base/browser/ui/codicons/codicon/codicon.ttf
--------------------------------------------------------------------------------
/go/resource/page/libs/monaco-editor/vs/basic-languages/azcli/azcli.js:
--------------------------------------------------------------------------------
1 | /*!-----------------------------------------------------------------------------
2 | * Copyright (c) Microsoft Corporation. All rights reserved.
3 | * monaco-languages version: 2.3.0(57af10ae0184db4e0f7f9a92ff972629c39ccb53)
4 | * Released under the MIT license
5 | * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
6 | *-----------------------------------------------------------------------------*/
7 | define("vs/basic-languages/azcli/azcli",["require","exports"],(function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.language=t.conf=void 0,t.conf={comments:{lineComment:"#"}},t.language={defaultToken:"keyword",ignoreCase:!0,tokenPostfix:".azcli",str:/[^#\s]/,tokenizer:{root:[{include:"@comment"},[/\s-+@str*\s*/,{cases:{"@eos":{token:"key.identifier",next:"@popall"},"@default":{token:"key.identifier",next:"@type"}}}],[/^-+@str*\s*/,{cases:{"@eos":{token:"key.identifier",next:"@popall"},"@default":{token:"key.identifier",next:"@type"}}}]],type:[{include:"@comment"},[/-+@str*\s*/,{cases:{"@eos":{token:"key.identifier",next:"@popall"},"@default":"key.identifier"}}],[/@str+\s*/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}]],comment:[[/#.*$/,{cases:{"@eos":{token:"comment",next:"@popall"}}}]]}}}));
--------------------------------------------------------------------------------
/go/resource/rbac_model.conf:
--------------------------------------------------------------------------------
1 | [request_definition]
2 | r = sub, obj, act
3 |
4 | [policy_definition]
5 | p = sub, obj, act
6 |
7 | [role_definition]
8 | g = _, _
9 |
10 | [policy_effect]
11 | e = some(where (p.eft == allow))
12 |
13 | [matchers]
14 | m = r.sub == p.sub && keyMatch2(r.obj,p.obj) && r.act == p.act
15 |
--------------------------------------------------------------------------------
/go/resource/template/readme.txt.tpl:
--------------------------------------------------------------------------------
1 | 代码解压后把fe的api文件内容粘贴进前端api文件夹下并修改为自己想要的名字即可
2 |
3 | 后端代码解压后同理,放到自己想要的 mvc对应路径 并且到 initRouter中注册自动生成的路由 到registerTable中注册自动生成的model
4 |
5 | 项目github:"https://github.com/piexlmax/github.com/nooncall/owls/go"
6 |
7 | 希望大家给个star多多鼓励
8 |
--------------------------------------------------------------------------------
/go/resource/template/server/model.go.tpl:
--------------------------------------------------------------------------------
1 | // 自动生成模板{{.StructName}}
2 | package autocode
3 |
4 | import (
5 | "github.com/nooncall/owls/go/global"
6 | )
7 |
8 | // {{.StructName}} 结构体
9 | // 如果含有time.Time 请自行import time包
10 | type {{.StructName}} struct {
11 | global.GVA_MODEL {{- range .Fields}}
12 | {{- if ne .FieldType "string" }}
13 | {{.FieldName}} *{{.FieldType}} `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}"`
14 | {{- else }}
15 | {{.FieldName}} {{.FieldType}} `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}"`
16 | {{- end }} {{- end }}
17 | }
18 |
19 | {{ if .TableName }}
20 | // TableName {{.StructName}} 表名
21 | func ({{.StructName}}) TableName() string {
22 | return "{{.TableName}}"
23 | }
24 | {{ end }}
25 |
--------------------------------------------------------------------------------
/go/resource/template/server/request.go.tpl:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/nooncall/owls/go/model/autocode"
5 | "github.com/nooncall/owls/go/model/common/request"
6 | )
7 |
8 | type {{.StructName}}Search struct{
9 | autocode.{{.StructName}}
10 | request.PageInfo
11 | }
--------------------------------------------------------------------------------
/go/router/autocode/auto_code_example.go:
--------------------------------------------------------------------------------
1 | package autocode
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | type AutoCodeExampleRouter struct{}
10 |
11 | func (s *AutoCodeExampleRouter) InitSysAutoCodeExampleRouter(Router *gin.RouterGroup) {
12 | autoCodeExampleRouter := Router.Group("autoCodeExample").Use(middleware.OperationRecord())
13 | autoCodeExampleRouterWithoutRecord := Router.Group("autoCodeExample")
14 | autoCodeExampleApi := v1.ApiGroupApp.AutoCodeApiGroup.AutoCodeExampleApi
15 | {
16 | autoCodeExampleRouter.POST("createSysAutoCodeExample", autoCodeExampleApi.CreateAutoCodeExample) // 新建AutoCodeExample
17 | autoCodeExampleRouter.DELETE("deleteSysAutoCodeExample", autoCodeExampleApi.DeleteAutoCodeExample) // 删除AutoCodeExample
18 | autoCodeExampleRouter.PUT("updateSysAutoCodeExample", autoCodeExampleApi.UpdateAutoCodeExample) // 更新AutoCodeExample
19 | }
20 | {
21 | autoCodeExampleRouterWithoutRecord.GET("findSysAutoCodeExample", autoCodeExampleApi.FindAutoCodeExample) // 根据ID获取AutoCodeExample
22 | autoCodeExampleRouterWithoutRecord.GET("getSysAutoCodeExampleList", autoCodeExampleApi.GetAutoCodeExampleList) // 获取AutoCodeExample列表
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/go/router/autocode/enter.go:
--------------------------------------------------------------------------------
1 | package autocode
2 |
3 | type RouterGroup struct {
4 | // Code generated by github.com/nooncall/owls/go Begin; DO NOT EDIT.
5 | AutoCodeExampleRouter
6 | // Code generated by github.com/nooncall/owls/go End; DO NOT EDIT.
7 | }
8 |
--------------------------------------------------------------------------------
/go/router/enter.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/nooncall/owls/go/router/autocode"
5 | "github.com/nooncall/owls/go/router/example"
6 | "github.com/nooncall/owls/go/router/redis"
7 | "github.com/nooncall/owls/go/router/routers"
8 | "github.com/nooncall/owls/go/router/system"
9 | "github.com/nooncall/owls/go/router/tidb_or_mysql"
10 | )
11 |
12 | type RouterGroup struct {
13 | System system.RouterGroup
14 | Example example.RouterGroup
15 | Autocode autocode.RouterGroup
16 | Redis redis.RouterGroup
17 | TidbOrMysql tidb_or_mysql.RouterGroup
18 | Routers routers.Routers
19 | }
20 |
21 | var RouterGroupApp = new(RouterGroup)
22 |
--------------------------------------------------------------------------------
/go/router/example/enter.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | type RouterGroup struct {
4 | ExcelRouter
5 | CustomerRouter
6 | }
7 |
--------------------------------------------------------------------------------
/go/router/example/exa_customer.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | type CustomerRouter struct{}
10 |
11 | func (e *CustomerRouter) InitCustomerRouter(Router *gin.RouterGroup) {
12 | customerRouter := Router.Group("customer").Use(middleware.OperationRecord())
13 | customerRouterWithoutRecord := Router.Group("customer")
14 | exaCustomerApi := v1.ApiGroupApp.ExampleApiGroup.CustomerApi
15 | {
16 | customerRouter.POST("customer", exaCustomerApi.CreateExaCustomer) // 创建客户
17 | customerRouter.PUT("customer", exaCustomerApi.UpdateExaCustomer) // 更新客户
18 | customerRouter.DELETE("customer", exaCustomerApi.DeleteExaCustomer) // 删除客户
19 | }
20 | {
21 | customerRouterWithoutRecord.GET("customer", exaCustomerApi.GetExaCustomer) // 获取单一客户信息
22 | customerRouterWithoutRecord.GET("customerList", exaCustomerApi.GetExaCustomerList) // 获取客户列表
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/go/router/example/exa_excel.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | )
7 |
8 | type ExcelRouter struct{}
9 |
10 | func (e *ExcelRouter) InitExcelRouter(Router *gin.RouterGroup) {
11 | excelRouter := Router.Group("excel")
12 | exaExcelApi := v1.ApiGroupApp.ExampleApiGroup.ExcelApi
13 | {
14 | excelRouter.POST("importExcel", exaExcelApi.ImportExcel) // 导入Excel
15 | excelRouter.GET("loadExcel", exaExcelApi.LoadExcel) // 加载Excel数据
16 | excelRouter.POST("exportExcel", exaExcelApi.ExportExcel) // 导出Excel
17 | excelRouter.GET("downloadTemplate", exaExcelApi.DownloadTemplate) // 下载模板文件
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/go/router/redis/enter.go:
--------------------------------------------------------------------------------
1 | package redis
2 |
3 | type RouterGroup struct {
4 | RedisRouter
5 | }
6 |
--------------------------------------------------------------------------------
/go/router/redis/redis.go:
--------------------------------------------------------------------------------
1 | package redis
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | type RedisRouter struct{}
10 |
11 | func (s *RedisRouter) InitApiRouter(Router *gin.RouterGroup) {
12 | apiRouter := Router.Group("redis").Use(middleware.OperationRecord())
13 | apiRouterWithoutRecord := Router.Group("redis")
14 |
15 | {
16 | readApi := v1.ApiGroupApp.Redis.ReadApi
17 |
18 | apiRouter.POST("/read", readApi.ReadData)
19 | }
20 |
21 | // task 接口复用,task包含写接口
22 |
23 | // admin, cluster 接口复用
24 | {
25 | ruleApi := v1.ApiGroupApp.Redis.ReadApi
26 |
27 | apiRouterWithoutRecord.GET("/rule/list", ruleApi.ListRule)
28 | apiRouter.PUT("/rule/status", ruleApi.UpdateRuleStatus)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/go/router/routers/auth.go:
--------------------------------------------------------------------------------
1 | package routers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | func (s *Routers) InitAuthRouter(Router *gin.RouterGroup) {
10 | recordRouter := Router.Use(middleware.OperationRecord())
11 |
12 | {
13 | auth := v1.ApiGroupApp.Auth
14 |
15 | recordRouter.POST("/auth", auth.AddAuth)
16 | recordRouter.DELETE("/auth", auth.DelAuth)
17 | Router.POST("/auth/list", auth.ListAuth)
18 | Router.POST("/data-type/list", auth.ListDataType)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/go/router/routers/enter.go:
--------------------------------------------------------------------------------
1 | // all follow routers will be added here
2 |
3 | package routers
4 |
5 | import "github.com/gin-gonic/gin"
6 |
7 | type Routers struct{}
8 |
9 | func (s *Routers) InitApiRouter(Router *gin.RouterGroup) {
10 | s.InitAuthRouter(Router)
11 | s.InitTaskRouter(Router)
12 | }
13 |
14 | var Router Routers
15 |
--------------------------------------------------------------------------------
/go/router/routers/task.go:
--------------------------------------------------------------------------------
1 | package routers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | func (s *Routers) InitTaskRouter(Router *gin.RouterGroup) {
10 | recordRouter := Router.Use(middleware.OperationRecord())
11 |
12 | {
13 | taskApi := v1.ApiGroupApp.Task
14 |
15 | recordRouter.POST("/task", taskApi.AddTask)
16 | recordRouter.PUT("/task", taskApi.UpdateTask)
17 | Router.GET("/task", taskApi.GetTask)
18 | Router.POST("/task/list", taskApi.ListTask)
19 | Router.POST("/task/review", taskApi.ListReviewTask)
20 | Router.POST("/task/history", taskApi.ListHistoryTask)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/go/router/system/enter.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | type RouterGroup struct {
4 | ApiRouter
5 | JwtRouter
6 | SysRouter
7 | BaseRouter
8 | InitRouter
9 | MenuRouter
10 | UserRouter
11 | CasbinRouter
12 | AutoCodeRouter
13 | AuthorityRouter
14 | DictionaryRouter
15 | OperationRecordRouter
16 | DictionaryDetailRouter
17 | AuthorityBtnRouter
18 | }
19 |
--------------------------------------------------------------------------------
/go/router/system/sys_api.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | type ApiRouter struct{}
10 |
11 | func (s *ApiRouter) InitApiRouter(Router *gin.RouterGroup) {
12 | apiRouter := Router.Group("api").Use(middleware.OperationRecord())
13 | apiRouterWithoutRecord := Router.Group("api")
14 | apiRouterApi := v1.ApiGroupApp.SystemApiGroup.SystemApiApi
15 | {
16 | apiRouter.POST("createApi", apiRouterApi.CreateApi) // 创建Api
17 | apiRouter.POST("deleteApi", apiRouterApi.DeleteApi) // 删除Api
18 | apiRouter.POST("getApiById", apiRouterApi.GetApiById) // 获取单条Api消息
19 | apiRouter.POST("updateApi", apiRouterApi.UpdateApi) // 更新api
20 | apiRouter.DELETE("deleteApisByIds", apiRouterApi.DeleteApisByIds) // 删除选中api
21 | }
22 | {
23 | apiRouterWithoutRecord.POST("getAllApis", apiRouterApi.GetAllApis) // 获取所有api
24 | apiRouterWithoutRecord.POST("getApiList", apiRouterApi.GetApiList) // 获取Api列表
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/go/router/system/sys_authority.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | type AuthorityRouter struct{}
10 |
11 | func (s *AuthorityRouter) InitAuthorityRouter(Router *gin.RouterGroup) {
12 | authorityRouter := Router.Group("authority").Use(middleware.OperationRecord())
13 | authorityRouterWithoutRecord := Router.Group("authority")
14 | authorityApi := v1.ApiGroupApp.SystemApiGroup.AuthorityApi
15 | {
16 | authorityRouter.POST("createAuthority", authorityApi.CreateAuthority) // 创建角色
17 | authorityRouter.POST("deleteAuthority", authorityApi.DeleteAuthority) // 删除角色
18 | authorityRouter.PUT("updateAuthority", authorityApi.UpdateAuthority) // 更新角色
19 | authorityRouter.POST("copyAuthority", authorityApi.CopyAuthority) // 拷贝角色
20 | authorityRouter.POST("setDataAuthority", authorityApi.SetDataAuthority) // 设置角色资源权限
21 | }
22 | {
23 | authorityRouterWithoutRecord.POST("getAuthorityList", authorityApi.GetAuthorityList) // 获取角色列表
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/go/router/system/sys_authority_btn.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | )
7 |
8 | type AuthorityBtnRouter struct{}
9 |
10 | func (s *AuthorityBtnRouter) InitAuthorityBtnRouterRouter(Router *gin.RouterGroup) {
11 | //authorityRouter := Router.Group("authorityBtn").Use(middleware.OperationRecord())
12 | authorityRouterWithoutRecord := Router.Group("authorityBtn")
13 | authorityBtnApi := v1.ApiGroupApp.SystemApiGroup.AuthorityBtnApi
14 | {
15 | authorityRouterWithoutRecord.POST("getAuthorityBtn", authorityBtnApi.GetAuthorityBtn)
16 | authorityRouterWithoutRecord.POST("setAuthorityBtn", authorityBtnApi.SetAuthorityBtn)
17 | authorityRouterWithoutRecord.POST("canRemoveAuthorityBtn", authorityBtnApi.CanRemoveAuthorityBtn)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/go/router/system/sys_auto_code.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | )
7 |
8 | type AutoCodeRouter struct{}
9 |
10 | func (s *AutoCodeRouter) InitAutoCodeRouter(Router *gin.RouterGroup) {
11 | autoCodeRouter := Router.Group("autoCode")
12 | autoCodeApi := v1.ApiGroupApp.SystemApiGroup.AutoCodeApi
13 | {
14 | autoCodeRouter.GET("getDB", autoCodeApi.GetDB) // 获取数据库
15 | autoCodeRouter.GET("getTables", autoCodeApi.GetTables) // 获取对应数据库的表
16 | autoCodeRouter.GET("getColumn", autoCodeApi.GetColumn) // 获取指定表所有字段信息
17 | autoCodeRouter.POST("preview", autoCodeApi.PreviewTemp) // 获取自动创建代码预览
18 | autoCodeRouter.POST("createTemp", autoCodeApi.CreateTemp) // 创建自动化代码
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/go/router/system/sys_auto_code_history.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | )
7 |
8 | type AutoCodeHistoryRouter struct{}
9 |
10 | func (s *AutoCodeRouter) InitAutoCodeHistoryRouter(Router *gin.RouterGroup) {
11 | autoCodeHistoryRouter := Router.Group("autoCode")
12 | autoCodeHistoryApi := v1.ApiGroupApp.SystemApiGroup.AutoCodeHistoryApi
13 | {
14 | autoCodeHistoryRouter.POST("getMeta", autoCodeHistoryApi.First) // 根据id获取meta信息
15 | autoCodeHistoryRouter.POST("rollback", autoCodeHistoryApi.RollBack) // 回滚
16 | autoCodeHistoryRouter.POST("delSysHistory", autoCodeHistoryApi.Delete) // 删除回滚记录
17 | autoCodeHistoryRouter.POST("getSysHistory", autoCodeHistoryApi.GetList) // 获取回滚记录分页
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/go/router/system/sys_base.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | )
7 |
8 | type BaseRouter struct{}
9 |
10 | func (s *BaseRouter) InitBaseRouter(Router *gin.RouterGroup) (R gin.IRoutes) {
11 | baseRouter := Router.Group("base")
12 | baseApi := v1.ApiGroupApp.SystemApiGroup.BaseApi
13 | {
14 | baseRouter.GET("login/model", baseApi.LoginModel)
15 | baseRouter.POST("register", baseApi.Register)
16 | baseRouter.POST("login", baseApi.Login)
17 | baseRouter.POST("captcha", baseApi.Captcha)
18 | }
19 | return baseRouter
20 | }
21 |
--------------------------------------------------------------------------------
/go/router/system/sys_casbin.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | type CasbinRouter struct{}
10 |
11 | func (s *CasbinRouter) InitCasbinRouter(Router *gin.RouterGroup) {
12 | casbinRouter := Router.Group("casbin").Use(middleware.OperationRecord())
13 | casbinRouterWithoutRecord := Router.Group("casbin")
14 | casbinApi := v1.ApiGroupApp.SystemApiGroup.CasbinApi
15 | {
16 | casbinRouter.POST("updateCasbin", casbinApi.UpdateCasbin)
17 | }
18 | {
19 | casbinRouterWithoutRecord.POST("getPolicyPathByAuthorityId", casbinApi.GetPolicyPathByAuthorityId)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/go/router/system/sys_dictionary.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | type DictionaryRouter struct{}
10 |
11 | func (s *DictionaryRouter) InitSysDictionaryRouter(Router *gin.RouterGroup) {
12 | sysDictionaryRouter := Router.Group("sysDictionary").Use(middleware.OperationRecord())
13 | sysDictionaryRouterWithoutRecord := Router.Group("sysDictionary")
14 | sysDictionaryApi := v1.ApiGroupApp.SystemApiGroup.DictionaryApi
15 | {
16 | sysDictionaryRouter.POST("createSysDictionary", sysDictionaryApi.CreateSysDictionary) // 新建SysDictionary
17 | sysDictionaryRouter.DELETE("deleteSysDictionary", sysDictionaryApi.DeleteSysDictionary) // 删除SysDictionary
18 | sysDictionaryRouter.PUT("updateSysDictionary", sysDictionaryApi.UpdateSysDictionary) // 更新SysDictionary
19 | }
20 | {
21 | sysDictionaryRouterWithoutRecord.GET("findSysDictionary", sysDictionaryApi.FindSysDictionary) // 根据ID获取SysDictionary
22 | sysDictionaryRouterWithoutRecord.GET("getSysDictionaryList", sysDictionaryApi.GetSysDictionaryList) // 获取SysDictionary列表
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/go/router/system/sys_dictionary_detail.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | type DictionaryDetailRouter struct{}
10 |
11 | func (s *DictionaryDetailRouter) InitSysDictionaryDetailRouter(Router *gin.RouterGroup) {
12 | dictionaryDetailRouter := Router.Group("sysDictionaryDetail").Use(middleware.OperationRecord())
13 | dictionaryDetailRouterWithoutRecord := Router.Group("sysDictionaryDetail")
14 | sysDictionaryDetailApi := v1.ApiGroupApp.SystemApiGroup.DictionaryDetailApi
15 | {
16 | dictionaryDetailRouter.POST("createSysDictionaryDetail", sysDictionaryDetailApi.CreateSysDictionaryDetail) // 新建SysDictionaryDetail
17 | dictionaryDetailRouter.DELETE("deleteSysDictionaryDetail", sysDictionaryDetailApi.DeleteSysDictionaryDetail) // 删除SysDictionaryDetail
18 | dictionaryDetailRouter.PUT("updateSysDictionaryDetail", sysDictionaryDetailApi.UpdateSysDictionaryDetail) // 更新SysDictionaryDetail
19 | }
20 | {
21 | dictionaryDetailRouterWithoutRecord.GET("findSysDictionaryDetail", sysDictionaryDetailApi.FindSysDictionaryDetail) // 根据ID获取SysDictionaryDetail
22 | dictionaryDetailRouterWithoutRecord.GET("getSysDictionaryDetailList", sysDictionaryDetailApi.GetSysDictionaryDetailList) // 获取SysDictionaryDetail列表
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/go/router/system/sys_initdb.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | )
7 |
8 | type InitRouter struct{}
9 |
10 | func (s *InitRouter) InitInitRouter(Router *gin.RouterGroup) {
11 | initRouter := Router.Group("init")
12 | dbApi := v1.ApiGroupApp.SystemApiGroup.DBApi
13 | {
14 | initRouter.POST("initdb", dbApi.InitDB) // 创建Api
15 | initRouter.POST("checkdb", dbApi.CheckDB) // 创建Api
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/go/router/system/sys_jwt.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | )
7 |
8 | type JwtRouter struct{}
9 |
10 | func (s *JwtRouter) InitJwtRouter(Router *gin.RouterGroup) {
11 | jwtRouter := Router.Group("jwt")
12 | jwtApi := v1.ApiGroupApp.SystemApiGroup.JwtApi
13 | {
14 | jwtRouter.POST("jsonInBlacklist", jwtApi.JsonInBlacklist) // jwt加入黑名单
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/go/router/system/sys_operation_record.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | )
7 |
8 | type OperationRecordRouter struct{}
9 |
10 | func (s *OperationRecordRouter) InitSysOperationRecordRouter(Router *gin.RouterGroup) {
11 | operationRecordRouter := Router.Group("sysOperationRecord")
12 | authorityMenuApi := v1.ApiGroupApp.SystemApiGroup.OperationRecordApi
13 | {
14 | operationRecordRouter.POST("createSysOperationRecord", authorityMenuApi.CreateSysOperationRecord) // 新建SysOperationRecord
15 | operationRecordRouter.DELETE("deleteSysOperationRecord", authorityMenuApi.DeleteSysOperationRecord) // 删除SysOperationRecord
16 | operationRecordRouter.DELETE("deleteSysOperationRecordByIds", authorityMenuApi.DeleteSysOperationRecordByIds) // 批量删除SysOperationRecord
17 | operationRecordRouter.GET("findSysOperationRecord", authorityMenuApi.FindSysOperationRecord) // 根据ID获取SysOperationRecord
18 | operationRecordRouter.GET("getSysOperationRecordList", authorityMenuApi.GetSysOperationRecordList) // 获取SysOperationRecord列表
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/go/router/system/sys_system.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | type SysRouter struct{}
10 |
11 | func (s *SysRouter) InitSystemRouter(Router *gin.RouterGroup) {
12 | sysRouter := Router.Group("system").Use(middleware.OperationRecord())
13 | systemApi := v1.ApiGroupApp.SystemApiGroup.SystemApi
14 | {
15 | sysRouter.POST("getSystemConfig", systemApi.GetSystemConfig) // 获取配置文件内容
16 | sysRouter.POST("setSystemConfig", systemApi.SetSystemConfig) // 设置配置文件内容
17 | sysRouter.POST("getServerInfo", systemApi.GetServerInfo) // 获取服务器信息
18 | sysRouter.POST("reloadSystem", systemApi.ReloadSystem) // 重启服务
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/go/router/system/sys_user.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | v1 "github.com/nooncall/owls/go/api/v1"
6 | "github.com/nooncall/owls/go/middleware"
7 | )
8 |
9 | type UserRouter struct{}
10 |
11 | func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup) {
12 | userRouter := Router.Group("user").Use(middleware.OperationRecord())
13 | userRouterWithoutRecord := Router.Group("user")
14 | baseApi := v1.ApiGroupApp.SystemApiGroup.BaseApi
15 | {
16 | userRouter.POST("register", baseApi.Register) // 管理员注册账号
17 | userRouter.POST("changePassword", baseApi.ChangePassword) // 用户修改密码
18 | userRouter.POST("setUserAuthority", baseApi.SetUserAuthority) // 设置用户权限
19 | userRouter.DELETE("deleteUser", baseApi.DeleteUser) // 删除用户
20 | userRouter.PUT("setUserInfo", baseApi.SetUserInfo) // 设置用户信息
21 | userRouter.PUT("setSelfInfo", baseApi.SetSelfInfo) // 设置自身信息
22 | userRouter.POST("setUserAuthorities", baseApi.SetUserAuthorities) // 设置用户权限组
23 | userRouter.POST("resetPassword", baseApi.ResetPassword) // 设置用户权限组
24 | }
25 | {
26 | userRouterWithoutRecord.POST("getUserList", baseApi.GetUserList) // 分页获取用户列表
27 | userRouterWithoutRecord.GET("getUserInfo", baseApi.GetUserInfo) // 获取自身信息
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/go/router/tidb_or_mysql/enter.go:
--------------------------------------------------------------------------------
1 | package tidb_or_mysql
2 |
3 | type RouterGroup struct {
4 | TidbOrMysqlRouter
5 | }
6 |
--------------------------------------------------------------------------------
/go/service/auth/auth/auth_task.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/nooncall/owls/go/service/task"
7 | )
8 |
9 | func (a Auth) AddTask(ctx context.Context, cluster string, db int, parentTaskID int64) (int64, bool, error) {
10 | // a.ParentTaskID = parentTaskID
11 | count, err := authDao.AddAuth(&a)
12 | return count, true, err
13 | }
14 |
15 | // give auth by set status
16 | func (a Auth) ExecTask(ctx context.Context, startSubTaskId, taskId int64, cluster, db string) error {
17 | a.Status = StatusPass
18 | return authDao.UpdateAuth(&a)
19 | }
20 |
21 | func (a Auth) UpdateTask(action string) error {
22 | switch action {
23 | case task.ActionCancel:
24 | a.Status = StatusCancelApply
25 | case task.ActionApproval:
26 | a.Status = StatusPass
27 | case task.Reject:
28 | a.Status = StatusReject
29 | case task.ActionUpdate:
30 | }
31 | return authDao.UpdateAuth(&a)
32 | }
33 |
34 | func (a Auth) ListTask(parentTaskID int64) (interface{}, error) {
35 | panic("implement me")
36 | }
37 |
38 | func (a Auth) GetTask(id int64) (interface{}, error) {
39 | return authDao.GetAuth(id)
40 | }
41 |
42 | func (a Auth) GetExecWaitTask() ([]interface{}, int64, error) {
43 | panic("implement me")
44 | }
45 |
--------------------------------------------------------------------------------
/go/service/auth/auth/filter.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | import "github.com/nooncall/owls/go/utils/logger"
4 |
5 | func FilterDB(dbs []string, userId uint, dataType, cluster string) []string {
6 | f := "FilterDB()-->: "
7 | auths, err := authDao.ListAuthForFilter(userId, StatusPass, DB)
8 | if err != nil {
9 | logger.Errorf("%s get auth err: %v", f, err)
10 | return dbs
11 | }
12 |
13 | var result []string
14 | for _, db := range dbs {
15 | for _, auth := range auths {
16 | if auth.Cluster == cluster && auth.DB == db && auth.DataType == dataType {
17 | result = append(result, db)
18 | break
19 | }
20 | }
21 | }
22 |
23 | return result
24 | }
25 |
26 | func FilterCluster(clusters []string, userId uint, dataType string) []string {
27 | f := "FilterCluster()-->: "
28 | auths, err := authDao.ListAuthForFilter(userId, StatusPass, DB)
29 | if err != nil {
30 | logger.Errorf("%s get auth err: %v", f, err)
31 | return clusters
32 | }
33 |
34 | var result []string
35 | for _, cluster := range clusters {
36 | for _, auth := range auths {
37 | if auth.Cluster == cluster && auth.DataType == dataType {
38 | result = append(result, cluster)
39 | break
40 | }
41 | }
42 | }
43 |
44 | return result
45 | }
46 |
--------------------------------------------------------------------------------
/go/service/auth/auth/type.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | const (
4 | DB = "db"
5 | )
6 |
7 | const (
8 | StatusCancelApply = "cancel_apply"
9 | StatusPass = "paas"
10 | StatusReject = "reject"
11 | )
12 |
13 | func Types() []string {
14 | return []string{DB}
15 | }
16 |
--------------------------------------------------------------------------------
/go/service/autocode/enter.go:
--------------------------------------------------------------------------------
1 | package autocode
2 |
3 | type ServiceGroup struct {
4 | // Code generated by github.com/nooncall/owls/go Begin; DO NOT EDIT.
5 | AutoCodeExampleService
6 | // Code generated by github.com/nooncall/owls/go End; DO NOT EDIT.
7 | }
8 |
--------------------------------------------------------------------------------
/go/service/enter.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/nooncall/owls/go/service/autocode"
5 | "github.com/nooncall/owls/go/service/example"
6 | "github.com/nooncall/owls/go/service/system"
7 | )
8 |
9 | type ServiceGroup struct {
10 | SystemServiceGroup system.ServiceGroup
11 | ExampleServiceGroup example.ServiceGroup
12 | AutoCodeServiceGroup autocode.ServiceGroup
13 | }
14 |
15 | var ServiceGroupApp = new(ServiceGroup)
16 |
--------------------------------------------------------------------------------
/go/service/example/enter.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | type ServiceGroup struct {
4 | ExcelService
5 | CustomerService
6 | FileUploadAndDownloadService
7 | }
8 |
--------------------------------------------------------------------------------
/go/service/redis/connection.go:
--------------------------------------------------------------------------------
1 | package redis
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "github.com/go-redis/redis/v8"
8 | "github.com/nooncall/owls/go/service/tidb_or_mysql/db_info"
9 | "github.com/nooncall/owls/go/utils/logger"
10 | )
11 |
12 | func NewRedisCli(clusterName string, database int) (r *redis.Client, err error) {
13 | cluster, err := db_info.GetClusterByName(clusterName)
14 | if err != nil {
15 | return nil, fmt.Errorf("get cluster info err: %s", err.Error())
16 | }
17 |
18 | // new,and init
19 | redisCli := redis.NewClient(&redis.Options{
20 | Addr: cluster.Addr,
21 | Password: cluster.Pwd, // redis的认证密码
22 | DB: database, // 连接的database库
23 | IdleTimeout: 300, // 默认Idle超时时间
24 | PoolSize: 10, // 连接池
25 | })
26 |
27 | res, err := redisCli.Ping(context.Background()).Result()
28 | if err != nil {
29 | logger.Errorf("Connect Failed! Err: %v", err)
30 | return nil, err
31 | }
32 | logger.Errorf("Connect Successful! Ping => %v", res)
33 | return redisCli, nil
34 | }
35 |
--------------------------------------------------------------------------------
/go/service/redis/init.go:
--------------------------------------------------------------------------------
1 | package redis
2 |
3 | import (
4 | _ "github.com/go-sql-driver/mysql"
5 | "gorm.io/gorm"
6 |
7 | "github.com/nooncall/owls/go/global"
8 | )
9 |
10 | var DB *gorm.DB
11 |
12 | func GetDB() *gorm.DB {
13 | // todo, refactor to config~~
14 | return global.GVA_DB.Debug()
15 | }
16 |
--------------------------------------------------------------------------------
/go/service/redis/query.go:
--------------------------------------------------------------------------------
1 | package redis
2 |
3 | import (
4 | "context"
5 | )
6 |
7 | type Params struct {
8 | Cmd, Cluster string
9 | DB int
10 | }
11 |
12 | // ExecQuery ...
13 | func ExecQuery(ctx context.Context, req *Params) interface{} {
14 | resp, err := ExecReadTask(ctx, req)
15 | if err != nil {
16 | return err.Error()
17 |
18 | }
19 | return resp
20 | }
21 |
--------------------------------------------------------------------------------
/go/service/redis/redis_dao/white_list_dao.go:
--------------------------------------------------------------------------------
1 | package redis_dao
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/nooncall/owls/go/service/redis"
7 | "gorm.io/gorm"
8 | )
9 |
10 | type WhiteListDao struct{}
11 |
12 | func NewWhiteListDao() redis.WhiteListDao {
13 | return &WhiteListDao{}
14 | }
15 |
16 | func (dao *WhiteListDao) AddWhiteList(ctx context.Context, db *gorm.DB, WhiteList *redis.WhiteList) (int64, error) {
17 | result := db.Create(WhiteList)
18 | if result.Error != nil {
19 | return 0, result.Error
20 | }
21 | return WhiteList.ID, nil
22 | }
23 |
24 | func (dao *WhiteListDao) DelWhiteList(ctx context.Context, db *gorm.DB, id int64) error {
25 | result := db.Delete(&redis.WhiteList{}, id)
26 | return result.Error
27 | }
28 |
29 | func (dao *WhiteListDao) ListWhiteList(ctx context.Context, db *gorm.DB, cmdType string) ([]redis.WhiteList, error) {
30 | var whiteLists []redis.WhiteList
31 | result := db.Where("cmd_type = ?", cmdType).Find(&whiteLists)
32 | if result.Error != nil {
33 | return nil, result.Error
34 | }
35 | return whiteLists, nil
36 | }
37 |
--------------------------------------------------------------------------------
/go/service/system/enter.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | type ServiceGroup struct {
4 | JwtService
5 | ApiService
6 | MenuService
7 | UserService
8 | CasbinService
9 | InitDBService
10 | AutoCodeService
11 | BaseMenuService
12 | AuthorityService
13 | DictionaryService
14 | SystemConfigService
15 | AutoCodeHistoryService
16 | OperationRecordService
17 | DictionaryDetailService
18 | AuthorityBtnService
19 | }
20 |
--------------------------------------------------------------------------------
/go/service/system/sys_auto_code_interface.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | "github.com/nooncall/owls/go/model/system/response"
6 | )
7 |
8 | type Database interface {
9 | GetDB() (data []response.Db, err error)
10 | GetTables(dbName string) (data []response.Table, err error)
11 | GetColumn(tableName string, dbName string) (data []response.Column, err error)
12 | }
13 |
14 | func (autoCodeService *AutoCodeService) Database() Database {
15 | switch global.GVA_CONFIG.System.DbType {
16 | case "mysql":
17 | return AutoCodeMysql
18 | case "pgsql":
19 | return AutoCodePgsql
20 | default:
21 | return AutoCodeMysql
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/go/service/task/status.go:
--------------------------------------------------------------------------------
1 | package task
2 |
3 | const (
4 | WaitApproval = "wait_approval"
5 | Pass = "pass"
6 | Failed = "failed"
7 | Cancel = "cancel"
8 | Reject = "reject"
9 | )
10 |
11 | func ExecStatus() []string {
12 | return []string{WaitApproval}
13 | }
14 |
15 | func SubmitStatus() []string {
16 | return []string{WaitApproval, Reject}
17 | }
18 |
19 | func HistoryStatus() []string {
20 | return []string{Pass, Failed, Cancel}
21 | }
22 |
--------------------------------------------------------------------------------
/go/service/task/type.go:
--------------------------------------------------------------------------------
1 | package task
2 |
3 | const (
4 | Auth = "auth"
5 | Redis = "redis"
6 |
7 | ActionCancel = "cancel"
8 | ActionUpdate = "update"
9 | ActionApproval = "approval"
10 | ActionResubmit = "resubmit"
11 | ActionReject = "reject"
12 | ActionExec = "exec"
13 | )
14 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/auth/admin.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | import (
4 | "github.com/nooncall/owls/go/service/tidb_or_mysql"
5 | "github.com/nooncall/owls/go/service/tidb_or_mysql/admin"
6 | )
7 |
8 | type AdminAuthToolImpl struct {
9 | }
10 |
11 | var AdminAuthService AdminAuthToolImpl
12 |
13 | func (AdminAuthToolImpl) GetReviewer(userName string) (reviewerName string, err error) {
14 | admins, _, err := admin.ListAdmin(&tidb_or_mysql.Pagination{Limit: 10})
15 | if err != nil {
16 | return "", err
17 | }
18 |
19 | var resp string
20 | for i, v := range admins {
21 | if i == 0 {
22 | resp += v.Username
23 | } else {
24 | resp += "," + v.Username
25 | }
26 | }
27 | return resp, nil
28 | }
29 |
30 | func (AdminAuthToolImpl) IsDba(userName string) (isDba bool, err error) {
31 | return true, nil
32 | // return admin.IsAdmin(userName)
33 | }
34 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/auth/auth_mock.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | type MockAuth struct {
4 | }
5 |
6 | var MockAuthService MockAuth
7 |
8 | func (MockAuth) GetReviewer(userName string) (reviewerName string, err error) {
9 | return "nobody", nil
10 | }
11 |
12 | func (MockAuth) IsDba(userName string) (isDba bool, err error) {
13 | return true, nil
14 | }
15 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/auth/config_auth_tool.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | import (
4 | "errors"
5 | "strings"
6 |
7 | "github.com/nooncall/owls/go/global"
8 | )
9 |
10 | type ConfAuthToolImpl struct {
11 | }
12 |
13 | var ConfAuthService ConfAuthToolImpl
14 |
15 | func (ConfAuthToolImpl) GetReviewer(userName string) (reviewerName string, err error) {
16 | return strings.Join(global.GVA_CONFIG.DBFilter.Reviewers, ","), nil
17 | }
18 |
19 | func (ConfAuthToolImpl) IsDba(userName string) (isDba bool, err error) {
20 | if len(global.GVA_CONFIG.DBFilter.Reviewers) < 1 {
21 | return false, errors.New("dba members not config")
22 | }
23 | for _, v := range global.GVA_CONFIG.DBFilter.Reviewers {
24 | if v == userName {
25 | return true, nil
26 | }
27 | }
28 |
29 | return false, nil
30 | }
31 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/auth/login_check.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | type LoginChecker interface {
4 | Login(userName, pwd string) error
5 | }
6 |
7 | var loginService LoginChecker
8 |
9 | func SetLoginService(impl LoginChecker) {
10 | loginService = impl
11 | }
12 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/auth/login_check/ldap.go:
--------------------------------------------------------------------------------
1 | package login_check
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 |
7 | ldap "github.com/jtblin/go-ldap-client"
8 | "github.com/nooncall/owls/go/global"
9 | "github.com/nooncall/owls/go/utils/logger"
10 | )
11 |
12 | type LoginServiceImpl struct {
13 | }
14 |
15 | var LoginService LoginServiceImpl
16 |
17 | func (LoginServiceImpl) Login(userName, pwd string) error {
18 | ok, _, err := getLdapConn().Authenticate(userName, pwd)
19 | if err != nil {
20 | return fmt.Errorf("authenticating user err %s: %+v ", userName, err)
21 | }
22 | if !ok {
23 | return fmt.Errorf("authenticating failed for user %s", "username")
24 | }
25 | logger.Infof("user: %s Login", userName)
26 | return nil
27 | }
28 |
29 | var ldapConn *ldap.LDAPClient
30 |
31 | func getLdapConn() *ldap.LDAPClient {
32 | once.Do(setLdapConn)
33 | return ldapConn
34 | }
35 |
36 | var once sync.Once
37 |
38 | func setLdapConn() {
39 | login := global.GVA_CONFIG.Login
40 | ldapConn = &ldap.LDAPClient{
41 | Base: login.Ldap.BaseDn,
42 | Host: login.Ldap.Host,
43 | Port: login.Ldap.Port,
44 | UseSSL: login.Ldap.UseSll,
45 | BindDN: login.Ldap.BaseDn,
46 | BindPassword: login.Ldap.BindPwd,
47 | UserFilter: "(uid=%s)",
48 | GroupFilter: "(memberUid=%s)",
49 | Attributes: []string{"givenName", "sn", "mail", "uid"},
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/common.go:
--------------------------------------------------------------------------------
1 | package tidb_or_mysql
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type Pagination struct {
8 | Offset int `json:"offset"`
9 | Limit int `json:"limit"`
10 | Key string `json:"key"`
11 |
12 | Operator string `json:"operator"`
13 | }
14 |
15 | type ClockInf interface {
16 | Now() time.Time
17 | NowUnix() int64
18 | }
19 |
20 | var Clock ClockInf
21 |
22 | func SetClock(impl ClockInf) {
23 | Clock = impl
24 | }
25 |
26 | type RealClock struct{}
27 |
28 | func (RealClock) Now() time.Time { return time.Now() }
29 | func (RealClock) NowUnix() int64 { return time.Now().Unix() }
30 | func (RealClock) After(d time.Duration) <-chan time.Time { return time.After(d) }
31 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/dao/backup.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "github.com/nooncall/owls/go/service/tidb_or_mysql/task"
5 | )
6 |
7 | type BackupImpl struct {
8 | }
9 |
10 | var BackupDAO BackupImpl
11 |
12 | func (BackupImpl) AddBackup(backup *task.OwlBackup) (int64, error) {
13 | err := GetDB().Create(backup).Error
14 | return backup.ID, err
15 | }
16 |
17 | func (BackupImpl) UpdateBackup(backup *task.OwlBackup) error {
18 | return GetDB().Model(backup).Where("id = ?", backup.ID).Updates(backup).Error
19 | }
20 |
21 | func (BackupImpl) GetBackupInfoById(id int64) (*task.OwlBackup, error) {
22 | var backup task.OwlBackup
23 | return &backup, GetDB().Where("id = ?", id).First(&backup).Error
24 | }
25 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/dao/init.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | _ "github.com/go-sql-driver/mysql"
5 | "gorm.io/gorm"
6 |
7 | "github.com/nooncall/owls/go/global"
8 | )
9 |
10 | var DB *gorm.DB
11 |
12 | func GetDB() *gorm.DB {
13 | // todo, refactor to config~~
14 | return global.GVA_DB.Debug()
15 | }
16 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/dao/rule.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "github.com/nooncall/owls/go/service/tidb_or_mysql/checker"
5 | "gorm.io/gorm"
6 | )
7 |
8 | type RuleDaoImpl struct {
9 | }
10 |
11 | var Rule RuleDaoImpl
12 |
13 | func (RuleDaoImpl) ListAllStatus() ([]checker.OwlRuleStatus, error) {
14 | var ruleStatus []checker.OwlRuleStatus
15 | return ruleStatus, GetDB().Find(&ruleStatus).Error
16 | }
17 |
18 | func (RuleDaoImpl) UpdateRuleStatus(ruleStatus *checker.OwlRuleStatus) error {
19 | err := GetDB().Where("name = ?", ruleStatus.Name).First(&checker.OwlRuleStatus{}).Error
20 | if err == gorm.ErrRecordNotFound {
21 | return GetDB().Create(ruleStatus).Error
22 | }
23 | if err != nil {
24 | return err
25 | }
26 |
27 | return GetDB().Model(ruleStatus).Where("name = ?", ruleStatus.Name).Updates(ruleStatus).Error
28 | }
29 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/dao/sub_task.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import "github.com/nooncall/owls/go/service/tidb_or_mysql/task"
4 |
5 | type SubTaskDaoImpl struct {
6 | }
7 |
8 | var SubTask SubTaskDaoImpl
9 |
10 | func (SubTaskDaoImpl) UpdateItem(item *task.OwlExecItem) error {
11 | return GetDB().Model(item).Where("id = ?", item.ID).Updates(item).Error
12 | }
13 |
14 | func (SubTaskDaoImpl) DelItem(item *task.OwlExecItem) error {
15 | return GetDB().Model(item).Where("id = ?", item.ID).Delete(item).Error
16 | }
17 |
18 | func (SubTaskDaoImpl) UpdateItemByBackupId(item *task.OwlExecItem) error {
19 | return GetDB().Model(item).Where("backup_id = ?", item.BackupID).Updates(item).Error
20 | }
21 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/sql_util/amend_sql.go:
--------------------------------------------------------------------------------
1 | package sql_util
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/nooncall/owls/go/utils/logger"
8 | "github.com/pingcap/parser/ast"
9 | )
10 |
11 | type readSql struct {
12 | sql string
13 | }
14 |
15 | func NewReadSql(sql string) *readSql {
16 | return &readSql{sql}
17 | }
18 |
19 | func (readSql *readSql) String() string {
20 | return readSql.sql
21 | }
22 |
23 | func (readSql *readSql) appendLimit() {
24 | readSql.sql = fmt.Sprintf("%s limit 10", readSql.sql)
25 | }
26 |
27 | func (readSql *readSql) Trim() {
28 | readSql.sql = strings.TrimSpace(readSql.sql)
29 | readSql.sql = strings.TrimRight(readSql.sql, ";")
30 | }
31 |
32 | func (readSql *readSql) SetLimitResult() string {
33 | f := "AddLimitToSelect-->: "
34 |
35 | readSql.Trim()
36 | stmtNodes, _, err := getParser().Parse(readSql.sql, "", "")
37 | if err != nil {
38 | logger.Errorf("%sparse sql err: %v", f, err)
39 | return readSql.sql
40 | }
41 |
42 | for _, tiStmt := range stmtNodes {
43 | switch node := tiStmt.(type) {
44 | case *ast.SelectStmt:
45 | if node.Limit == nil {
46 | readSql.appendLimit()
47 | return readSql.String()
48 | }
49 | default:
50 | return readSql.String()
51 | }
52 | }
53 |
54 | return readSql.String()
55 | }
56 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/sql_util/test/amend_sql_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/nooncall/owls/go/service/tidb_or_mysql/sql_util"
5 | "testing"
6 | )
7 |
8 | func TestAddLimit(t *testing.T) {
9 | testData := []struct {
10 | source, expect string
11 | }{
12 | {
13 | "select * from cluster; ",
14 | "select * from cluster limit 10",
15 | },
16 | {
17 | "select * from cluster limit 2",
18 | "select * from cluster limit 2",
19 | },
20 | {
21 | "select * from cluster",
22 | "select * from cluster limit 10",
23 | },
24 |
25 | {
26 | "select * from owl_clusters where id in (select id from owl_clusters limit 2)",
27 | "select * from owl_clusters where id in (select id from owl_clusters limit 2) limit 10",
28 | },
29 | {
30 | "select * from owl_clusters where id in (select id from owl_clusters)",
31 | "select * from owl_clusters where id in (select id from owl_clusters) limit 10",
32 | },
33 | {
34 | "select * from owl_clusters where id in (select id from owl_clusters) limit 5",
35 | "select * from owl_clusters where id in (select id from owl_clusters) limit 5",
36 | },
37 | }
38 |
39 | for i, v := range testData {
40 | if v.expect != sql_util.NewReadSql(v.source).SetLimitResult() {
41 | t.Log("failed at :", testData[i])
42 | t.FailNow()
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/task/checker.go:
--------------------------------------------------------------------------------
1 | package task
2 |
3 | type sqlChecker interface {
4 | SqlCheck(sql, charset, collation string, info *DBInfo) (pass bool, suggestion string, affectRow int)
5 | ListRules() interface{}
6 | }
7 |
8 | var checker sqlChecker
9 |
10 | func SetChecker(impl sqlChecker) {
11 | checker = impl
12 | }
13 |
--------------------------------------------------------------------------------
/go/service/tidb_or_mysql/task/db.go:
--------------------------------------------------------------------------------
1 | package task
2 |
3 | import (
4 | "database/sql"
5 |
6 | "github.com/nooncall/owls/go/utils/logger"
7 | )
8 |
9 | type DBInfo struct {
10 | DB *sql.DB
11 | DefaultDB *sql.DB
12 | DBName string
13 | }
14 |
15 | func (db *DBInfo) CloseConn() {
16 | if err := db.DB.Close(); err != nil {
17 | logger.Errorf("close db conn err: %s", err.Error())
18 | }
19 | if err := db.DefaultDB.Close(); err != nil {
20 | logger.Errorf("close default db conn err: %s", err.Error())
21 | }
22 | }
23 |
24 | type dbTools interface {
25 | GetDBConn(dbName, cluster string) (*DBInfo, error)
26 | }
27 |
28 | var dbTool dbTools
29 |
30 | func SetDbTools(impl dbTools) {
31 | dbTool = impl
32 | }
33 |
34 | type OwlAccount struct {
35 | ID uint64 `json:"id" gorm:"column:id"`
36 | Username string `json:"username" gorm:"column:username"`
37 | Passwd string `json:"passwd" gorm:"column:passwd"`
38 | Dbtype int64 `json:"dbtype" gorm:"column:dbtype"`
39 | }
40 |
--------------------------------------------------------------------------------
/go/source/example/file_mysql.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | "github.com/nooncall/owls/go/model/example"
6 | "github.com/nooncall/owls/go/model/system"
7 | "github.com/pkg/errors"
8 | "gorm.io/gorm"
9 | )
10 |
11 | var FileMysql = new(fileMysql)
12 |
13 | type fileMysql struct{}
14 |
15 | func (f *fileMysql) TableName() string {
16 | return "exa_file_upload_and_downloads"
17 | }
18 |
19 | func (f *fileMysql) Initialize(initData *system.InitDBData) error {
20 | entities := []example.ExaFileUploadAndDownload{
21 | {Name: "10.png", Url: "https://qmplusimg.henrongyi.top/gvalogo.png", Tag: "png", Key: "158787308910.png"},
22 | {Name: "logo.png", Url: "https://qmplusimg.henrongyi.top/1576554439myAvatar.png", Tag: "png", Key: "1587973709logo.png"},
23 | }
24 | if err := global.GVA_DB.Create(&entities).Error; err != nil {
25 | return errors.Wrap(err, f.TableName()+"表数据初始化失败!")
26 | }
27 | return nil
28 | }
29 |
30 | func (f *fileMysql) CheckDataExist() bool {
31 | if errors.Is(global.GVA_DB.Where("`name` = ? AND `key` = ?", "logo.png", "1587973709logo.png").First(&example.ExaFileUploadAndDownload{}).Error, gorm.ErrRecordNotFound) {
32 | return false
33 | }
34 | return true
35 | }
36 |
--------------------------------------------------------------------------------
/go/source/example/file_pgsql.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | "github.com/nooncall/owls/go/model/example"
6 | "github.com/nooncall/owls/go/model/system"
7 | "github.com/pkg/errors"
8 | "gorm.io/gorm"
9 | )
10 |
11 | var FilePgsql = new(filePgsql)
12 |
13 | type filePgsql struct{}
14 |
15 | func (f *filePgsql) TableName() string {
16 | return "exa_file_upload_and_downloads"
17 | }
18 |
19 | func (f *filePgsql) Initialize(initData *system.InitDBData) error {
20 | entities := []example.ExaFileUploadAndDownload{
21 | {Name: "10.png", Url: "https://qmplusimg.henrongyi.top/gvalogo.png", Tag: "png", Key: "158787308910.png"},
22 | {Name: "logo.png", Url: "https://qmplusimg.henrongyi.top/1576554439myAvatar.png", Tag: "png", Key: "1587973709logo.png"},
23 | }
24 | if err := global.GVA_DB.Create(&entities).Error; err != nil {
25 | return errors.Wrap(err, f.TableName()+"表数据初始化失败!")
26 | }
27 | return nil
28 | }
29 |
30 | func (f *filePgsql) CheckDataExist() bool {
31 | if errors.Is(global.GVA_DB.Where("name = ? AND key = ?", "logo.png", "1587973709logo.png").First(&example.ExaFileUploadAndDownload{}).Error, gorm.ErrRecordNotFound) {
32 | return false
33 | }
34 | return true
35 | }
36 |
--------------------------------------------------------------------------------
/go/source/system/authority.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | "github.com/nooncall/owls/go/model/system"
6 | "github.com/pkg/errors"
7 | "gorm.io/gorm"
8 | )
9 |
10 | var Authority = new(authority)
11 |
12 | type authority struct{}
13 |
14 | func (a *authority) TableName() string {
15 | return "sys_authorities"
16 | }
17 |
18 | func (a *authority) Initialize(initData *system.InitDBData) error {
19 | entities := []system.SysAuthority{
20 | {AuthorityId: "888", AuthorityName: "dev", ParentId: "0", DefaultRouter: "dashboard"},
21 | {AuthorityId: "887", AuthorityName: "admin", ParentId: "0", DefaultRouter: "dashboard"},
22 | {AuthorityId: "886", AuthorityName: "user", ParentId: "0", DefaultRouter: "dashboard"},
23 | }
24 | if err := global.GVA_DB.Create(&entities).Error; err != nil {
25 | return errors.Wrapf(err, "%s表数据初始化失败!", a.TableName())
26 | }
27 | return nil
28 | }
29 |
30 | func (a *authority) CheckDataExist() bool {
31 | if errors.Is(global.GVA_DB.Where("authority_id = ?", "888").First(&system.SysAuthority{}).Error, gorm.ErrRecordNotFound) { // 判断是否存在数据
32 | return false
33 | }
34 | return true
35 | }
36 |
--------------------------------------------------------------------------------
/go/source/system/user_authority.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/nooncall/owls/go/global"
5 | "github.com/nooncall/owls/go/model/system"
6 | "github.com/pkg/errors"
7 | "gorm.io/gorm"
8 | )
9 |
10 | var UserAuthority = new(userAuthority)
11 |
12 | type userAuthority struct{}
13 |
14 | func (a *userAuthority) TableName() string {
15 | var entity system.SysUseAuthority
16 | return entity.TableName()
17 | }
18 |
19 | func (a *userAuthority) Initialize(initData *system.InitDBData) error {
20 | entities := []system.SysUseAuthority{
21 | {SysUserId: 1, SysAuthorityAuthorityId: "888"},
22 | {SysUserId: 2, SysAuthorityAuthorityId: "887"},
23 | {SysUserId: 3, SysAuthorityAuthorityId: "886"},
24 | }
25 | if err := global.GVA_DB.Create(&entities).Error; err != nil {
26 | return errors.Wrap(err, a.TableName()+"表数据初始化失败!")
27 | }
28 | return nil
29 | }
30 |
31 | func (a *userAuthority) CheckDataExist() bool {
32 | if errors.Is(global.GVA_DB.Where("sys_user_id = ? AND sys_authority_authority_id = ?", 1, "888").First(&system.SysUseAuthority{}).Error, gorm.ErrRecordNotFound) { // 判断是否存在数据
33 | return false
34 | }
35 | return true
36 | }
37 |
--------------------------------------------------------------------------------
/go/utils/constant.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | // todo, refactor to consts package
4 | const (
5 | ConfigEnv = "GVA_CONFIG"
6 | ConfigFile = "config.yaml"
7 |
8 | ClusterTypeRedis = "redis"
9 | ClusterTypeMysql = "mysql" // or tidb
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/go/utils/crypto.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "crypto/aes"
5 | "crypto/cipher"
6 | "fmt"
7 | "github.com/nooncall/owls/go/global"
8 | )
9 |
10 | //加密
11 | func AesCrypto(source []byte) ([]byte, error) {
12 | var block cipher.Block
13 | var err error
14 | if block, err = aes.NewCipher([]byte(global.GVA_CONFIG.DBFilter.AesKey)); err != nil {
15 | return nil, fmt.Errorf("crypto err: %s", err.Error())
16 | }
17 | stream := cipher.NewCTR(block, []byte(global.GVA_CONFIG.DBFilter.AesIv))
18 | stream.XORKeyStream(source, source)
19 | return source, nil
20 | }
21 |
22 | //解密
23 | func AesDeCrypto(cryptoData []byte) ([]byte, error) {
24 | return AesCrypto(cryptoData)
25 | }
26 |
--------------------------------------------------------------------------------
/go/utils/crypto_test.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/nooncall/owls/go/config"
7 | "github.com/nooncall/owls/go/utils/logger"
8 | )
9 |
10 | func TestCryPto(t *testing.T) {
11 | logger.InitLog(".", "test.log", "debug")
12 | config.InitConfig("../config/config.yaml")
13 |
14 | f := "TestCryPto"
15 | pwd := "aaaaaa"
16 |
17 | cryptoPwd, err := AesCrypto([]byte(pwd))
18 | if err != nil {
19 | t.Errorf("%s crypto err: %s", f, err.Error())
20 | t.FailNow()
21 | }
22 | deCryptoPwd, err := AesDeCrypto(cryptoPwd)
23 | if err != nil {
24 | t.Errorf("%s decrypto err: %s", f, err.Error())
25 | t.FailNow()
26 | }
27 |
28 | if pwd != string(deCryptoPwd) {
29 | t.Errorf("%s failed, not equal", f)
30 | t.FailNow()
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/go/utils/db_automation.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "time"
7 |
8 | "gorm.io/gorm"
9 | )
10 |
11 | //@author: [songzhibin97](https://github.com/songzhibin97)
12 | //@function: ClearTable
13 | //@description: 清理数据库表数据
14 | //@param: db(数据库对象) *gorm.DB, tableName(表名) string, compareField(比较字段) string, interval(间隔) string
15 | //@return: error
16 |
17 | func ClearTable(db *gorm.DB, tableName string, compareField string, interval string) error {
18 | if db == nil {
19 | return errors.New("db Cannot be empty")
20 | }
21 | duration, err := time.ParseDuration(interval)
22 | if err != nil {
23 | return err
24 | }
25 | if duration < 0 {
26 | return errors.New("parse duration < 0")
27 | }
28 | return db.Debug().Exec(fmt.Sprintf("DELETE FROM %s WHERE %s < ?", tableName, compareField), time.Now().Add(-duration)).Error
29 | }
30 |
31 | func GenerateOrderField(key string, desc bool) string {
32 | if desc {
33 | return fmt.Sprintf("%s desc", key)
34 | }
35 |
36 | return fmt.Sprintf("%s asc", key)
37 | }
38 |
--------------------------------------------------------------------------------
/go/utils/directory.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "errors"
5 | "os"
6 |
7 | "github.com/nooncall/owls/go/global"
8 | "go.uber.org/zap"
9 | )
10 |
11 | //@author: [piexlmax](https://github.com/piexlmax)
12 | //@function: PathExists
13 | //@description: 文件目录是否存在
14 | //@param: path string
15 | //@return: bool, error
16 |
17 | func PathExists(path string) (bool, error) {
18 | fi, err := os.Stat(path)
19 | if err == nil {
20 | if fi.IsDir() {
21 | return true, nil
22 | }
23 | return false, errors.New("存在同名文件")
24 | }
25 | if os.IsNotExist(err) {
26 | return false, nil
27 | }
28 | return false, err
29 | }
30 |
31 | //@author: [piexlmax](https://github.com/piexlmax)
32 | //@function: CreateDir
33 | //@description: 批量创建文件夹
34 | //@param: dirs ...string
35 | //@return: err error
36 |
37 | func CreateDir(dirs ...string) (err error) {
38 | for _, v := range dirs {
39 | exist, err := PathExists(v)
40 | if err != nil {
41 | return err
42 | }
43 | if !exist {
44 | global.GVA_LOG.Debug("create directory" + v)
45 | if err := os.MkdirAll(v, os.ModePerm); err != nil {
46 | global.GVA_LOG.Error("create directory"+v, zap.Any(" error:", err))
47 | return err
48 | }
49 | }
50 | }
51 | return err
52 | }
53 |
--------------------------------------------------------------------------------
/go/utils/fmt_plus.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | "strings"
7 | )
8 |
9 | //@author: [piexlmax](https://github.com/piexlmax)
10 | //@function: StructToMap
11 | //@description: 利用反射将结构体转化为map
12 | //@param: obj interface{}
13 | //@return: map[string]interface{}
14 |
15 | func StructToMap(obj interface{}) map[string]interface{} {
16 | obj1 := reflect.TypeOf(obj)
17 | obj2 := reflect.ValueOf(obj)
18 |
19 | data := make(map[string]interface{})
20 | for i := 0; i < obj1.NumField(); i++ {
21 | if obj1.Field(i).Tag.Get("mapstructure") != "" {
22 | data[obj1.Field(i).Tag.Get("mapstructure")] = obj2.Field(i).Interface()
23 | } else {
24 | data[obj1.Field(i).Name] = obj2.Field(i).Interface()
25 | }
26 | }
27 | return data
28 | }
29 |
30 | //@author: [piexlmax](https://github.com/piexlmax)
31 | //@function: ArrayToString
32 | //@description: 将数组格式化为字符串
33 | //@param: array []interface{}
34 | //@return: string
35 |
36 | func ArrayToString(array []interface{}) string {
37 | return strings.Replace(strings.Trim(fmt.Sprint(array), "[]"), " ", ",", -1)
38 | }
39 |
--------------------------------------------------------------------------------
/go/utils/http.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "net/http"
7 | "strings"
8 | )
9 |
10 | const (
11 | PostMethod = "POST"
12 | GetMethod = "GET"
13 | )
14 |
15 | func DoHttpReq(method, url, jsonParam string, header http.Header) ([]byte, error) {
16 | cli := &http.Client{}
17 | req, err := http.NewRequest(method, url, strings.NewReader(jsonParam))
18 | if err != nil {
19 | return nil, fmt.Errorf("new request err:%s", err.Error())
20 | }
21 |
22 | req.Header = header
23 | resp, err := cli.Do(req)
24 | if err != nil {
25 | return nil, fmt.Errorf("do request err: %s", err.Error())
26 | }
27 | defer resp.Body.Close()
28 |
29 | return ioutil.ReadAll(resp.Body)
30 | }
31 |
--------------------------------------------------------------------------------
/go/utils/md5.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "crypto/md5"
5 | "encoding/hex"
6 | )
7 |
8 | //@author: [piexlmax](https://github.com/piexlmax)
9 | //@function: MD5V
10 | //@description: md5加密
11 | //@param: str []byte
12 | //@return: string
13 |
14 | func MD5V(str []byte, b ...byte) string {
15 | h := md5.New()
16 | h.Write(str)
17 | return hex.EncodeToString(h.Sum(b))
18 | }
19 |
--------------------------------------------------------------------------------
/go/utils/numbers.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import "strconv"
4 |
5 | func SubTwoStrNum(numA, numB string) (int64, error) {
6 | a, err := strconv.ParseInt(numA, 10, 64)
7 | if err != nil {
8 | return 0, err
9 | }
10 |
11 | b, err := strconv.ParseInt(numB, 10, 64)
12 | if err != nil {
13 | return 0, err
14 | }
15 |
16 | return a - b, nil
17 | }
18 |
19 | func Int64ArrayDeduplication(data []int64) (result []int64) {
20 | mapData := make(map[int64]struct{})
21 | for _, v := range data {
22 | mapData[v] = struct{}{}
23 | }
24 |
25 | for k, _ := range mapData {
26 | result = append(result, k)
27 | }
28 | return
29 | }
30 |
--------------------------------------------------------------------------------
/go/utils/plugin/plugin.go:
--------------------------------------------------------------------------------
1 | package plugin
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | const (
8 | OnlyFuncName = "Plugin"
9 | )
10 |
11 | // Plugin 插件模式接口化
12 | type Plugin interface {
13 | // Register 注册路由
14 | Register(group *gin.RouterGroup)
15 |
16 | // RouterPath 用户返回注册路由
17 | RouterPath() string
18 | }
19 |
--------------------------------------------------------------------------------
/go/utils/reload.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "errors"
5 | "os"
6 | "os/exec"
7 | "runtime"
8 | "strconv"
9 | )
10 |
11 | func Reload() error {
12 | if runtime.GOOS == "windows" {
13 | return errors.New("系统不支持")
14 | }
15 | pid := os.Getpid()
16 | cmd := exec.Command("kill", "-1", strconv.Itoa(pid))
17 | return cmd.Run()
18 | }
19 |
--------------------------------------------------------------------------------
/go/utils/rotatelogs.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/natefinch/lumberjack"
7 | "github.com/nooncall/owls/go/global"
8 | "go.uber.org/zap/zapcore"
9 | )
10 |
11 | //@author: [SliverHorn](https://github.com/SliverHorn)
12 | //@function: GetWriteSyncer
13 | //@description: zap logger中加入file-rotatelogs
14 | //@return: zapcore.WriteSyncer, error
15 |
16 | func GetWriteSyncer(file string) zapcore.WriteSyncer {
17 | lumberJackLogger := &lumberjack.Logger{
18 | Filename: file, // 日志文件的位置
19 | MaxSize: 10, // 在进行切割之前,日志文件的最大大小(以MB为单位)
20 | MaxBackups: 200, // 保留旧文件的最大个数
21 | MaxAge: 30, // 保留旧文件的最大天数
22 | Compress: true, // 是否压缩/归档旧文件
23 | }
24 |
25 | if global.GVA_CONFIG.Zap.LogInConsole {
26 | return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(lumberJackLogger))
27 | }
28 | return zapcore.AddSync(lumberJackLogger)
29 | }
30 |
--------------------------------------------------------------------------------
/go/utils/set.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | func MergeStringMaps(m1, m2 map[string]string) map[string]string {
4 | for k, v := range m1 {
5 | m2[k] = v
6 | }
7 |
8 | return m2
9 | }
10 |
--------------------------------------------------------------------------------
/go/utils/time_convert.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import "time"
4 |
5 | const timeFmt = "2006-01-02 15:04:05"
6 |
7 | func TimestampToStr(timestamp int64) string {
8 | return time.Unix(timestamp, 0).Format(timeFmt)
9 | }
10 |
--------------------------------------------------------------------------------
/go/utils/timer/timed_task_test.go:
--------------------------------------------------------------------------------
1 | package timer
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | "time"
7 |
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | var job = mockJob{}
12 |
13 | type mockJob struct{}
14 |
15 | func (job mockJob) Run() {
16 | mockFunc()
17 | }
18 |
19 | func mockFunc() {
20 | time.Sleep(time.Second)
21 | fmt.Println("1s...")
22 | }
23 |
24 | func TestNewTimerTask(t *testing.T) {
25 | tm := NewTimerTask()
26 | _tm := tm.(*timer)
27 |
28 | {
29 | _, err := tm.AddTaskByFunc("func", "@every 1s", mockFunc)
30 | assert.Nil(t, err)
31 | _, ok := _tm.taskList["func"]
32 | if !ok {
33 | t.Error("no find func")
34 | }
35 | }
36 |
37 | {
38 | _, err := tm.AddTaskByJob("job", "@every 1s", job)
39 | assert.Nil(t, err)
40 | _, ok := _tm.taskList["job"]
41 | if !ok {
42 | t.Error("no find job")
43 | }
44 | }
45 |
46 | {
47 | _, ok := tm.FindCron("func")
48 | if !ok {
49 | t.Error("no find func")
50 | }
51 | _, ok = tm.FindCron("job")
52 | if !ok {
53 | t.Error("no find job")
54 | }
55 | _, ok = tm.FindCron("none")
56 | if ok {
57 | t.Error("find none")
58 | }
59 | }
60 | {
61 | tm.Clear("func")
62 | _, ok := tm.FindCron("func")
63 | if ok {
64 | t.Error("find func")
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/go/utils/util_test.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func TestDelUselessSpace(t *testing.T) {
9 | type Data struct {
10 | Str string
11 | Target string
12 | }
13 | data := []Data{
14 | {
15 | Str: " hgetall hello",
16 | Target: "hgetall hello",
17 | },
18 | {
19 | Str: " hgetall hello",
20 | Target: "hgetall hello",
21 | },
22 | {
23 | Str: " he llo ",
24 | Target: "he llo",
25 | },
26 | }
27 |
28 | for _, v := range data {
29 | resp := DelUselessSpace(v.Str)
30 | if v.Target != resp {
31 | t.Log(fmt.Sprintf("test DelUselessSpace failed, expect: %s, got:%s", v.Target, resp))
32 | t.FailNow()
33 | }
34 | }
35 | }
36 |
37 | func TestSubTwoStrNum(t *testing.T) {
38 | type Data struct {
39 | a string
40 | b string
41 | target int64
42 | }
43 | data := []Data{
44 | {
45 | a: "10",
46 | b: "8",
47 | target: 2,
48 | },
49 | {
50 | a: "7",
51 | b: "8",
52 | target: -1,
53 | },
54 | }
55 |
56 | for _, v := range data {
57 | resp, err := SubTwoStrNum(v.a, v.b)
58 | if err != nil {
59 | t.Log("test sub str num err: ", err.Error())
60 | t.FailNow()
61 | }
62 |
63 | if v.target != resp {
64 | t.Log(fmt.Sprintf("test DelUselessSpace failed, expect: %d, got:%d", v.target, resp))
65 | t.FailNow()
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/issue.list:
--------------------------------------------------------------------------------
1 | 1, 使用admin做开发,但是给admin加权限还是看不到新页面,需要给普通用户加权限才能看到。
2 |
3 | 2, 页面报404,有可能是没有权限。
4 |
--------------------------------------------------------------------------------
/web/.docker-compose/nginx/conf.d/my.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 8080;
3 | server_name localhost;
4 |
5 | #charset koi8-r;
6 | #access_log logs/host.access.log main;
7 |
8 | location / {
9 | root /usr/share/nginx/html;
10 | add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
11 | try_files $uri $uri/ /index.html;
12 | }
13 |
14 | location /api {
15 | proxy_set_header Host $http_host;
16 | proxy_set_header X-Real-IP $remote_addr;
17 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
18 | proxy_set_header X-Forwarded-Proto $scheme;
19 | rewrite ^/api/(.*)$ /$1 break; #重写
20 | proxy_pass http://177.7.0.12:80; # 设置代理服务器的协议和地址
21 | }
22 |
23 | location /api/swagger/index.html {
24 | proxy_pass http://127.0.0.1:80/swagger/index.html;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/web/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/web/.env.development:
--------------------------------------------------------------------------------
1 | ENV = 'development'
2 | VITE_CLI_PORT = 8080
3 | VITE_SERVER_PORT = 8778
4 | VITE_BASE_API = /api
5 | VITE_BASE_PATH = http://127.0.0.1
6 | // 如果使用docker-compose开发模式,设置为下面的地址
7 | //VITE_BASE_PATH = http://177.7.0.12
8 |
--------------------------------------------------------------------------------
/web/.env.production:
--------------------------------------------------------------------------------
1 | ENV = 'production'
2 |
3 | VITE_CLI_PORT = 8080
4 | VITE_SERVER_PORT = 8778
5 | VITE_BASE_API = /
6 | #下方修改为你的线上ip
7 | VITE_BASE_PATH = https://127.0.0.1:80
8 |
--------------------------------------------------------------------------------
/web/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | src/assets
3 | public
4 | dist
5 |
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*
2 | package-lock.json
3 | yarn.lock
--------------------------------------------------------------------------------
/web/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:16
2 |
3 | WORKDIR /gva_web/
4 | COPY . .
5 |
6 | RUN yarn && yarn build
7 |
8 | FROM nginx:alpine
9 | LABEL MAINTAINER="SliverHorn@sliver_horn@qq.com"
10 |
11 | COPY .docker-compose/nginx/conf.d/my.conf /etc/nginx/conf.d/my.conf
12 | COPY --from=0 /gva_web/dist /usr/share/nginx/html
13 | RUN cat /etc/nginx/nginx.conf
14 | RUN cat /etc/nginx/conf.d/my.conf
15 | RUN ls -al /usr/share/nginx/html
16 |
--------------------------------------------------------------------------------
/web/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ],
5 | 'plugins': [
6 |
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/web/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/favicon.ico
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/web/limit.js:
--------------------------------------------------------------------------------
1 | // 运行项目前通过node执行此脚本 (此脚本与 node_modules 目录同级)
2 | const fs = require('fs')
3 | const path = require('path')
4 | const wfPath = path.resolve(__dirname, './node_modules/.bin')
5 |
6 | fs.readdir(wfPath, (err, files) => {
7 | if (err) {
8 | console.log(err)
9 | } else {
10 | if (files.length != 0) {
11 | files.forEach((item) => {
12 | if (item.split('.')[1] === 'cmd') {
13 | replaceStr(`${wfPath}/${item}`, /"%_prog%"/, '%_prog%')
14 | }
15 | })
16 | }
17 | }
18 | })
19 |
20 | // 参数:[文件路径、 需要修改的字符串、修改后的字符串] (替换对应文件内字符串的公共函数)
21 | function replaceStr(filePath, sourceRegx, targetSrt) {
22 | fs.readFile(filePath, (err, data) => {
23 | if (err) {
24 | console.log(err)
25 | } else {
26 | let str = data.toString()
27 | str = str.replace(sourceRegx, targetSrt)
28 | fs.writeFile(filePath, str, (err) => {
29 | if(err){
30 | console.log(err)
31 | }else{
32 | console.log("\x1B[42m%s\x1B[0m","文件修改成功")
33 | }
34 | })
35 | }
36 | })
37 | }
--------------------------------------------------------------------------------
/web/openDocument.js:
--------------------------------------------------------------------------------
1 | /*
2 | 商用代码公司自用产品无需授权
3 | 若作为代码出售的产品(任何涉及代码交付第三方作为后续开发)必须保留此脚本
4 | 或标注原作者信息
5 | 否则将依法维权
6 | */
7 |
8 | var child_process = require('child_process')
9 |
10 | var url = 'http://owls.nooncall.cn:8778/docs'
11 | var cmd = ''
12 | console.log(process.platform)
13 | switch (process.platform) {
14 | case 'win32':
15 | cmd = 'start'
16 | child_process.exec(cmd + ' ' + url)
17 | break
18 |
19 | case 'darwin':
20 | cmd = 'open'
21 | child_process.exec(cmd + ' ' + url)
22 | break
23 | }
24 |
--------------------------------------------------------------------------------
/web/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
28 |
--------------------------------------------------------------------------------
/web/src/api/auth/auth.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | export const listAuth = (data, subType) => {
4 | return service({
5 | url: '/auth/list',
6 | method: 'post',
7 | data
8 | })
9 | }
10 |
11 | export const delAuth = (data) => {
12 | return service({
13 | url: '/auth?id=' + data,
14 | method: 'delete',
15 | })
16 | }
17 |
18 | export const createAuth = (data) => {
19 | return service({
20 | url: '/auth',
21 | method: 'post',
22 | data
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/web/src/api/authorityBtn.js:
--------------------------------------------------------------------------------
1 |
2 | import service from '@/utils/request'
3 |
4 | export const getAuthorityBtnApi = (data) => {
5 | return service({
6 | url: '/authorityBtn/getAuthorityBtn',
7 | method: 'post',
8 | data
9 | })
10 | }
11 |
12 | export const setAuthorityBtnApi = (data) => {
13 | return service({
14 | url: '/authorityBtn/setAuthorityBtn',
15 | method: 'post',
16 | data
17 | })
18 | }
19 |
20 | export const canRemoveAuthorityBtnApi = (params) => {
21 | return service({
22 | url: '/authorityBtn/canRemoveAuthorityBtn',
23 | method: 'post',
24 | params
25 | })
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/web/src/api/breakpoint.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Summary 设置角色资源权限
3 | // @Security ApiKeyAuth
4 | // @accept application/json
5 | // @Produce application/json
6 | // @Param data body sysModel.SysAuthority true "设置角色资源权限"
7 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
8 | // @Router /authority/setDataAuthority [post]
9 |
10 | export const findFile = (params) => {
11 | return service({
12 | url: '/fileUploadAndDownload/findFile',
13 | method: 'get',
14 | params
15 | })
16 | }
17 |
18 | export const breakpointContinue = (data) => {
19 | return service({
20 | url: '/fileUploadAndDownload/breakpointContinue',
21 | method: 'post',
22 | headers: { 'Content-Type': 'multipart/form-data' },
23 | data
24 | })
25 | }
26 |
27 | export const breakpointContinueFinish = (params) => {
28 | return service({
29 | url: '/fileUploadAndDownload/breakpointContinueFinish',
30 | method: 'post',
31 | params
32 | })
33 | }
34 |
35 | export const removeChunk = (data, params) => {
36 | return service({
37 | url: '/fileUploadAndDownload/removeChunk',
38 | method: 'post',
39 | data,
40 | params
41 | })
42 | }
43 |
--------------------------------------------------------------------------------
/web/src/api/casbin.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags authority
3 | // @Summary 更改角色api权限
4 | // @Security ApiKeyAuth
5 | // @accept application/json
6 | // @Produce application/json
7 | // @Param data body api.CreateAuthorityPatams true "更改角色api权限"
8 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
9 | // @Router /casbin/UpdateCasbin [post]
10 | export const UpdateCasbin = (data) => {
11 | return service({
12 | url: '/casbin/updateCasbin',
13 | method: 'post',
14 | data
15 | })
16 | }
17 |
18 | // @Tags casbin
19 | // @Summary 获取权限列表
20 | // @Security ApiKeyAuth
21 | // @accept application/json
22 | // @Produce application/json
23 | // @Param data body api.CreateAuthorityPatams true "获取权限列表"
24 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
25 | // @Router /casbin/getPolicyPathByAuthorityId [post]
26 | export const getPolicyPathByAuthorityId = (data) => {
27 | return service({
28 | url: '/casbin/getPolicyPathByAuthorityId',
29 | method: 'post',
30 | data
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/web/src/api/db/cluster.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | export const listCluster = (data) => {
4 | return service({
5 | url: '/db/cluster/list',
6 | method: 'post',
7 | data
8 | })
9 | }
10 |
11 | export const listClusterName = (filter, ctype) => {
12 | return service({
13 | url: '/db/cluster/name/list?filter=' + filter + '&c_type=' + ctype,
14 | method: 'get',
15 | })
16 | }
17 |
18 | export const listDatabase = (cluster, filter) => {
19 | return service({
20 | url: '/db/cluster/db/list?filter=' + filter + '&cluster=' + cluster,
21 | method: 'get',
22 | })
23 | }
24 |
25 | export const listTable = (cluster, db) => {
26 | return service({
27 | url: '/db/cluster/table/list?cluster=' + cluster + '&db=' + db,
28 | method: 'get'
29 | })
30 | }
31 |
32 | export const deleteCluster = (data) => {
33 | return service({
34 | url: '/db/cluster?id=' + data.id,
35 | method: 'delete',
36 | data
37 | })
38 | }
39 |
40 | export const updateCluster = (data) => {
41 | return service({
42 | url: '/db/cluster',
43 | method: 'put',
44 | data
45 | })
46 | }
47 |
48 | export const createCluster = (data) => {
49 | return service({
50 | url: '/db/cluster',
51 | method: 'post',
52 | data
53 | })
54 | }
55 |
--------------------------------------------------------------------------------
/web/src/api/db/read.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | export const readRedisData = (data) => {
4 | return service({
5 | url: '/redis/read',
6 | method: 'post',
7 | data
8 | })
9 | }
10 |
11 |
12 | export const readData = (data) => {
13 | return service({
14 | url: '/db/read',
15 | method: 'post',
16 | data
17 | })
18 | }
19 |
20 | export const getTableInfo = (data) => {
21 | return service({
22 | url: '/db/table',
23 | method: 'post',
24 | data
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/web/src/api/db/rule.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | export const listRedisRule = (data) => {
4 | return service({
5 | url: '/redis/rule/list',
6 | method: 'get',
7 | data
8 | })
9 | }
10 |
11 | export const listRule = (data) => {
12 | return service({
13 | url: '/db/rule/list',
14 | method: 'post',
15 | data
16 | })
17 | }
18 |
19 | export const updateRuleStatus = (data) => {
20 | return service({
21 | url: '/db/rule/status',
22 | method: 'put',
23 | data
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/web/src/api/db/task.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | export const listTask = (data) => {
4 | return service({
5 | url: '/db/task/list',
6 | method: 'post',
7 | data
8 | })
9 | }
10 |
11 | export const listReviewTask = (data) => {
12 | return service({
13 | url: '/db/task/review',
14 | method: 'post',
15 | data
16 | })
17 | }
18 |
19 | export const listHistoryTask = (data) => {
20 | return service({
21 | url: '/db/task/history',
22 | method: 'post',
23 | data
24 | })
25 | }
26 | export const getTask = (data) => {
27 | return service({
28 | url: '/db/task?id=' + data,
29 | method: 'get',
30 | })
31 | }
32 |
33 | export const updateTask = (data) => {
34 | return service({
35 | url: '/db/task',
36 | method: 'put',
37 | data
38 | })
39 | }
40 |
41 | export const createTask = (data) => {
42 | return service({
43 | url: '/db/task',
44 | method: 'post',
45 | data
46 | })
47 | }
48 |
49 | export const listBackup = (data) => {
50 | return service({
51 | url: '/db/backup/list',
52 | method: 'post',
53 | data
54 | })
55 | }
56 |
57 | export const rollback = (data) => {
58 | return service({
59 | url: '/db/backup/rollback',
60 | method: 'post',
61 | data
62 | })
63 | }
64 |
--------------------------------------------------------------------------------
/web/src/api/email.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags email
3 | // @Summary 发送测试邮件
4 | // @Security ApiKeyAuth
5 | // @Produce application/json
6 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
7 | // @Router /email/emailTest [post]
8 | export const emailTest = (data) => {
9 | return service({
10 | url: '/email/emailTest',
11 | method: 'post',
12 | data
13 | })
14 | }
15 |
--------------------------------------------------------------------------------
/web/src/api/fileUploadAndDownload.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags FileUploadAndDownload
3 | // @Summary 分页文件列表
4 | // @Security ApiKeyAuth
5 | // @accept application/json
6 | // @Produce application/json
7 | // @Param data body modelInterface.PageInfo true "分页获取文件户列表"
8 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
9 | // @Router /fileUploadAndDownload/getFileList [post]
10 | export const getFileList = (data) => {
11 | return service({
12 | url: '/fileUploadAndDownload/getFileList',
13 | method: 'post',
14 | data
15 | })
16 | }
17 |
18 | // @Tags FileUploadAndDownload
19 | // @Summary 删除文件
20 | // @Security ApiKeyAuth
21 | // @Produce application/json
22 | // @Param data body dbModel.FileUploadAndDownload true "传入文件里面id即可"
23 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"返回成功"}"
24 | // @Router /fileUploadAndDownload/deleteFile [post]
25 | export const deleteFile = (data) => {
26 | return service({
27 | url: '/fileUploadAndDownload/deleteFile',
28 | method: 'post',
29 | data
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/web/src/api/github.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | const service = axios.create()
4 |
5 | export function Commits(page) {
6 | return service({
7 | url: 'https://api.github.com/repos/flipped-aurora/gin-vue-admin/commits?page=' + page,
8 | method: 'get'
9 | })
10 | }
11 |
12 | export function Members() {
13 | return service({
14 | url: 'https://api.github.com/orgs/FLIPPED-AURORA/members',
15 | method: 'get'
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/web/src/api/initdb.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags InitDB
3 | // @Summary 初始化用户数据库
4 | // @Produce application/json
5 | // @Param data body request.InitDB true "初始化数据库参数"
6 | // @Success 200 {string} string "{"code":0,"data":{},"msg":"自动创建数据库成功"}"
7 | // @Router /init/initdb [post]
8 | export const initDB = (data) => {
9 | return service({
10 | url: '/init/initdb',
11 | method: 'post',
12 | data
13 | })
14 | }
15 |
16 | // @Tags CheckDB
17 | // @Summary 初始化用户数据库
18 | // @Produce application/json
19 | // @Success 200 {string} string "{"code":0,"data":{},"msg":"探测完成"}"
20 | // @Router /init/checkdb [post]
21 | export const checkDB = () => {
22 | return service({
23 | url: '/init/checkdb',
24 | method: 'post'
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/web/src/api/jwt.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags jwt
3 | // @Summary jwt加入黑名单
4 | // @Security ApiKeyAuth
5 | // @accept application/json
6 | // @Produce application/json
7 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"拉黑成功"}"
8 | // @Router /jwt/jsonInBlacklist [post]
9 | export const jsonInBlacklist = () => {
10 | return service({
11 | url: '/jwt/jsonInBlacklist',
12 | method: 'post'
13 | })
14 | }
15 |
--------------------------------------------------------------------------------
/web/src/api/system.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags systrm
3 | // @Summary 获取配置文件内容
4 | // @Security ApiKeyAuth
5 | // @Produce application/json
6 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
7 | // @Router /system/getSystemConfig [post]
8 | export const getSystemConfig = () => {
9 | return service({
10 | url: '/system/getSystemConfig',
11 | method: 'post'
12 | })
13 | }
14 |
15 | // @Tags system
16 | // @Summary 设置配置文件内容
17 | // @Security ApiKeyAuth
18 | // @Produce application/json
19 | // @Param data body sysModel.System true
20 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
21 | // @Router /system/setSystemConfig [post]
22 | export const setSystemConfig = (data) => {
23 | return service({
24 | url: '/system/setSystemConfig',
25 | method: 'post',
26 | data
27 | })
28 | }
29 |
30 | // @Tags system
31 | // @Summary 获取服务器运行状态
32 | // @Security ApiKeyAuth
33 | // @Produce application/json
34 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
35 | // @Router /system/getServerInfo [post]
36 | export const getSystemState = () => {
37 | return service({
38 | url: '/system/getServerInfo',
39 | method: 'post',
40 | donNotShowLoading: true
41 | })
42 | }
43 |
--------------------------------------------------------------------------------
/web/src/api/task/task.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | export const listTask = (data, subType) => {
4 | return service({
5 | url: '/task/list?type=' + subType,
6 | method: 'post',
7 | data
8 | })
9 | }
10 |
11 | export const listReviewTask = (data, subType) => {
12 | return service({
13 | url: '/task/review?type=' + subType,
14 | method: 'post',
15 | data
16 | })
17 | }
18 |
19 | export const listHistoryTask = (data, subType) => {
20 | return service({
21 | url: '/task/history?type=' + subType,
22 | method: 'post',
23 | data
24 | })
25 | }
26 | export const getTask = (data, subType) => {
27 | return service({
28 | url: '/task?id=' + data + '&type=' + subType,
29 | method: 'get',
30 | })
31 | }
32 |
33 | export const updateTask = (data) => {
34 | return service({
35 | url: '/task',
36 | method: 'put',
37 | data
38 | })
39 | }
40 |
41 | export const createTask = (data) => {
42 | return service({
43 | url: '/task',
44 | method: 'post',
45 | data
46 | })
47 | }
48 |
--------------------------------------------------------------------------------
/web/src/assets/dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/dashboard.png
--------------------------------------------------------------------------------
/web/src/assets/docs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/docs.png
--------------------------------------------------------------------------------
/web/src/assets/flipped-aurora.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/flipped-aurora.png
--------------------------------------------------------------------------------
/web/src/assets/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/github.png
--------------------------------------------------------------------------------
/web/src/assets/kefu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/kefu.png
--------------------------------------------------------------------------------
/web/src/assets/login_background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/login_background.jpg
--------------------------------------------------------------------------------
/web/src/assets/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/logo.jpg
--------------------------------------------------------------------------------
/web/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/logo.png
--------------------------------------------------------------------------------
/web/src/assets/logo_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/logo_login.png
--------------------------------------------------------------------------------
/web/src/assets/nav_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/nav_logo.png
--------------------------------------------------------------------------------
/web/src/assets/noBody.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/noBody.png
--------------------------------------------------------------------------------
/web/src/assets/notFound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/notFound.png
--------------------------------------------------------------------------------
/web/src/assets/qm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/qm.png
--------------------------------------------------------------------------------
/web/src/assets/video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/assets/video.png
--------------------------------------------------------------------------------
/web/src/components/warningBar/warningBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 | {{ title }}
10 |
11 |
12 |
13 |
22 |
42 |
--------------------------------------------------------------------------------
/web/src/core/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 网站配置文件
3 | */
4 |
5 | const config = {
6 | appName: 'Owls',
7 | // todo, set a better image addr
8 | appLogo: 'https://img0.baidu.com/it/u=2822765666,2555722031&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=501',
9 | showViteLogo: true
10 | }
11 |
12 | export const viteLogo = (env) => {
13 | if (config.showViteLogo) {
14 | const chalk = require('chalk')
15 | console.log(
16 | chalk.green(
17 | `> 欢迎使用Owls,开源地址:https://github.com/qingfeng777/owls`
18 | )
19 | )
20 | console.log(
21 | chalk.green(
22 | `> 当前版本:V0.0.1`
23 | )
24 | )
25 | console.log(
26 | chalk.green(
27 | `> 加群方式:微信:xxxx QQ群:xxxx`
28 | )
29 | )
30 | console.log(
31 | chalk.green(
32 | `> 默认自动化文档地址:http://127.0.0.1:${env.VITE_SERVER_PORT}/swagger/index.html`
33 | )
34 | )
35 | console.log(
36 | chalk.green(
37 | `> 默认前端文件运行地址:http://127.0.0.1:${env.VITE_CLI_PORT}`
38 | )
39 | )
40 | console.log(
41 | chalk.green(
42 | `> 如果项目让您获得了收益,那就帮忙宣传一下吧!`
43 | )
44 | )
45 | console.log('\n')
46 | }
47 | }
48 |
49 | export default config
50 |
--------------------------------------------------------------------------------
/web/src/core/gin-vue-admin.js:
--------------------------------------------------------------------------------
1 | /*
2 | * owls
3 | *
4 | * */
5 | // 加载网站配置文件夹
6 | import { register } from './global'
7 |
8 | export default {
9 | install: (app) => {
10 | register(app)
11 | console.log(`
12 | 欢迎使用 owls
13 | 当前版本:V0.3.0
14 | 加群方式:微信:grsixk
15 | 默认自动化文档地址:http://127.0.0.1:${import.meta.env.VITE_SERVER_PORT}/swagger/index.html
16 | 默认前端文件运行地址:http://127.0.0.1:${import.meta.env.VITE_CLI_PORT}
17 | 如果项目让您获得了收益,希望您能帮忙宣传下
18 | `)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/web/src/core/global.js:
--------------------------------------------------------------------------------
1 | import config from './config'
2 | import { emitter } from '@/utils/bus.js'
3 |
4 | // 统一导入el-icon图标
5 | import * as ElIconModules from '@element-plus/icons-vue'
6 | // 导入转换图标名称的函数
7 |
8 | export const closeThisPage = () => {
9 | emitter.emit('closeThisPage')
10 | }
11 |
12 | export const register = (app) => {
13 | // 统一注册el-icon图标
14 | for (const iconName in ElIconModules) {
15 | app.component(iconName, ElIconModules[iconName])
16 | }
17 | app.config.globalProperties.$GIN_VUE_ADMIN = config
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/directive/auth.js:
--------------------------------------------------------------------------------
1 | // 权限按钮展示指令
2 | import { useUserStore } from '@/pinia/modules/user'
3 | export default {
4 | install: (app) => {
5 | const userStore = useUserStore()
6 | app.directive('auth', {
7 | // 当被绑定的元素插入到 DOM 中时……
8 | mounted: function(el, binding) {
9 | const userInfo = userStore.userInfo
10 | let type = ''
11 | switch (Object.prototype.toString.call(binding.value)) {
12 | case '[object Array]':
13 | type = 'Array'
14 | break
15 | case '[object String]':
16 | type = 'String'
17 | break
18 | case '[object Number]':
19 | type = 'Number'
20 | break
21 | default:
22 | type = ''
23 | break
24 | }
25 | if (type === '') {
26 | el.parentNode.removeChild(el)
27 | return
28 | }
29 | const waitUse = binding.value.toString().split(',')
30 | let flag = waitUse.some(item => item === userInfo.authorityId)
31 | if (binding.modifiers.not) {
32 | flag = !flag
33 | }
34 | if (!flag) {
35 | el.parentNode.removeChild(el)
36 | }
37 | }
38 | })
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/web/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import 'element-plus/dist/index.css'
3 | import './style/element_visiable.scss'
4 | import ElementPlus from 'element-plus'
5 | import zhCn from 'element-plus/es/locale/lang/zh-cn'
6 | // 引入gin-vue-admin前端初始化相关内容
7 | import './core/gin-vue-admin'
8 | // 引入封装的router
9 | import router from '@/router/index'
10 | import '@/permission'
11 | import run from '@/core/gin-vue-admin.js'
12 | import auth from '@/directive/auth'
13 | import { store } from '@/pinia'
14 | import App from './App.vue'
15 | const app = createApp(App)
16 | app.config.productionTip = false
17 |
18 | app
19 | .use(run)
20 | .use(store)
21 | .use(auth)
22 | .use(router)
23 | .use(ElementPlus, { locale: zhCn })
24 | .mount('#app')
25 |
26 | export default app
27 |
--------------------------------------------------------------------------------
/web/src/pinia/index.js:
--------------------------------------------------------------------------------
1 | import { createPinia } from 'pinia'
2 |
3 | const store = createPinia()
4 |
5 | export {
6 | store
7 | }
8 |
--------------------------------------------------------------------------------
/web/src/pinia/modules/dictionary.js:
--------------------------------------------------------------------------------
1 | import { findSysDictionary } from '@/api/sysDictionary'
2 |
3 | import { defineStore } from 'pinia'
4 | import { ref } from 'vue'
5 |
6 | export const useDictionaryStore = defineStore('dictionary', () => {
7 | const dictionaryMap = ref({})
8 |
9 | const setDictionaryMap = (dictionaryRes) => {
10 | dictionaryMap.value = { ...dictionaryMap.value, ...dictionaryRes }
11 | }
12 |
13 | const getDictionary = async(type) => {
14 | if (dictionaryMap.value[type] && dictionaryMap.value[type].length) {
15 | return dictionaryMap.value[type]
16 | } else {
17 | const res = await findSysDictionary({ type })
18 | if (res.code === 0) {
19 | const dictionaryRes = {}
20 | const dict = []
21 | res.data.resysDictionary.sysDictionaryDetails && res.data.resysDictionary.sysDictionaryDetails.forEach(item => {
22 | dict.push({
23 | label: item.label,
24 | value: item.value
25 | })
26 | })
27 | dictionaryRes[res.data.resysDictionary.type] = dict
28 | setDictionaryMap(dictionaryRes)
29 | return dictionaryMap.value[type]
30 | }
31 | }
32 | }
33 |
34 | return {
35 | dictionaryMap,
36 | setDictionaryMap,
37 | getDictionary
38 | }
39 | })
40 |
--------------------------------------------------------------------------------
/web/src/router/index.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHashHistory } from 'vue-router'
2 |
3 | const routes = [{
4 | path: '/',
5 | name: 'root',
6 | redirect: '/login'
7 | },
8 | {
9 | path: '/init',
10 | name: 'Init',
11 | component: () => import('@/view/init/index.vue')
12 | },
13 | {
14 | path: '/login',
15 | name: 'Login',
16 | component: () => import('@/view/login/index.vue')
17 | }
18 | ]
19 |
20 | const router = createRouter({
21 | history: createWebHashHistory(),
22 | routes
23 | })
24 |
25 | export default router
26 |
--------------------------------------------------------------------------------
/web/src/style/base.scss:
--------------------------------------------------------------------------------
1 | .clearflex {
2 | *zoom: 1;
3 | }
4 |
5 | .clearflex:after {
6 | content: '';
7 | display: block;
8 | height: 0;
9 | visibility: hidden;
10 | clear: both;
11 | }
12 |
13 | .fl-left {
14 | float: left;
15 | }
16 |
17 | .fl-right {
18 | float: right;
19 | }
20 |
21 | .mg {
22 | margin: 10px !important;
23 | }
24 |
25 | .left-mg-xs {
26 | margin-left: 6px !important;
27 | }
28 |
29 | .left-mg-sm {
30 | margin-left: 10px !important;
31 | }
32 |
33 | .left-mg-md {
34 | margin-left: 14px !important;
35 | }
36 |
37 | .top-mg-lg {
38 | margin-top: 20px !important;
39 | }
40 |
41 | .tb-mg-lg {
42 | margin: 20px 0 !important;
43 | }
44 |
45 | .bottom-mg-lg {
46 | margin-bottom: 20px !important;
47 | }
48 |
49 | .left-mg-lg {
50 | margin-left: 18px !important;
51 | }
52 |
53 | .title-1 {
54 | text-align: center;
55 | font-size: 32px;
56 | }
57 |
58 | .title-3 {
59 | text-align: center;
60 | }
61 |
--------------------------------------------------------------------------------
/web/src/style/basics.scss:
--------------------------------------------------------------------------------
1 | // basice
2 | $font-size: 14px;
3 | $icon-size:18px;
4 | $active-color:#1890ff;
5 | $bg-main:#f0f2f5;
6 | $border-color: #f4f4f4;
7 | $white-bg:#fff;
8 | $el-icon-small:30px;
9 | $el-icon-mini:24px;
10 | // aside
11 | $width-aside:220px;
12 | $width-hideside-aside:54px;
13 | $width-mobile-aside:210px;
14 | $color-aside:rgba(255, 255, 255, .9);
15 | $icon-arrow-size-aside:12px;
16 | $width-submenu-aside:55px;
17 | $height-aside-tilte:60px;
18 | $height-aside-img:30px;
19 | $width-aside-img:30px;
20 | // header
21 | $height-header: 60px;
22 | // nav-scroll
23 | $height-nav-scroll:40px;
24 | $active-bg-tabs-item-nav-scroll:#409eff;
25 | $bg-tabs-item-nav-scroll:#ddd;
26 | // table
27 | $bg-color-table-thead:#fafafa;
28 | $border-color-table:#ededed;
29 | $height-table-cell:45px;
30 | $color-table-tbody:#595959;
31 | $color-table-thead:#262626;
32 | // dashboard
33 | $height-car:68px;
34 | // mobile
35 | $padding-xs: 5px;
36 | $margin-xs: 5px;
--------------------------------------------------------------------------------
/web/src/style/init.sass:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nooncall/owls/73f8a9ca53babede1d74790766883082c02fe0dc/web/src/style/init.sass
--------------------------------------------------------------------------------
/web/src/utils/asyncRouter.js:
--------------------------------------------------------------------------------
1 | const modules = import.meta.glob('../view/**/*.vue')
2 |
3 | export const asyncRouterHandle = (asyncRouter) => {
4 | asyncRouter.forEach(item => {
5 | if (item.component) {
6 | item.component = dynamicImport(modules, item.component)
7 | } else {
8 | delete item['component']
9 | }
10 | if (item.children) {
11 | asyncRouterHandle(item.children)
12 | }
13 | })
14 | }
15 |
16 | function dynamicImport(
17 | dynamicViewsModules,
18 | component
19 | ) {
20 | const keys = Object.keys(dynamicViewsModules)
21 | const matchKeys = keys.filter((key) => {
22 | const k = key.replace('../', '')
23 | return k === component
24 | })
25 | const matchKey = matchKeys[0]
26 |
27 | return dynamicViewsModules[matchKey]
28 | }
29 |
--------------------------------------------------------------------------------
/web/src/utils/btnAuth.js:
--------------------------------------------------------------------------------
1 | import { useRoute } from 'vue-router'
2 | import {reactive }from 'vue'
3 | export const useBtnAuth = () => {
4 | const route = useRoute()
5 | return route.meta.btns || reactive({})
6 | }
7 |
--------------------------------------------------------------------------------
/web/src/utils/bus.js:
--------------------------------------------------------------------------------
1 |
2 | // using ES6 modules
3 | import mitt from 'mitt'
4 |
5 | export const emitter = mitt()
6 |
7 |
--------------------------------------------------------------------------------
/web/src/utils/date.js:
--------------------------------------------------------------------------------
1 | // 对Date的扩展,将 Date 转化为指定格式的String
2 | // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
3 | // 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
4 | // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
5 | // (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
6 | // eslint-disable-next-line no-extend-native
7 | Date.prototype.Format = function(fmt) {
8 | var o = {
9 | 'M+': this.getMonth() + 1, // 月份
10 | 'd+': this.getDate(), // 日
11 | 'h+': this.getHours(), // 小时
12 | 'm+': this.getMinutes(), // 分
13 | 's+': this.getSeconds(), // 秒
14 | 'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
15 | 'S': this.getMilliseconds() // 毫秒
16 | }
17 | if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length)) }
18 | for (var k in o) {
19 | if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))) }
20 | }
21 | return fmt
22 | }
23 |
24 | export function formatTimeToStr(times, pattern) {
25 | var d = new Date(times).Format('yyyy-MM-dd hh:mm:ss')
26 | if (pattern) {
27 | d = new Date(times).Format(pattern)
28 | }
29 | return d.toLocaleString()
30 | }
31 |
--------------------------------------------------------------------------------
/web/src/utils/dictionary.js:
--------------------------------------------------------------------------------
1 | import { useDictionaryStore } from '@/pinia/modules/dictionary'
2 | // 获取字典方法 使用示例 getDict('sex').then(res) 或者 async函数下 const res = await getDict('sex')
3 | export const getDict = async(type) => {
4 | const dictionaryStore = useDictionaryStore()
5 | await dictionaryStore.getDictionary(type)
6 | return dictionaryStore.dictionaryMap[type]
7 | }
8 |
--------------------------------------------------------------------------------
/web/src/utils/downloadImg.js:
--------------------------------------------------------------------------------
1 | export const downloadImage = (imgsrc, name) => { // 下载图片地址和图片名
2 | var image = new Image()
3 | image.setAttribute('crossOrigin', 'anonymous')
4 | image.onload = function() {
5 | var canvas = document.createElement('canvas')
6 | canvas.width = image.width
7 | canvas.height = image.height
8 | var context = canvas.getContext('2d')
9 | context.drawImage(image, 0, 0, image.width, image.height)
10 | var url = canvas.toDataURL('image/png') // 得到图片的base64编码数据
11 |
12 | var a = document.createElement('a') // 生成一个a元素
13 | var event = new MouseEvent('click') // 创建一个单击事件
14 | a.download = name || 'photo' // 设置图片名称
15 | a.href = url // 将生成的URL设置为a.href属性
16 | a.dispatchEvent(event) // 触发a的单击事件
17 | }
18 | image.src = imgsrc
19 | }
20 |
--------------------------------------------------------------------------------
/web/src/utils/format.js:
--------------------------------------------------------------------------------
1 | import { formatTimeToStr } from '@/utils/date'
2 | import { getDict } from '@/utils/dictionary'
3 |
4 | export const formatBoolean = (bool) => {
5 | if (bool !== null) {
6 | return bool ? '是' : '否'
7 | } else {
8 | return ''
9 | }
10 | }
11 | export const formatDate = (time) => {
12 | if (time !== null && time !== '') {
13 | var date = new Date(time)
14 | return formatTimeToStr(date, 'yyyy-MM-dd hh:mm:ss')
15 | } else {
16 | return ''
17 | }
18 | }
19 |
20 | export const filterDict = (value, options) => {
21 | const rowLabel = options && options.filter(item => item.value === value)
22 | return rowLabel && rowLabel[0] && rowLabel[0].label
23 | }
24 |
25 | export const getDictFunc = async(type) => {
26 | const dicts = await getDict(type)
27 | return dicts
28 | }
29 |
--------------------------------------------------------------------------------
/web/src/utils/page.js:
--------------------------------------------------------------------------------
1 | import config from '@/core/config'
2 | export default function getPageTitle(pageTitle) {
3 | if (pageTitle) {
4 | return `${pageTitle} - ${config.appName}`
5 | }
6 | return `${config.appName}`
7 | }
8 |
--------------------------------------------------------------------------------
/web/src/utils/stringFun.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export const toUpperCase = (str) => {
3 | if (str[0]) {
4 | return str.replace(str[0], str[0].toUpperCase())
5 | } else {
6 | return ''
7 | }
8 | }
9 |
10 | export const toLowerCase = (str) => {
11 | if (str[0]) {
12 | return str.replace(str[0], str[0].toLowerCase())
13 | } else {
14 | return ''
15 | }
16 | }
17 |
18 | // 驼峰转换下划线
19 | export const toSQLLine = (str) => {
20 | if (str === 'ID') return 'ID'
21 | return str.replace(/([A-Z])/g, "_$1").toLowerCase();
22 | }
23 |
24 | // 下划线转换驼峰
25 | export const toHump = (name) => {
26 | return name.replace(/\_(\w)/g, function(all, letter) {
27 | return letter.toUpperCase();
28 | });
29 | }
--------------------------------------------------------------------------------
/web/src/view/auth/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
22 | // 申请页,列表、创建、撤销
23 | // 审批页,简单通过或拒绝,无历史页
24 |
25 | // 初始化名改为管理员角色,管理员拥有所有权限
26 |
27 | // auth: 列表、添加、删除。
28 |
29 | // 然后就可以写查询啦!
30 |
--------------------------------------------------------------------------------
/web/src/view/error/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |

6 |
页面被神秘力量吸走了(如果您是开源版请联系我们修复)
7 |
常见问题为当前此角色无当前路由,如果确定要使用本路由,请到角色管理进行分配
8 |
↓
9 |

10 |
11 |
12 |
13 |
14 |
15 |
21 |
22 |
46 |
--------------------------------------------------------------------------------
/web/src/view/error/reload.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
--------------------------------------------------------------------------------
/web/src/view/example/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
22 |
--------------------------------------------------------------------------------
/web/src/view/layout/aside/asideComponent/asyncSubmenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ routerInfo.meta.title }}
8 |
9 |
10 |
11 |
12 |
13 |
18 |
19 |
29 |
--------------------------------------------------------------------------------
/web/src/view/layout/aside/asideComponent/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
15 |
35 |
36 |
--------------------------------------------------------------------------------
/web/src/view/layout/aside/asideComponent/menuItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
17 |
18 |
28 |
29 |
34 |
--------------------------------------------------------------------------------
/web/src/view/layout/bottomInfo/bottomInfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
26 |
27 |
44 |
--------------------------------------------------------------------------------
/web/src/view/redis/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
22 |
--------------------------------------------------------------------------------
/web/src/view/routerHolder.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
24 |
--------------------------------------------------------------------------------
/web/src/view/superAdmin/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
22 |
--------------------------------------------------------------------------------
/web/src/view/systemTools/formCreate/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/web/src/view/systemTools/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
22 |
--------------------------------------------------------------------------------
/web/src/view/tidbOrMysql/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
22 |
--------------------------------------------------------------------------------