Commit 60e0bcd8 authored by oyhk's avatar oyhk
Browse files

[add] 添加版本计划项目排序配置

parent b0d5fe4e
Showing with 195 additions and 24 deletions
+195 -24
......@@ -3,7 +3,7 @@ import { BaseEntity } from '../common/base.entity';
import { ApiResultCode } from '../common/api-result';
/**
* 项目扩展表,用于插件管理
* 版本计划项目配置服务器
*/
@Entity()
export class PlanEnvProjectConfigServer extends BaseEntity {
......
import { Column, Entity } from 'typeorm';
import { BaseEntity } from '../common/base.entity';
/**
* 版本计划
*/
@Entity()
export class PlanProjectSort extends BaseEntity {
static entityName = 'PlanProjectSort';
@Column({ unique: true, comment: '项目id' })
projectId: number;
@Column({ comment: '项目名称' })
projectName: string;
@Column({ comment: '项目排序' })
sort: number;
}
import { Body, Controller, Delete, Get, Post, Put, Query, Req, Res } from '@nestjs/common';
import { Response } from 'express';
import { Body, Controller, Delete, Get, Post, Put, Query, Req, Res } from '@nestjs/common';
import { ApiResult, ApiResultCode } from '../common/api-result';
import { InjectRepository } from '@nestjs/typeorm';
import { EntityManager, Repository, Transaction, TransactionManager } from 'typeorm';
......@@ -7,13 +7,13 @@ import { JwtService } from '@nestjs/jwt';
import { Env } from '../env/env.entity';
import { PlanDto } from './plan.dto';
import { Project } from '../project/project.entity';
import { UserDto } from '../user/user.dto';
import { PlanEnvProjectConfig } from './plan-env-project-config.entity';
import { Plan } from './plan.entity';
import { PlanEnvProjectConfigServer, PlanEnvProjectConfigServerType } from './plan-env-project-config-server.entity';
import { PlanEnv } from './plan-env.entity';
import { PlanScript } from './plan-script.entity';
import { EnvDto } from '../env/env.dto';
import { Page } from '../common/page';
import { ServerDto } from '../server/server.dto';
import { UserAuth, UserAuthOperation } from '../user/user-auth';
......@@ -21,6 +21,9 @@ import { PlanEnvDto } from './plan-env.dto';
import { PlanEnvProjectConfigDto } from './plan-env-project-config.dto';
import { PlanScriptDto } from './plan-script.dto';
import * as https from 'https';
import { PlanProjectSort } from './plan-project-sort.entity';
@Controller()
export class PlanController {
......@@ -31,6 +34,8 @@ export class PlanController {
private projectRepository: Repository<Project>,
@InjectRepository(Plan)
private planRepository: Repository<Plan>,
@InjectRepository(PlanProjectSort)
private planProjectSortRepository: Repository<PlanProjectSort>,
@InjectRepository(PlanScript)
private planScriptRepository: Repository<PlanScript>,
@InjectRepository(PlanEnv)
......@@ -43,6 +48,49 @@ export class PlanController {
) {
}
@Get('/api/plans/project-sort-list')
async projectSortList(@Query() dto: PlanDto, @Res() res: Response) {
const ar = new ApiResult();
const projectList = await this.projectRepository.find();
const projectSortList = await this.planProjectSortRepository.find();
const projectSortIdList = projectSortList.map(projectSort => projectSort.projectId);
for (const project of projectList) {
}
return res.json(ar);
}
@Get('/api/plans/gray-publish-first')
async grayPublishFirst(@Query() dto: PlanDto, @Res() res: Response) {
const ar = new ApiResult();
// 首次灰度发布
// 1. 先下线注册中心需要发布的所有项目
// 2. 按照项目发布顺序发布项目
// 3. 发布完成后,注册中心每个项目手动上线
const plan = await this.planRepository.findOne(dto.id);
// const clientRequest = http.request('https://api.yiwoaikeji.com/gateway/info', (clientResponse) => {
// clientResponse.on('data',(chunk)=>{
// console.log(chunk);
// })
// });
// clientRequest.end();
const clientRequest = https.request('https://api.yiwoaikeji.com/gateway/info', (clientResponse) => {
clientResponse.setEncoding('utf8');
clientResponse.on('data', (chunk) => {
console.log(JSON.parse(chunk));
});
});
clientRequest.end();
return res.json(ar);
}
@Get('/api/plans/project-list')
async list(@Query() dto: PlanDto, @Res() res: Response) {
const ar = new ApiResult();
......@@ -90,15 +138,19 @@ export class PlanController {
@Get('/api/plans/page')
async page(@Query() dto: PlanDto, @Res() res: Response) {
const ar = new ApiResult();
const page = new Page();
await this.planRepository.createQueryBuilder('s').orderBy('id','DESC')
const page = new Page<PlanDto>();
await this.planRepository.createQueryBuilder('s').orderBy('id', 'DESC')
.skip(PlanDto.getOffset(PlanDto.getPageNo(dto.pageNo), ServerDto.getPageSize(dto.pageSize)))
.take(PlanDto.getPageSize(dto.pageSize))
.getManyAndCount()
.then(value => {
page.data = value[0];
page.data = value[0] as PlanDto[];
page.total = value[1];
});
// 版本计划环境列表
for (const planDto of page.data) {
planDto.planEnvList = await this.planEnvRepository.find({ planId: planDto.id }) as PlanEnvDto[];
}
page.pageNo = dto.pageNo;
page.pageSize = dto.pageSize;
// 分页总数,总记录数 / 页条数,当存在小数点,使用了 Math.ceil 直接网上取整数
......
......@@ -10,9 +10,10 @@ import { Plan } from './plan.entity';
import { PlanEnv } from './plan-env.entity';
import { PlanEnvProjectConfigServer } from './plan-env-project-config-server.entity';
import { PlanScript } from './plan-script.entity';
import { PlanProjectSort } from './plan-project-sort.entity';
@Module({
imports: [TypeOrmModule.forFeature([Env,Project,Plan,PlanEnv,PlanEnvProjectConfig,PlanEnvProjectConfigServer,PlanScript]), JwtModule.register({ secret: 'hard!to-guess_secret' })],
imports: [TypeOrmModule.forFeature([Env,Project,Plan,PlanProjectSort,PlanEnv,PlanEnvProjectConfig,PlanEnvProjectConfigServer,PlanScript]), JwtModule.register({ secret: 'hard!to-guess_secret' })],
controllers: [PlanController],
})
export class PlanModule {
......
......@@ -102,6 +102,11 @@ const config: IConfig = {
path: routes.pageRoutes.planCreate,
component: '@/pages/plan/PlanCreate',
},
{
title: '版本计划项目排序配置',
path: routes.pageRoutes.planProjectSort,
component: '@/pages/plan/PlanProjectSort',
},
],
},
......@@ -171,6 +176,19 @@ const config: IConfig = {
},
],
},
//插件模块
{
path: routes.pageRoutes.pluginEurekaIndex,
title: '插件',
routes: [
{
path: routes.pageRoutes.pluginEurekaIndex,
title: 'Eureka',
component: '@/pages/plugin/eureka/EurekaIndex',
},
],
},
],
},
],
......
......@@ -8,6 +8,7 @@ import {
DeploymentUnitOutlined,
EnvironmentOutlined,
PushpinOutlined,
AppstoreOutlined,
} from '@ant-design/icons';
import ProLayout, { MenuDataItem, DefaultFooter, PageLoading } from '@ant-design/pro-layout';
import { Link, connect, history } from 'umi';
......@@ -156,27 +157,34 @@ const BaseLayout: React.FC = props => {
key: 'plan',
path: routes.pageRoutes.planIndex,
children: [
// {
// name: '项目编辑',
// key: 'projectEdit',
// path: routes.pageRoutes.projectEdit,
// hideInMenu: true,
// },
{
name: '版本计划编辑',
key: 'planEdit',
path: routes.pageRoutes.planEdit,
hideInMenu: true,
},
{
name: '版本计划创建',
key: 'planCreate',
path: routes.pageRoutes.planCreate,
hideInMenu: true,
},
// {
// name: '项目环境日志',
// key: 'projectEnvLog',
// path: routes.pageRoutes.projectEnvLogIndex,
// hideInMenu: true,
// },
],
},
// 插件
{
icon: <AppstoreOutlined />,
name: '插件',
key: 'plugin',
children: [
{
name: 'Eureka',
key: 'pluginEureka',
icon:'',
path: routes.pageRoutes.pluginEurekaIndex,
},
],
},
]
);
}}
......
import React from 'react';
import routes from '@/routes';
import { Link } from 'umi';
import { PlusOutlined } from '@ant-design/icons';
import { PlusOutlined, DeploymentUnitOutlined } from '@ant-design/icons';
import ProTable, { ProColumns } from '@ant-design/pro-table';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { EnvDto } from '@/services/dto/EnvDto';
import { momentFormat } from '@/utils/utils';
import { Button, notification } from 'antd';
import { momentFormat, uuid } from '@/utils/utils';
import { Button, notification, Table } from 'antd';
import { PlanDto } from '@/services/dto/PlanDto';
import { useRequest } from '@umijs/hooks';
import { ApiResult } from '@/services/ApiResult';
......@@ -21,6 +21,9 @@ export default () => {
})
,
{
onSuccess: (apiResult) => {
console.log(apiResult);
},
formatResult: (res: any) => ({
list: res?.result?.data,
total: res?.result?.total,
......@@ -35,6 +38,8 @@ export default () => {
manual: true,
onSuccess: (apiResult, params) => {
if (apiResult) {
notification.success({
message: `版本计划:${params[0]?.name}`,
description: '删除成功',
......@@ -78,7 +83,36 @@ export default () => {
dataSource={paginatedResult.data?.list}
toolBarRender={() => [
<Link to={routes.pageRoutes.planCreate}><PlusOutlined/> 添加版本计划</Link>,
]}
headerTitle={<div><Link to={routes.pageRoutes.planProjectSort}><DeploymentUnitOutlined/> 项目排序配置</Link></div>}
expandable={
{
expandedRowRender: (record) => {
return <Table
rowKey={uuid()}
columns={
[
{ title: '环境名称', dataIndex: 'envName' },
{
title: 'DevOps', key: 'DevOps', render: () => {
return <div key={uuid()}>
<Button type='primary' size='small'>首次灰度发布</Button>&nbsp;&nbsp;&nbsp;&nbsp;
<Button type='primary' size='small'>灰度发布</Button>&nbsp;&nbsp;&nbsp;&nbsp;
<Button danger type='primary' size='small'>正式发布</Button>&nbsp;&nbsp;&nbsp;&nbsp;
</div>;
},
},
]
}
dataSource={record.planEnvList}
pagination={false}
footer={() => <div/>}/>;
},
defaultExpandAllRows: true,
}
}
pagination={{
...paginatedResult.pagination,
onChange: (pageNo, pageSize) => {
......
import React from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Form } from 'antd';
export default () => {
return (
<PageHeaderWrapper>
<Form
initialValues={[]}
>
<Form.List name="projectList">
{
(fields, { add, remove }) => {
return (
<div>123</div>
);
}
}
</Form.List>
</Form>
</PageHeaderWrapper>
);
}
import React from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
export default () => {
return (
<PageHeaderWrapper>
<div>Eureka</div>
</PageHeaderWrapper>
);
}
......@@ -29,6 +29,7 @@ export default {
},
// 版本计划
planIndex: pageRoot + '/plan',
planProjectSort: pageRoot + '/plan/project-sort',
planCreate: pageRoot + '/plan/create',
planEdit: pageRoot + '/plan/edit/:id',
planEditParams: (id: any) => pageRoot + `/plan/edit/${id}`,
......@@ -50,6 +51,8 @@ export default {
envEdit: pageRoot + '/env/edit/:id',
envEditParams: (id: any) => pageRoot + `/env/edit/${id}`,
pluginEurekaIndex: pageRoot + '/plugin/eureka',
},
// API
apiRoutes: {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment