├── .env.development
├── .env.production
├── README.MD
├── package.json
├── public
└── index.html
├── readme
├── 00c7a5fd.png
└── 33408b0f.png
├── src
├── App.tsx
├── assets
│ └── style.css
├── components
│ ├── Content.tsx
│ ├── ContentForm.tsx
│ └── NavBar.tsx
├── index.tsx
└── utils
│ └── custom-icon.tsx
└── tsconfig.json
/.env.development:
--------------------------------------------------------------------------------
1 | REACT_APP_API_BASE_URL = http://127.0.0.1:5000/
2 |
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | GENERATE_SOURCEMAP = false
2 | REACT_APP_API_BASE_URL = /
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | # 😲 `gsuite-user-auto-create`
2 |
3 | [](https://forthebadge.com)
4 |
5 | 
6 | 
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gsuite-user-auto-create",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@ant-design/icons": "^4.4.0",
7 | "@testing-library/jest-dom": "^5.11.9",
8 | "@testing-library/react": "^11.2.3",
9 | "@testing-library/user-event": "^12.6.2",
10 | "@types/jest": "^26.0.20",
11 | "@types/node": "^12.19.15",
12 | "@types/react": "^16.14.2",
13 | "@types/react-dom": "^16.9.10",
14 | "antd": "^4.10.3",
15 | "axios": "^0.21.1",
16 | "copy-to-clipboard": "^3.3.1",
17 | "react": "^17.0.1",
18 | "react-dom": "^17.0.1",
19 | "react-scripts": "4.0.1",
20 | "typescript": "^4.1.3",
21 | "web-vitals": "^0.2.4"
22 | },
23 | "scripts": {
24 | "start": "react-scripts start",
25 | "build": "react-scripts build",
26 | "test": "react-scripts test",
27 | "eject": "react-scripts eject"
28 | },
29 | "eslintConfig": {
30 | "extends": [
31 | "react-app",
32 | "react-app/jest"
33 | ]
34 | },
35 | "browserslist": {
36 | "production": [
37 | ">0.2%",
38 | "not dead",
39 | "not op_mini all"
40 | ],
41 | "development": [
42 | "last 1 chrome version",
43 | "last 1 firefox version",
44 | "last 1 safari version"
45 | ]
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
13 | Google Workspace
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/readme/00c7a5fd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realByg/gsuite-user-auto-create/82cb8a75327cf50c81108ca0c0a0a33c0b19c8a1/readme/00c7a5fd.png
--------------------------------------------------------------------------------
/readme/33408b0f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realByg/gsuite-user-auto-create/82cb8a75327cf50c81108ca0c0a0a33c0b19c8a1/readme/33408b0f.png
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Layout} from 'antd'
3 |
4 | import NavBar from './components/NavBar'
5 | import Content from './components/Content'
6 |
7 | export default function App() {
8 | return (
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | )
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/src/assets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | overflow: hidden;
6 | height: 100vh;
7 | width: 100% !important
8 | }
9 |
10 | .background-white {
11 | background-color: #ffffff;
12 | }
13 |
14 | .text-white {
15 | color: #ffffff;
16 | }
17 |
18 | .justify-between {
19 | justify-content: space-between;
20 | }
21 |
22 | .justify-around {
23 | justify-content: space-around;
24 | }
25 |
26 | .align-center {
27 | align-items: center;
28 | }
29 |
30 | .display-flex {
31 | display: flex;
32 | }
33 |
34 | .text-center {
35 | text-align: center;
36 | }
37 |
38 | .lineOneFont {
39 | font-size: 60px;
40 | font-weight: 700;
41 | color: #ffffff
42 | }
43 |
44 | .lineTwoFont {
45 | font-size: 50px;
46 | font-weight: 400;
47 | color: #ffffff
48 | }
49 |
50 | @media screen and (max-width: 600px) {
51 | .hide-on-small {
52 | display: none;
53 | }
54 |
55 | .lineOneFont {
56 | font-size: 30px;
57 | }
58 |
59 | .lineTwoFont {
60 | font-size: 20px;
61 | font-weight: 300
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/components/Content.tsx:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react'
2 | import {Row, Col, Button, Space, Modal} from 'antd'
3 |
4 | import ContentForm from './ContentForm'
5 |
6 | export default function Content() {
7 | const contentBg = {
8 | background: 'url(https://i.loli.net/2020/01/22/Rgv3xJAVYN4n9Za.png) no-repeat',
9 | backgroundSize: 'cover',
10 | backgroundPosition: 'center',
11 | backgroundRepeat: 'no-repeat',
12 | height: '100vh'
13 | }
14 |
15 | const [modalVisible, setModalVisible] = useState(false)
16 |
17 | return (
18 |
19 |
23 |
24 |
25 | Google Workspace
26 |
27 |
28 |
29 |
30 |
31 | 您所需的一切工具,都汇集在这里。
32 |
33 |
34 |
35 |
36 |
37 |
38 |
47 |
48 | setModalVisible(false)}
57 | >
58 |
59 |
60 |
61 |
70 |
71 |
72 |
73 |
74 | )
75 | }
76 |
--------------------------------------------------------------------------------
/src/components/ContentForm.tsx:
--------------------------------------------------------------------------------
1 | import React, {useState, useEffect} from 'react'
2 | import {Spin, Form, Button, Input, message, Row, Col, Select} from 'antd'
3 | import {CopyOutlined, KeyOutlined, MailOutlined} from '@ant-design/icons'
4 | import copy from 'copy-to-clipboard'
5 | import axios from 'axios'
6 |
7 |
8 | export default function ContentForm() {
9 | const [spinning, setSpinning] = useState(false)
10 | const [gsConfig, setGsConfig] = useState([
11 | {
12 | domains: [],
13 | id: '0',
14 | name: '',
15 | },
16 | ])
17 | const [domains, setDomains] = useState([])
18 | const [createdAccount, setCreatedAccount] = useState({
19 | email: '',
20 | password: '',
21 | })
22 | const [form] = Form.useForm()
23 |
24 | const createUser = (formData: object) => {
25 | setSpinning(true)
26 | axios({
27 | method: 'post',
28 | url: 'createUser',
29 | baseURL: process.env.REACT_APP_API_BASE_URL,
30 | data: formData,
31 | })
32 | .then(async (r: any) => {
33 | if (r.data.success) {
34 | message.success('账号创建成功')
35 | setCreatedAccount({
36 | email: r.data.account.primaryEmail,
37 | password: r.data.account.password,
38 | })
39 | } else {
40 | message.error(r.data.msg)
41 | form.resetFields()
42 | }
43 | })
44 | .catch(async (e: any) => {
45 | message.error(e)
46 | })
47 | .then(() => {
48 | setSpinning(false)
49 | })
50 | }
51 |
52 | useEffect(() => {
53 | setSpinning(true)
54 | axios({
55 | method: 'post',
56 | url: 'getGSConfig',
57 | baseURL: process.env.REACT_APP_API_BASE_URL,
58 | })
59 | .then((r: any) => {
60 | setGsConfig(r.data)
61 | })
62 | .catch(async (e: any) => {
63 | message.error(e)
64 | })
65 | .then(() => {
66 | setSpinning(false)
67 | })
68 | }, [])
69 |
70 | useEffect(() => {
71 | form.setFieldsValue({
72 | 'email': {
73 | 'domain': domains[0]
74 | }
75 | })
76 | }, [domains, form])
77 |
78 | const CreatedForm = (
79 |
84 | }
87 | suffix={ {
89 | copy(createdAccount.email)
90 | message.success('已复制邮箱')
91 | }}
92 | />}
93 | />
94 |
95 |
96 |
97 | }
100 | suffix={ {
102 | copy(createdAccount.password)
103 | message.success('已复制密码')
104 | }}
105 | />}
106 | />
107 |
108 |
109 |
110 |
118 |
119 |
120 | )
121 |
122 | const CreateForm = (
123 |
135 |
153 |
154 |
155 |
163 |
164 |
176 |
181 |
182 |
183 |
188 |
203 |
204 |
205 |
206 |
207 |
217 | 获取激活码
224 | // )}
225 | />
226 |
227 |
228 |
229 |
235 |
236 |
237 | )
238 |
239 |
240 | return (
241 |
242 |
243 |
247 | {!!createdAccount.password ? CreatedForm : CreateForm}
248 |
249 |
250 |
251 | )
252 | }
253 |
--------------------------------------------------------------------------------
/src/components/NavBar.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Row, Col, Space} from 'antd'
3 | import CustomIcon from '../utils/custom-icon'
4 |
5 | export default function NavBar() {
6 | const gsFont = {
7 | fontWeight: 500,
8 | fontSize: 24
9 | }
10 |
11 | return (
12 |
13 |
16 |
17 |
18 |
23 |
24 |
28 | |
29 |
30 |
31 |
35 | Google Workspace
36 |
37 |
38 |
39 |
40 |
47 |
48 |
54 |
55 |
61 |
62 |
68 |
69 |
76 |
77 |
84 |
85 |
86 |
87 |
88 | )
89 | }
90 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 |
5 | import 'antd/dist/antd.css'
6 | import './assets/style.css'
7 |
8 | ReactDOM.render(
9 | ,
10 | document.getElementById('root')
11 | )
12 |
--------------------------------------------------------------------------------
/src/utils/custom-icon.tsx:
--------------------------------------------------------------------------------
1 | import {createFromIconfontCN} from '@ant-design/icons'
2 |
3 | export default createFromIconfontCN({
4 | scriptUrl: 'https://at.alicdn.com/t/font_2344266_q4e9zpytr8a.js'
5 | })
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react-jsx"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------