├── .dockerignore ├── .gitignore ├── LICENSE ├── README.md ├── deploy ├── client-web │ ├── Dockerfile │ └── nginx.conf ├── server-api │ ├── Dockerfile │ └── config.default.json └── server-client │ ├── Dockerfile │ └── config.default.json ├── packages ├── client-web │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── src │ │ ├── api │ │ │ ├── axios-ins.ts │ │ │ ├── detail │ │ │ │ ├── account.ts │ │ │ │ ├── domain.ts │ │ │ │ ├── group.ts │ │ │ │ ├── member.ts │ │ │ │ └── project.ts │ │ │ └── index.ts │ │ ├── component │ │ │ ├── category-detail │ │ │ │ └── category-detail.tsx │ │ │ ├── layout │ │ │ │ ├── page-layout │ │ │ │ │ ├── component │ │ │ │ │ │ ├── footer │ │ │ │ │ │ │ ├── footer.module.less │ │ │ │ │ │ │ └── footer.tsx │ │ │ │ │ │ └── header │ │ │ │ │ │ │ └── header.tsx │ │ │ │ │ └── index.tsx │ │ │ │ └── wide-layout │ │ │ │ │ ├── wide-layout.module.less │ │ │ │ │ └── wide-layout.tsx │ │ │ └── qrcode │ │ │ │ └── qrcode.tsx │ │ ├── index.tsx │ │ ├── interface │ │ │ ├── client-api │ │ │ │ ├── domain.interface.ts │ │ │ │ ├── group.interface.ts │ │ │ │ ├── member.interface.ts │ │ │ │ └── project.interface.ts │ │ │ └── constants.ts │ │ ├── page │ │ │ ├── component │ │ │ │ ├── create-project-modal │ │ │ │ │ └── create-project-modal.tsx │ │ │ │ └── project-list-card │ │ │ │ │ ├── project-item │ │ │ │ │ ├── project-item.module.less │ │ │ │ │ └── project-item.tsx │ │ │ │ │ └── project-list-card.tsx │ │ │ ├── group │ │ │ │ ├── group-detail │ │ │ │ │ ├── group-holder │ │ │ │ │ │ └── group-holder.tsx │ │ │ │ │ ├── group-layout-store.ts │ │ │ │ │ ├── group-layout.tsx │ │ │ │ │ ├── group-project │ │ │ │ │ │ ├── group-project-store.ts │ │ │ │ │ │ └── group-project.tsx │ │ │ │ │ └── group-settiing │ │ │ │ │ │ ├── group-setting-advance │ │ │ │ │ │ ├── group-setting-advance-store.ts │ │ │ │ │ │ └── group-setting-advance.tsx │ │ │ │ │ │ ├── group-setting-common │ │ │ │ │ │ ├── group-setting-common-store.ts │ │ │ │ │ │ └── group-setting-common.tsx │ │ │ │ │ │ ├── group-setting-member │ │ │ │ │ │ ├── group-role-select │ │ │ │ │ │ │ └── group-role-select.tsx │ │ │ │ │ │ ├── group-setting-member-store.ts │ │ │ │ │ │ └── group-setting-member.tsx │ │ │ │ │ │ ├── group-setting-store.ts │ │ │ │ │ │ ├── group-setting.module.less │ │ │ │ │ │ └── group-setting.tsx │ │ │ │ └── group-list │ │ │ │ │ ├── components │ │ │ │ │ └── create-group-modal │ │ │ │ │ │ └── create-group-modal.tsx │ │ │ │ │ ├── group-list.store.ts │ │ │ │ │ └── group-list.tsx │ │ │ └── project │ │ │ │ ├── project-detail │ │ │ │ ├── project-holder │ │ │ │ │ └── project-holder.tsx │ │ │ │ ├── project-layout-store.ts │ │ │ │ ├── project-layout.tsx │ │ │ │ ├── project-setting │ │ │ │ │ ├── project-setting-advance │ │ │ │ │ │ ├── project-setting-advance-store.ts │ │ │ │ │ │ └── project-setting-advance.tsx │ │ │ │ │ ├── project-setting-common │ │ │ │ │ │ ├── project-setting-common-store.ts │ │ │ │ │ │ └── project-setting-common.tsx │ │ │ │ │ ├── project-setting-domain │ │ │ │ │ │ ├── create-domain-modal │ │ │ │ │ │ │ └── create-domain-modal.tsx │ │ │ │ │ │ ├── project-setting-domain-store.ts │ │ │ │ │ │ └── project-setting-domain.tsx │ │ │ │ │ ├── project-setting-member │ │ │ │ │ │ ├── project-setting-member-store.ts │ │ │ │ │ │ ├── project-setting-member.tsx │ │ │ │ │ │ └── role-select │ │ │ │ │ │ │ ├── role-select.tsx │ │ │ │ │ │ │ └── role.ts │ │ │ │ │ ├── project-setting-store.ts │ │ │ │ │ ├── project-setting.module.less │ │ │ │ │ └── project-setting.tsx │ │ │ │ └── project-workspace │ │ │ │ │ ├── create-workspace-modal │ │ │ │ │ └── create-workspace-modal.tsx │ │ │ │ │ ├── project-workspace-store.ts │ │ │ │ │ ├── project-workspace.module.less │ │ │ │ │ ├── project-workspace.tsx │ │ │ │ │ └── workspace-single │ │ │ │ │ ├── create-deploy-file │ │ │ │ │ └── create-deploy-file.tsx │ │ │ │ │ ├── create-deploy-url │ │ │ │ │ └── create-deploy-url.tsx │ │ │ │ │ ├── deploy-info-descriptions │ │ │ │ │ └── deploy-info-descriptions.tsx │ │ │ │ │ ├── deploy-info-modal │ │ │ │ │ └── deploy-info-modal.tsx │ │ │ │ │ ├── tabs-deploy-info │ │ │ │ │ └── tabs-deploy-info.tsx │ │ │ │ │ ├── tabs-deploys-table │ │ │ │ │ └── tabs-deploys-table.tsx │ │ │ │ │ ├── workspace-single-store.ts │ │ │ │ │ └── workspace-single.tsx │ │ │ │ └── project-list │ │ │ │ ├── project-list-store.ts │ │ │ │ └── project-list.tsx │ │ ├── routes.tsx │ │ ├── store │ │ │ ├── router-store.ts │ │ │ └── user-store.ts │ │ ├── style │ │ │ ├── style.less │ │ │ └── variable.less │ │ └── util │ │ │ ├── basic-store.ts │ │ │ ├── define-property.ts │ │ │ ├── get-normal-url.ts │ │ │ ├── get-preview-url.ts │ │ │ ├── get-query.ts │ │ │ └── time-format.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── typings │ │ └── declaration.d.ts │ └── vite.config.ts ├── server-api │ ├── .eslintrc.json │ ├── .gitignore │ ├── .prettierrc.js │ ├── bootstrap.js │ ├── jest.config.js │ ├── package.json │ ├── script │ │ └── sql │ │ │ └── init.sql │ ├── src │ │ ├── configuration.ts │ │ ├── controller │ │ │ ├── account-ctr.ts │ │ │ ├── common │ │ │ │ ├── api-response.ts │ │ │ │ └── web-util.ts │ │ │ ├── group-ctr.ts │ │ │ ├── project-ctr.ts │ │ │ ├── project-domain-ctr.ts │ │ │ ├── project-env-ctr.ts │ │ │ ├── project-env-deploy-ctr.ts │ │ │ └── project-member-ctr.ts │ │ ├── entity │ │ │ ├── base │ │ │ │ ├── base-column.ts │ │ │ │ └── bool-transform.ts │ │ │ ├── group-member.ts │ │ │ ├── group.ts │ │ │ ├── project-domain.ts │ │ │ ├── project-env-deploy.ts │ │ │ ├── project-env.ts │ │ │ ├── project-member.ts │ │ │ ├── project.ts │ │ │ └── user.ts │ │ ├── error │ │ │ └── custom-error.ts │ │ ├── interface │ │ │ ├── config.interface.ts │ │ │ ├── group.interface.ts │ │ │ ├── project-domain.interface.ts │ │ │ ├── project-env-deploy.interface.ts │ │ │ ├── project-env.interface.ts │ │ │ ├── project-member.interface.ts │ │ │ └── project.interface.ts │ │ ├── middleware │ │ │ ├── auth.ts │ │ │ ├── request.ts │ │ │ └── validate.ts │ │ ├── plugin │ │ │ └── noop.ts │ │ ├── service │ │ │ ├── account-srv.ts │ │ │ ├── group-member-srv.ts │ │ │ ├── group-srv.ts │ │ │ ├── project-domain-srv.ts │ │ │ ├── project-env-deploy-srv.ts │ │ │ ├── project-env-srv.ts │ │ │ ├── project-member-srv.ts │ │ │ └── project-srv.ts │ │ └── util │ │ │ ├── parse-str-to-num.ts │ │ │ └── query-runner-repo.ts │ ├── tsconfig.json │ └── typings │ │ └── index.d.ts └── server-client │ ├── .gitignore │ ├── .prettierrc.js │ ├── package.json │ ├── resource │ ├── 404.html │ └── favicon.ico │ ├── src │ ├── cache │ │ ├── host-cache.ts │ │ └── memory-cache.ts │ ├── config │ │ ├── index.ts │ │ └── typeorm │ │ │ └── typeorm-configuration.ts │ ├── controller │ │ └── dispatch-controller.ts │ ├── entity │ │ ├── base │ │ │ ├── base-column.ts │ │ │ └── bool-transform.ts │ │ ├── project-domain.ts │ │ ├── project-env-deploy.ts │ │ ├── project-env.ts │ │ └── project.ts │ ├── error │ │ ├── InvalidPreviewError.ts │ │ ├── ResourceFetchFailedError.ts │ │ ├── UnMatchedHostError.ts │ │ ├── UnMatchedProjectEnvDeployError.ts │ │ ├── UnMatchedProjectEnvError.ts │ │ └── UnMatchedProjectError.ts │ ├── index.ts │ ├── interface │ │ ├── application.ts │ │ └── context.ts │ ├── schedule │ │ ├── base │ │ │ ├── BaseLoop.ts │ │ │ └── BaseSchedule.ts │ │ ├── index.ts │ │ └── resource-update-loop.ts │ ├── service │ │ ├── project-service.ts │ │ └── resource-service.ts │ └── util │ │ ├── app-config.ts │ │ ├── ctx-print.ts │ │ ├── logger.ts │ │ ├── query-runner-repo.ts │ │ └── req-hostname.ts │ └── tsconfig.json ├── pnpm-lock.yaml └── pnpm-workspace.yaml /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | node_modules -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules/ 3 | 4 | # IDE 5 | /.idea 6 | /.awcache 7 | /.vscode 8 | /.devcontainer 9 | *.code-workspace 10 | 11 | # misc 12 | .DS_Store 13 | npm-debug.log 14 | yarn-error.log 15 | 16 | # output 17 | logs/ 18 | dist/ 19 | coverage/ 20 | images/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 JD.com, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pubfree 前端发布平台 2 | 3 | ## 描述 4 | ### 主要技术栈 5 | - 前端 React + Antd 6 | - 后端 NodeJS + MySQL 7 | - 工具 pnpm、vite 8 |   9 | ## 目录 10 | - [Pubfree 前端发布平台](#pubfree-前端发布平台) 11 | - [描述](#描述) 12 | - [主要技术栈](#主要技术栈) 13 | - [目录](#目录) 14 | - [安装](#安装) 15 | - [安装 pnpm](#安装-pnpm) 16 | - [安装依赖](#安装依赖) 17 | - [数据库建表](#数据库建表) 18 | - [运行 server-api](#运行-server-api) 19 | - [运行 server-client](#运行-server-client) 20 | - [运行 client-web](#运行-client-web) 21 | - [使用](#使用) 22 | - [快速发布流程](#快速发布流程) 23 | - [1. 创建项目](#1-创建项目) 24 | - [2. 资源发布](#2-资源发布) 25 | - [3. 资源生效](#3-资源生效) 26 | - [4. 查看页面](#4-查看页面) 27 | - [License](#license) 28 |   29 | ## 安装 30 | 安装前请确保已安装 MySQL 和 NodeJS,为了正常使用 vite, 请确保 NodeJS 版本为 ^14.18.0 || >=16.0.0。 31 |   32 | ### 安装 pnpm 33 | ````bash 34 | npm install -g pnpm 35 | ```` 36 | 查看 pnpm 版本,确认 pnpm 已经安装成功 37 | ````bash 38 | pnpm -v 39 | ```` 40 |   41 | ### 安装依赖 42 | 项目根目录下安装项目依赖 43 | ````bash 44 | pnpm install 45 | ```` 46 |   47 | ### 数据库建表 48 | 将 open-source/packages/server-api/script/sql/init.sql 文件中的 sql 语句复制到 MySQL 中运行,建立服务所需的基本数据库表。 49 |   50 | ### 运行 server-api 51 | 在 open-source/packages/server-api/resource 下新建 config.default.json,并配置数据库等信息 52 | ````js 53 | { 54 | "orm": { 55 | "host": "127.0.0.1", 56 | "port": 3306, 57 | "database": "pubfree_open", 58 | "username": "root", 59 | "password": "root" 60 | } 61 | } 62 | 63 | ```` 64 | 本地运行 65 | ````bash 66 | cd packages/server-api 67 | pnpm dev 68 | ```` 69 | 在本地 http://127.0.0.1:7001 下便可访问到 cms 页面用到的接口。 70 |   71 | ### 运行 server-client 72 | 在 open-source/packages/server-client/resource 下新建 config.default.json,并配置数据库等信息 73 | ````js 74 | { 75 | "mysql": { 76 | "enable": true, 77 | "options": { 78 | "host": "127.0.0.1", 79 | "port": 3306, 80 | "database": "pubfree_open", 81 | "username": "root", 82 | "password": "root" 83 | } 84 | }, 85 | "schedule": { 86 | "enable": true 87 | } 88 | } 89 | ```` 90 | 本地运行 91 | ````bash 92 | cd packages/server-client 93 | pnpm dev 94 | ```` 95 | 通过 http://127.0.0.1:3000 可访问到发布在平台上的页面。 96 |   97 | ### 运行 client-web 98 | 本地运行 99 | ````bash 100 | cd packages/client-web 101 | pnpm dev 102 | ```` 103 | 通过 http://localhost:5173 可访问发布平台的 cms 页面。 104 |   105 | ## 使用 106 | ### 快速发布流程 107 | #### 1. 创建项目 108 | ![image](https://img14.360buyimg.com/imagetools/jfs/t1/105149/20/34273/57679/635a36bbE218c80ef/f0e2aae07970886b.png) 109 |   110 | #### 2. 资源发布 111 | 使用 zip 上传(本地开发环境不支持)或者输入 html 资源地址发布 112 | ![image](https://img11.360buyimg.com/imagetools/jfs/t1/163595/19/28519/58928/635a3728E590137d6/47cafdfe3dc8f304.png) 113 | ![image](https://img11.360buyimg.com/imagetools/jfs/t1/165869/35/31958/58647/635a37adE079e68bb/ec97699dfc18b23c.png) 114 |   115 | #### 3. 资源生效 116 | ![image](https://img10.360buyimg.com/imagetools/jfs/t1/212448/21/22800/62291/635a3d73Ef52f159c/b9da61eb8847544e.png) 117 |   118 | #### 4. 查看页面 119 | ![image](https://img14.360buyimg.com/imagetools/jfs/t1/109768/38/33231/62656/635a3dd6E287d9b3c/482c3616706297ed.png) 120 |   121 | ## License 122 | [MIT © JD.com, Inc.](./LICENSE) -------------------------------------------------------------------------------- /deploy/client-web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.23.2-alpine 2 | COPY packages/client-web/dist/ /usr/share/nginx/html 3 | COPY deploy/client-web/nginx.conf /etc/nginx/conf.d/default.conf 4 | -------------------------------------------------------------------------------- /deploy/client-web/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | listen [::]:80; 4 | server_name localhost; 5 | 6 | #access_log /var/log/nginx/host.access.log main; 7 | 8 | location / { 9 | try_files $uri /$uri /index.html; 10 | root /usr/share/nginx/html; 11 | index index.html index.htm; 12 | } 13 | 14 | #error_page 404 /404.html; 15 | 16 | # redirect server error pages to the static page /50x.html 17 | # 18 | error_page 500 502 503 504 /50x.html; 19 | location = /50x.html { 20 | root /usr/share/nginx/html; 21 | } 22 | 23 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80 24 | # 25 | #location ~ \.php$ { 26 | # proxy_pass http://127.0.0.1; 27 | #} 28 | 29 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 30 | # 31 | #location ~ \.php$ { 32 | # root html; 33 | # fastcgi_pass 127.0.0.1:9000; 34 | # fastcgi_index index.php; 35 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; 36 | # include fastcgi_params; 37 | #} 38 | 39 | # deny access to .htaccess files, if Apache's document root 40 | # concurs with nginx's one 41 | # 42 | #location ~ /\.ht { 43 | # deny all; 44 | #} 45 | } -------------------------------------------------------------------------------- /deploy/server-api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12.22.12-alpine3.15 2 | WORKDIR /root 3 | COPY . . 4 | RUN yarn global add pnpm@6 && \ 5 | pnpm config set registry https://registry.npm.taobao.org && \ 6 | pnpm config set recursive-install false && \ 7 | cd packages/server-api && \ 8 | pnpm install && \ 9 | pnpm run build 10 | CMD cd packages/server-api && pnpm run start 11 | -------------------------------------------------------------------------------- /deploy/server-api/config.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "orm": { 3 | "host": "host.docker.internal", 4 | "port": 3306, 5 | "database": "pubfree_open", 6 | "username": "root", 7 | "password": "root" 8 | } 9 | } -------------------------------------------------------------------------------- /deploy/server-client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12.22.12-alpine3.15 2 | WORKDIR /root 3 | COPY . . 4 | RUN yarn global add pnpm@6 && \ 5 | pnpm config set registry https://registry.npm.taobao.org && \ 6 | pnpm config set recursive-install false && \ 7 | cd packages/server-client && \ 8 | pnpm install && \ 9 | pnpm run build 10 | CMD cd packages/server-client && pnpm run start 11 | -------------------------------------------------------------------------------- /deploy/server-client/config.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "mysql": { 3 | "enable": true, 4 | "options": { 5 | "host": "host.docker.internal", 6 | "port": 3306, 7 | "database": "pubfree_open", 8 | "username": "root", 9 | "password": "root" 10 | } 11 | }, 12 | "schedule": { 13 | "enable": true 14 | } 15 | } -------------------------------------------------------------------------------- /packages/client-web/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | .vscode 4 | 5 | dist 6 | build 7 | 8 | config/spark-builder-config.json 9 | config/webpack.dev.js 10 | 11 | script/publish/oss-token.json 12 | 13 | node_modules 14 | package-lock.json -------------------------------------------------------------------------------- /packages/client-web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | Pubfree 前端静态发布平台 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/client-web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pubfree-web", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "prettier": "prettier -l --write 'src/**/*.{ts,tsx,js,jsx,less,css}'", 6 | "prettier-check": "prettier -l 'src/**/*.{ts,tsx,less,css}'", 7 | "tslint": "tsc -p tsconfig.json --noEmit", 8 | "lint": "yarn prettier-check && yarn tslint", 9 | "dev": "vite", 10 | "build": "tsc && vite build", 11 | "preview": "vite preview" 12 | }, 13 | "dependencies": { 14 | "@ant-design/icons": "^4.7.0", 15 | "antd": "4.18.4", 16 | "axios": "0.21.4", 17 | "classnames": "^2.3.1", 18 | "history": "^4.9.0", 19 | "lodash-es": "^4.17.21", 20 | "mobx": "4.15.7", 21 | "mobx-react": "6.3.1", 22 | "qrcode": "1.5.0", 23 | "react": "^17.0.1", 24 | "react-dom": "^17.0.1", 25 | "react-router-dom": "^5.2.0" 26 | }, 27 | "devDependencies": { 28 | "@types/lodash-es": "4.17.4", 29 | "@types/qrcode": "^1.4.2", 30 | "@types/react": "17.0.3", 31 | "@types/react-dom": "17.0.3", 32 | "@types/react-router-dom": "^5.2.0", 33 | "@vitejs/plugin-react": "^2.1.0", 34 | "autoprefixer": "^10.4.12", 35 | "less": "^4.1.3", 36 | "postcss-px-to-viewport": "^1.1.1", 37 | "prettier": "^2.7.1", 38 | "typescript": "^4.6.4", 39 | "vite": "^3.1.3" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/client-web/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('autoprefixer'), 4 | require('postcss-px-to-viewport')({ 5 | unitToConvert: 'px', 6 | viewportWidth: 1920, 7 | unitPrecision: 5, 8 | propList: ['*'], 9 | viewportUnit: 'vw', 10 | fontViewportUnit: 'vw', 11 | selectorBlackList: [], 12 | minPixelValue: 1, 13 | mediaQuery: false, 14 | replace: true, 15 | exclude: /.+/, 16 | include: undefined, 17 | }), 18 | ], 19 | remove: false, 20 | } 21 | -------------------------------------------------------------------------------- /packages/client-web/src/api/axios-ins.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { DefineProperty } from "../util/define-property"; 3 | 4 | const axiosIns = axios.create({ 5 | baseURL: DefineProperty.ServerUrl + "/api", 6 | timeout: 5000, 7 | withCredentials: true, 8 | }); 9 | 10 | axiosIns.interceptors.response.use((response) => { 11 | return response.data; 12 | }); 13 | 14 | export default axiosIns; 15 | -------------------------------------------------------------------------------- /packages/client-web/src/api/detail/account.ts: -------------------------------------------------------------------------------- 1 | import axiosIns from "../axios-ins"; 2 | import { IApiRes } from "../index"; 3 | 4 | export const accountInfo = async (): Promise> => { 5 | return axiosIns.get("/account/info"); 6 | }; 7 | 8 | export const accountLogin = async (): Promise> => { 9 | return axiosIns.post("/account/login"); 10 | }; 11 | 12 | export const accountLogout = async (): Promise> => { 13 | return axiosIns.post("/account/logout"); 14 | }; 15 | 16 | export const accountRegister = async (): Promise> => { 17 | return axiosIns.post("/account/register"); 18 | }; 19 | 20 | export interface IAccountInfo { 21 | id: number; 22 | name: string; 23 | } 24 | -------------------------------------------------------------------------------- /packages/client-web/src/api/detail/domain.ts: -------------------------------------------------------------------------------- 1 | import { IDomainDTO } from "../../interface/client-api/domain.interface"; 2 | import axiosIns from "../axios-ins"; 3 | import { IApiRes } from "../index"; 4 | 5 | export const getProjectDomains = ( 6 | projectId: number 7 | ): Promise> => { 8 | return axiosIns.get(`/projects/${projectId}/domains`); 9 | }; 10 | 11 | export const createProjectDomain = ( 12 | projectId: number, 13 | params: { projectEnvId: number; host: string } 14 | ): Promise> => { 15 | return axiosIns.post(`/projects/${projectId}/domains`, params); 16 | }; 17 | 18 | export const deleteProjectDomain = ( 19 | projectId: number, 20 | domainId: number 21 | ): Promise> => { 22 | return axiosIns.delete(`/projects/${projectId}/domains/${domainId}`); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/client-web/src/api/detail/group.ts: -------------------------------------------------------------------------------- 1 | import { IGroupDTO } from "../../interface/client-api/group.interface"; 2 | import { IProjectDTO } from "../../interface/client-api/project.interface"; 3 | import axiosIns from "../axios-ins"; 4 | import { IApiRes } from "../index"; 5 | 6 | export const getGroups = async (): Promise> => { 7 | return axiosIns.get(`/groups`); 8 | }; 9 | 10 | export const getGroupDetail = async ( 11 | groupId: number 12 | ): Promise> => { 13 | return axiosIns.get(`/groups/${groupId}`); 14 | }; 15 | 16 | export const createGroup = async (params: { 17 | name: string; 18 | description: string; 19 | }): Promise> => { 20 | return axiosIns.post(`/groups`, params); 21 | }; 22 | 23 | export const updateGroup = async (groupId: number): Promise> => { 24 | return axiosIns.post(`/groups/${groupId}`); 25 | }; 26 | 27 | export const deleteGroup = async (groupId: number): Promise> => { 28 | return axiosIns.delete(`/groups/${groupId}`); 29 | }; 30 | 31 | export const getGroupProjects = async ( 32 | groupId: number 33 | ): Promise> => { 34 | return axiosIns.get(`/groups/${groupId}/projects`); 35 | }; 36 | -------------------------------------------------------------------------------- /packages/client-web/src/api/detail/member.ts: -------------------------------------------------------------------------------- 1 | import { 2 | EGroupMemberRole, 3 | EProjectMemberRole, 4 | IGroupMemberDTO, 5 | IProjectMemberDTO, 6 | } from "../../interface/client-api/member.interface"; 7 | import axiosIns from "../axios-ins"; 8 | import { IApiRes } from "../index"; 9 | 10 | export const getGroupMembers = ( 11 | groupId: number 12 | ): Promise> => { 13 | return axiosIns.get(`/groups/${groupId}/members`); 14 | }; 15 | 16 | export const addGroupMember = ( 17 | groupId: number, 18 | params: { name: string; role: EGroupMemberRole } 19 | ): Promise> => { 20 | return axiosIns.post(`/groups/${groupId}/members`, params); 21 | }; 22 | 23 | export const deleteGroupMember = ( 24 | groupId: number, 25 | memberId: number 26 | ): Promise> => { 27 | return axiosIns.delete(`/groups/${groupId}/members/${memberId}`); 28 | }; 29 | 30 | export const getProjectMembers = ( 31 | projectId: number 32 | ): Promise> => { 33 | return axiosIns.get(`/projects/${projectId}/members`); 34 | }; 35 | 36 | export const addProjectMember = ( 37 | projectId: number, 38 | params: { name: string; role: EProjectMemberRole } 39 | ): Promise> => { 40 | return axiosIns.post(`/projects/${projectId}/members`, params); 41 | }; 42 | 43 | export const deleteProjectMember = ( 44 | projectId: number, 45 | memberId: number 46 | ): Promise> => { 47 | return axiosIns.delete(`/projects/${projectId}/members/${memberId}`); 48 | }; 49 | -------------------------------------------------------------------------------- /packages/client-web/src/api/detail/project.ts: -------------------------------------------------------------------------------- 1 | import { 2 | EProjectEnvType, 3 | ICreateProjectDTO, 4 | IGetProjectsQuery, 5 | IProjectDeployDTO, 6 | IProjectDTO, 7 | IProjectEnvDTO, 8 | } from "../../interface/client-api/project.interface"; 9 | import axiosIns from "../axios-ins"; 10 | import { IApiRes } from "../index"; 11 | 12 | export const getProjects = ( 13 | query: IGetProjectsQuery 14 | ): Promise< 15 | IApiRes<{ 16 | total: number; 17 | projects: IProjectDTO[]; 18 | }> 19 | > => { 20 | return axiosIns.get(`/projects`, { 21 | params: query, 22 | }); 23 | }; 24 | 25 | export const getProjectInfo = ( 26 | projectId: number 27 | ): Promise> => { 28 | return axiosIns.get(`/projects/${projectId}`); 29 | }; 30 | 31 | export const createProject = ( 32 | params: ICreateProjectDTO 33 | ): Promise> => { 34 | return axiosIns.post(`/projects`, params); 35 | }; 36 | 37 | export const updateProject = (projectId: number): Promise> => { 38 | return axiosIns.post(`/projects/${projectId}`); 39 | }; 40 | 41 | export const deleteProject = (projectId: number): Promise> => { 42 | return axiosIns.delete(`/projects/${projectId}`); 43 | }; 44 | 45 | export const getProjectEnvs = ( 46 | projectId: number 47 | ): Promise> => { 48 | return axiosIns.get(`/projects/${projectId}/envs`); 49 | }; 50 | 51 | export const createProjectEnv = ( 52 | projectId: number, 53 | params: { name: string; type: EProjectEnvType } 54 | ): Promise> => { 55 | return axiosIns.post(`/projects/${projectId}/envs`, params); 56 | }; 57 | 58 | export const updateProjectEnv = ( 59 | projectId: number, 60 | envId: number 61 | ): Promise> => { 62 | return axiosIns.post(`/projects/${projectId}/envs/${envId}`); 63 | }; 64 | 65 | export const deleteProjectEnv = ( 66 | projectId: number, 67 | envId: number 68 | ): Promise> => { 69 | return axiosIns.delete(`/projects/${projectId}/envs/${envId}`); 70 | }; 71 | 72 | export const getProjectDeploys = ( 73 | projectId: number, 74 | envId: number 75 | ): Promise> => { 76 | return axiosIns.get(`/projects/${projectId}/envs/${envId}/deploys`); 77 | }; 78 | 79 | export const createProjectDeploy = ( 80 | projectId: number, 81 | envId: number, 82 | params: { type: "url" | "zip"; options: { target: string; remark: string } } 83 | ): Promise> => { 84 | return axiosIns.post(`/projects/${projectId}/envs/${envId}/deploys`, params); 85 | }; 86 | 87 | export const activateDeploy = ( 88 | projectId: number, 89 | envId: number, 90 | deployId: number 91 | ): Promise> => { 92 | return axiosIns.post( 93 | `/projects/${projectId}/envs/${envId}/deploys/${deployId}/activate` 94 | ); 95 | }; 96 | 97 | export const deactivateDeploy = ( 98 | projectId: number, 99 | envId: number, 100 | deployId: number 101 | ): Promise> => { 102 | return axiosIns.post( 103 | `/projects/${projectId}/envs/${envId}/deploys/${deployId}/deactivate` 104 | ); 105 | }; 106 | -------------------------------------------------------------------------------- /packages/client-web/src/api/index.ts: -------------------------------------------------------------------------------- 1 | import * as account from "./detail/account"; 2 | import * as domain from "./detail/domain"; 3 | import * as group from "./detail/group"; 4 | import * as member from "./detail/member"; 5 | import * as project from "./detail/project"; 6 | 7 | export interface IApiRes { 8 | code: EApiCode; 9 | data: T; 10 | message?: string; 11 | } 12 | 13 | export enum EApiCode { 14 | Success = 200, 15 | Unauthorized = 401, 16 | } 17 | 18 | const Api = { 19 | account: account, 20 | domain: domain, 21 | group: group, 22 | member: member, 23 | project: project, 24 | }; 25 | 26 | export default Api; 27 | -------------------------------------------------------------------------------- /packages/client-web/src/component/category-detail/category-detail.tsx: -------------------------------------------------------------------------------- 1 | import { Card, Space } from "antd"; 2 | import React from "react"; 3 | 4 | interface IProps { 5 | title: string; 6 | direction?: "horizontal" | "vertical"; 7 | } 8 | 9 | const CategoryDetail: React.FC = (props) => { 10 | const { title, direction = "horizontal" } = props; 11 | return ( 12 | 20 | 21 | {props.children} 22 | 23 | 24 | ); 25 | }; 26 | 27 | export default CategoryDetail; 28 | -------------------------------------------------------------------------------- /packages/client-web/src/component/layout/page-layout/component/footer/footer.module.less: -------------------------------------------------------------------------------- 1 | .common-layout-footer { 2 | background-color: #303846 !important; 3 | color: #fff !important; 4 | 5 | .footer-col { 6 | display: flex; 7 | justify-content: space-around; 8 | 9 | .footer-link { 10 | font-size: 15px; 11 | margin-bottom: 10px; 12 | display: flex; 13 | flex-direction: column; 14 | align-items: flex-start; 15 | 16 | .footer-name { 17 | color: #fff; 18 | text-decoration: underline; 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/client-web/src/component/layout/page-layout/component/footer/footer.tsx: -------------------------------------------------------------------------------- 1 | import { Space } from "antd"; 2 | import { Footer } from "antd/lib/layout/layout"; 3 | import React from "react"; 4 | import styles from "./footer.module.less"; 5 | 6 | const LayoutFooter: React.FC = () => { 7 | return ( 8 |
12 | 13 |
Pubfree @2022 Created by Jd
14 |
15 |
16 | ); 17 | }; 18 | 19 | export default LayoutFooter; 20 | -------------------------------------------------------------------------------- /packages/client-web/src/component/layout/page-layout/index.tsx: -------------------------------------------------------------------------------- 1 | import { Layout } from "antd"; 2 | import React from "react"; 3 | import Footer from "./component/footer/footer"; 4 | import Header from "./component/header/header"; 5 | 6 | const PageLayout: React.FC = (props) => { 7 | const { Content } = Layout; 8 | 9 | return ( 10 | 17 |
18 | 23 | {props.children} 24 | 25 |