diff --git a/.env b/.env index 29bdcd0..a598b98 100644 --- a/.env +++ b/.env @@ -21,7 +21,7 @@ DB_PASSWORD='123456' DB_DATABASE='yice-performance' # devops 的默认用户名和密码 -DEVOPS_USERNAME="admin@dtstack.com" +DEVOPS_USERNAME="admin" DEVOPS_PASSWORD="123456" # devops 接口请求时默认的 cookie DEVOPS_COOKIE="" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 97cb81f..8b93bfa 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -19,7 +19,7 @@ jobs: node-version: 14 - name: Setup pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v4 with: version: 6.35.1 @@ -38,5 +38,8 @@ jobs: - name: Run test run: pnpm test + - name: Run check-types + run: pnpm check-types + - name: Run build run: pnpm build diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 855f6ac..8c3aff1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,12 +3,14 @@ before_script: - echo $CI_COMMIT_REF_NAME - whoami + - npm config set registry https://registry.npmmirror.com/ - pnpm install --reporter=silent stages: - prettier - eslint - stylelint + - check-types - test - build @@ -36,10 +38,19 @@ stylelint: rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME =~ /master/ +# 创建 MR 时执行;master 分支有 push 时执行 +check-types: + stage: check-types + needs: [prettier, eslint, stylelint] + script: + - pnpm check-types; + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME =~ /master/ + # 创建 MR 时执行;master 分支有 push 时执行 test: stage: test - needs: [prettier, eslint, stylelint] + needs: [check-types] script: - pnpm test; rules: diff --git a/.prettierignore b/.prettierignore index 263ce8f..7403c5f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,3 +2,4 @@ *.md dist *.less +.turbo diff --git a/.vscode/settings.json b/.vscode/settings.json index 246521a..d8ee3b7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,4 @@ { - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit", - "source.fixAll.stylelint": "explicit" - }, "editor.defaultFormatter": "esbenp.prettier-vscode", "files.insertFinalNewline": true, "[typescriptreact]": { diff --git a/CHANGELOG.md b/CHANGELOG.md index 348772c..dcb18c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [2.2.2](///compare/v2.2.1...v2.2.2) (2024-11-20) + + +### Bug Fixes + +* use new fetchData's params when autoRefresh 69baf39 + +### [2.2.1](///compare/v2.2.0...v2.2.1) (2024-11-19) + + +### Bug Fixes + +* use real time when send emails 7c69162 + +## [2.2.0](///compare/v2.1.2...v2.2.0) (2024-09-10) + + +### Features + +* add pm2-logrotate for split logs by day f40eedd +* some optimize 6d0668e +* support 63x 70x f7a6dfa + ### [2.1.2](///compare/v2.1.1...v2.1.2) (2024-07-16) diff --git a/README.md b/README.md index cfc02da..7064ba8 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,26 @@ cd yice-performance > 易测检测系统和我司内部的 devops 系统深度绑定,用于检测我司需要登录的一些页面,但不影响评分功能的实现参考。 +## 常见问题 + +### 1. yice-server 容器无法启动 + +  可能是 `docker` 版本较低,建议升级到 docker v24 及以上,升级前应当备份。 + +### 2. gcc 版本过低 + +  主机部署时建议使用 Ubuntu。 +  主机模式部署时 CentOS7 上启动服务时报错:Error: /lib64/libstdc++.so.6: version 'CXXABI_1.3.9' not found,这是因为 CentOS7 的 gcc 版本过低,需要升级到 gcc-4.8.5 以上,执行下方命令可以看到没有 CXXABI_1.3.9。 + +``` shell +strings /lib64/libstdc++.so.6 | grep CXXABI +``` + +### 3. MacOS M 系列 arm 芯片本地安装 canvas 时失败 + +   node@14.21.3 pnpm@6.35.1 代理开增强模式,可以正常安装依赖并启动。出现报错时,可以考虑使用这个依赖版本组合。 + + ## 趋势 [![Stargazers over time](https://starchart.cc/dtstack/yice-performance.svg)](https://starchart.cc/dtstack/yice-performance) diff --git a/apps/server/package.json b/apps/server/package.json index 09de395..a94558b 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -35,7 +35,7 @@ "cron-parser": "^4.8.1", "dingtalk-robot-sender": "^1.2.0", "dotenv": "^16.3.1", - "jsdom": "^22.1.0", + "jsdom": "21.1.2", "lighthouse": "9.6.8", "mysql": "^2.18.1", "mysql2": "^3.2.0", diff --git a/apps/server/src/modules/devops/controllers/devops.controller.ts b/apps/server/src/modules/devops/controllers/devops.controller.ts index 325a200..76ef8df 100644 --- a/apps/server/src/modules/devops/controllers/devops.controller.ts +++ b/apps/server/src/modules/devops/controllers/devops.controller.ts @@ -51,7 +51,7 @@ export class DevopsController { @HttpCode(HttpStatus.OK) @Get('getDevopsUrl') async getDevopsUrl(@Query() query: getStagesReqDto) { - return await this.devopsService.getDevopsUrl(query?.shiliId); + return await this.devopsService.getDevopsUrl(+query?.shiliId); } @ApiOperation({ summary: '获取 devops 项目列表' }) diff --git a/apps/server/src/modules/devops/dto/devops.req.dto.ts b/apps/server/src/modules/devops/dto/devops.req.dto.ts index 895d913..0dd7ca9 100644 --- a/apps/server/src/modules/devops/dto/devops.req.dto.ts +++ b/apps/server/src/modules/devops/dto/devops.req.dto.ts @@ -7,7 +7,7 @@ export class getShiLisReqDto { export class getStagesReqDto { @ApiPropertyOptional({ required: false, description: 'devops实例id' }) - shiliId: number; + shiliId: string; } export class getHistoriesReqDto { diff --git a/apps/server/src/modules/devops/services/devops.service.ts b/apps/server/src/modules/devops/services/devops.service.ts index 8885ea1..325850e 100644 --- a/apps/server/src/modules/devops/services/devops.service.ts +++ b/apps/server/src/modules/devops/services/devops.service.ts @@ -82,10 +82,38 @@ export class DevopsService { // 5、获取实例下的详情 url, 相当于同时做了 2, 3, 4 async getDevopsUrl(shiliId: number) { try { - const stages = await this.getStages(shiliId); - const histories = await this.getHistories({ shiliId, stageId: stages?.[0]?.id }); - const history = await this.getHistory(histories?.[0]?.id); - return history; + // 主机环境 + if (shiliId > 99_999) { + // 主机环境,写死地址 + // hostList 的 value 需要和 hostUrlList 的 value 同步修改 + const hostUrlList = [ + { + label: '7.0.x', + value: 100_000, + url: 'http://70x.dtstack.cn', + loginUrl: 'http://70x.dtstack.cn/uic/#/', + }, + { + label: '6.3.x', + value: 100_001, + url: 'http://63x.dtstack.cn', + loginUrl: 'http://63x.dtstack.cn/uic/#/', + }, + ]; + const portalfront = hostUrlList.find((item) => item.value === shiliId)?.url; + return { + portalfront, + loginUrl: `${portalfront}/uic/#/`, + username: process.env.DEVOPS_USERNAME, + password: process.env.DEVOPS_PASSWORD, + }; + } else { + // devops 环境 + const stages = await this.getStages(shiliId); + const histories = await this.getHistories({ shiliId, stageId: stages?.[0]?.id }); + const history = await this.getHistory(histories?.[0]?.id); + return history; + } } catch (error) { console.log(`请求 devops 接口失败, DEVOPS_COOKIE: ${process.env.DEVOPS_COOKIE}`); throw new HttpException('请求 devops 接口失败', HttpStatus.OK); diff --git a/apps/server/src/modules/email/controllers/email.controller.ts b/apps/server/src/modules/email/controllers/email.controller.ts index c118b47..67e161f 100644 --- a/apps/server/src/modules/email/controllers/email.controller.ts +++ b/apps/server/src/modules/email/controllers/email.controller.ts @@ -4,7 +4,7 @@ import { ApiOperation } from '@nestjs/swagger'; import { ChartService } from '@/modules/chart/services/chart.service'; import { ProjectService } from '@/modules/project/services/project.service'; -import { lastMonthRange, lastWeekRange } from '@/utils'; +import { getLastMonthRange, getLastWeekRange } from '@/utils'; import { EmailService } from '../services/email.service'; @Controller('email') @@ -34,17 +34,17 @@ export class EmailController { const { projectId, name, emails } = project; if (emails?.split(',').length) { try { + console.log( + `\nprojectId: ${projectId}, ${name}, 开始发送【单个子产品】的数据周报到指定邮箱` + ); await this.sendProject({ projectId, emails }); } catch (error) {} - console.log( - `\nprojectId: ${projectId}, ${name}, 发送【单个子产品】的数据周报到指定邮箱` - ); } }); } async handleSendAll() { if (process.env.DEFAULT_EMAIL) { - console.log('\n发送【所有子产品】的数据周报到指定邮箱'); + console.log('\n开始发送【所有子产品】的数据周报到指定邮箱'); await this.sendAll({ emails: process.env.DEFAULT_EMAIL }); } } @@ -68,8 +68,8 @@ export class EmailController { } async generatePromise(project) { - const [startTime, endTime] = lastWeekRange; - const [startMonthTime, endMonthTime] = lastMonthRange; + const [startTime, endTime] = getLastWeekRange(); + const [startMonthTime, endMonthTime] = getLastMonthRange(); const projectChartData = await this.chartService.projectChart({ projectId: project.projectId, startTime, @@ -102,8 +102,8 @@ export class EmailController { throw new Error('DEFAULT_EMAIL 未配置邮箱'); } - const [startTime, endTime] = lastWeekRange; - const [startMonthTime, endMonthTime] = lastMonthRange; + const [startTime, endTime] = getLastWeekRange(); + const [startMonthTime, endMonthTime] = getLastMonthRange(); let projectList = await this.projectService.findAll(); projectList = projectList.filter((project) => project.name !== '汇总'); @@ -143,10 +143,7 @@ export class EmailController { return result; } } catch (error) { - throw new HttpException( - `尝试发送【所有子产品】的数据周报失败, ${error}`, - HttpStatus.OK - ); + throw new HttpException(`发送【所有子产品】的数据周报失败, ${error}`, HttpStatus.OK); } } } diff --git a/apps/server/src/modules/email/services/email.service.ts b/apps/server/src/modules/email/services/email.service.ts index 08736c9..137d2f7 100644 --- a/apps/server/src/modules/email/services/email.service.ts +++ b/apps/server/src/modules/email/services/email.service.ts @@ -2,7 +2,7 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { MailerService } from '@nestjs-modules/mailer'; import { IFileSizeChartData, IProjectChartData } from 'typing'; -import { lastWeekRange } from '@/utils'; +import { getLastWeekRange } from '@/utils'; import { renderChart } from '@/utils/echarts'; @Injectable() @@ -14,7 +14,7 @@ export class EmailService { projectChartData: IProjectChartData, fileSizeChartData: IFileSizeChartData ) { - const [_, __, startTime, endTime] = lastWeekRange; + const [_, __, startTime, endTime] = getLastWeekRange(); const { projectId, name, emails } = project; if (emails?.split(',')?.length) { @@ -32,32 +32,32 @@ export class EmailService { return result; } catch (error) { console.log( - `\nprojectId: ${projectId}, ${name}, 尝试发送【单个子产品】的数据周报失败`, + `\nprojectId: ${projectId}, ${name}, 发送【单个子产品】的数据周报失败`, error ); - throw new HttpException('尝试发送单个子产品的数据周报失败', HttpStatus.OK); + throw new HttpException('发送单个子产品的数据周报失败', HttpStatus.OK); } } } // 定时发送所有子产品的数据周报到指定邮箱 async sendMailAllProject(emails, chartDataList = []) { - const [_, __, startTime, endTime] = lastWeekRange; + const [_, __, startTime, endTime] = getLastWeekRange(); if (emails?.split(',')?.length) { const html = renderChart(chartDataList); try { const result = await this.mailerService.sendMail({ to: emails?.split(','), - subject: `【数栈子产品】易测数据周报(${startTime}~${endTime})`, // 标题 + subject: `【所有子产品】易测数据周报(${startTime}~${endTime})`, // 标题 html, }); console.log('\n发送【所有子产品】的数据周报成功', result); return result; } catch (error) { - console.log('\n尝试发送【所有子产品】的数据周报失败', error); - throw new HttpException('尝试发送【所有子产品】的数据周报失败', HttpStatus.OK); + console.log('\n发送【所有子产品】的数据周报失败', error); + throw new HttpException('发送【所有子产品】的数据周报失败', HttpStatus.OK); } } } diff --git a/apps/server/src/modules/task/dto/task.dto.ts b/apps/server/src/modules/task/dto/task.dto.ts index 032a94f..f97a0e2 100644 --- a/apps/server/src/modules/task/dto/task.dto.ts +++ b/apps/server/src/modules/task/dto/task.dto.ts @@ -23,6 +23,7 @@ export class TaskDto { readonly createAt?: Date; @IsOptional() + // eslint-disable-next-line camelcase @IsUrl({ protocols: ['http', 'https'], require_protocol: true }, { message: '检测地址无效' }) @MaxLength(2048, { message: '检测地址最大长度为2048' }) @ApiPropertyOptional({ description: '检测地址' }) diff --git a/apps/server/src/modules/task/services/task.run.service.ts b/apps/server/src/modules/task/services/task.run.service.ts index 9a23f84..97dd907 100644 --- a/apps/server/src/modules/task/services/task.run.service.ts +++ b/apps/server/src/modules/task/services/task.run.service.ts @@ -174,7 +174,7 @@ export class TaskRunService { .printSql() .execute(); - console.log(`taskId: ${taskId}, 数据整理完成,已落库`); + console.log(`taskId: ${taskId}, 数据整理完成,已落库。本次检测完成`); } catch (error) { status = TASK_STATUS.FAIL; failReason = error; diff --git a/apps/server/src/modules/version/dto/version.dto.ts b/apps/server/src/modules/version/dto/version.dto.ts index d946756..e48508d 100644 --- a/apps/server/src/modules/version/dto/version.dto.ts +++ b/apps/server/src/modules/version/dto/version.dto.ts @@ -16,6 +16,7 @@ export class VersionDto { @MaxLength(64, { message: '版本名称最大长度为64' }) readonly name: string; + // eslint-disable-next-line camelcase @IsUrl({ protocols: ['http', 'https'], require_protocol: true }, { message: '检测地址无效' }) @IsNotEmpty({ message: '检测地址不能为空' }) @ApiPropertyOptional({ description: '检测地址' }) diff --git a/apps/server/src/mysql/some.sql b/apps/server/src/mysql/some.sql deleted file mode 100644 index 4299948..0000000 --- a/apps/server/src/mysql/some.sql +++ /dev/null @@ -1,19 +0,0 @@ --- 版本表添加 note 字段用于存储调度配置时的备注 -ALTER TABLE version add COLUMN note varchar(256) NULL COMMENT '备注'; - - - --- 任务表添加 previewImg 字段用于存储检测结果的首屏图片预览 -ALTER TABLE task add COLUMN previewImg LONGTEXT NULL COMMENT '结果的首屏图片预览'; - - - --- 产品表添加 emails 字段用于接收数据周报邮件 -ALTER TABLE project add COLUMN emails varchar(256) NULL COMMENT '子产品相关人员邮箱,用于接收数据周报邮件'; - - - - --- 版本表添加 sort 字段用于版本排序 -ALTER TABLE version add COLUMN sort int NULL DEFAULT 1 COMMENT '排序序号'; - diff --git a/apps/server/src/utils/date.ts b/apps/server/src/utils/date.ts index c3e81e4..9c1a6e0 100644 --- a/apps/server/src/utils/date.ts +++ b/apps/server/src/utils/date.ts @@ -21,16 +21,20 @@ export const formatTime = (mo, isEnd?: boolean, output = 'YYYY-MM-DD HH:mm:ss') }; // 近七天 -export const lastWeekRange: any = [ - formatTime(todayStart().subtract(6, 'days')), - formatTime(todayStart().subtract(0, 'days'), true), - formatTime(todayStart().subtract(6, 'days'), false, 'MM-DD'), - formatTime(todayStart().subtract(0, 'days'), true, 'MM-DD'), -]; +export const getLastWeekRange = () => { + return [ + formatTime(todayStart().subtract(6, 'days')), + formatTime(todayStart().subtract(0, 'days'), true), + formatTime(todayStart().subtract(6, 'days'), false, 'MM-DD'), + formatTime(todayStart().subtract(0, 'days'), true, 'MM-DD'), + ]; +}; // 近 30 天 -export const lastMonthRange: any = [ - formatTime(todayStart().subtract(29, 'days')), - formatTime(todayStart().subtract(0, 'days'), true), - formatTime(todayStart().subtract(29, 'days'), false, 'MM-DD'), - formatTime(todayStart().subtract(0, 'days'), true, 'MM-DD'), -]; +export const getLastMonthRange = () => { + return [ + formatTime(todayStart().subtract(29, 'days')), + formatTime(todayStart().subtract(0, 'days'), true), + formatTime(todayStart().subtract(29, 'days'), false, 'MM-DD'), + formatTime(todayStart().subtract(0, 'days'), true, 'MM-DD'), + ]; +}; diff --git a/apps/server/src/utils/echarts.ts b/apps/server/src/utils/echarts.ts index af00ab0..e5fe35c 100644 --- a/apps/server/src/utils/echarts.ts +++ b/apps/server/src/utils/echarts.ts @@ -15,8 +15,8 @@ export const getProjectChartOptions = (projectChartData: IProjectChartData) => { const legendSelectedMap = {}; if (versionNameList?.length) { for (let i = 0; i < versionNameList.length; i++) { - // 默认选择前三个 - legendSelectedMap[versionNameList[i]] = i < 3; + // 默认选择前两个 + legendSelectedMap[versionNameList[i]] = i < 2; } } diff --git a/apps/server/src/utils/taskRun.ts b/apps/server/src/utils/taskRun.ts index ab750a2..4b8202d 100644 --- a/apps/server/src/utils/taskRun.ts +++ b/apps/server/src/utils/taskRun.ts @@ -125,6 +125,7 @@ const changeTenant = async (page, taskId) => { const sleepTime = Number(process.env.RESPONSE_SLEEP ?? 5); // 租户 + await sleep(sleepTime / 2); await page.click('.ant-select'); const tenantInput = await page.$('input#change_ten_id'); await sleep(sleepTime / 2); @@ -217,6 +218,7 @@ export const taskRun = async (task: ITask, successCallback, failCallback, comple console.log(`taskId: ${taskId}, 开始整理数据...`); // 保存检测结果的报告文件,便于预览 + // eslint-disable-next-line no-useless-escape const urlStr = url.replace(/http(s?):\/\//g, '').replace(/\/|\#|\?|\&/g, '-'); // 创建当天的文件夹用于存放报告文件 diff --git a/apps/web/src/const/index.ts b/apps/web/src/const/index.ts index ba2ac8d..0cf4862 100644 --- a/apps/web/src/const/index.ts +++ b/apps/web/src/const/index.ts @@ -43,7 +43,7 @@ export const IS_USEFUL_TEXT = [ */ const scoreColor = { orangeMin: 50, - greenMin: 80, + greenMin: 90, }; export const getScoreColor = (score: number) => { diff --git a/apps/web/src/main.less b/apps/web/src/main.less index 449474f..11b3717 100644 --- a/apps/web/src/main.less +++ b/apps/web/src/main.less @@ -1 +1,33 @@ @import url("antd/dist/antd.css"); + +::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +::-webkit-scrollbar-track { + cursor: pointer; + width: 6px; + background: transparent; + -webkit-border-radius: 2em; + -moz-border-radius: 2em; + border-radius: 2em; +} + +::-webkit-scrollbar-thumb { + cursor: pointer; + background-color: rgba(#101F1C, 0.3); + background-clip: padding-box; + min-height: 28px; + -webkit-border-radius: 2em; + -moz-border-radius: 2em; + border-radius: 2em; +} + +::-webkit-scrollbar-track:hover { + background: rgba(#101F1C, 0.1); +} + +::-webkit-scrollbar-thumb:hover { + background-color: rgba(#101F1C, 0.5); +} diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx index 30d17d4..6616c40 100644 --- a/apps/web/src/main.tsx +++ b/apps/web/src/main.tsx @@ -10,7 +10,7 @@ import Routers from './routers'; import './main.less'; const yiceRole = localStorage.getItem('yice-role'); -!yiceRole && localStorage.setItem('yice-role', YICE_ROLE.USER); +!yiceRole && localStorage.setItem('yice-role', YICE_ROLE.ADMIN); ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( diff --git a/apps/web/src/utils/index.ts b/apps/web/src/utils/index.ts index e3578d9..8256249 100644 --- a/apps/web/src/utils/index.ts +++ b/apps/web/src/utils/index.ts @@ -14,4 +14,5 @@ export function getImgUrl(fileName: string, url?: string) { * 以 http(s) 开头的检测地址 */ export const httpPattern = + // eslint-disable-next-line no-useless-escape /^(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/; diff --git a/apps/web/src/views/home/components/chartModal/index.tsx b/apps/web/src/views/home/components/chartModal/index.tsx index 183b746..0f0aefb 100644 --- a/apps/web/src/views/home/components/chartModal/index.tsx +++ b/apps/web/src/views/home/components/chartModal/index.tsx @@ -189,8 +189,18 @@ export default function ChartModal(props: IProps) { const tabItems = [ { label: '性能评分趋势图', key: 'project', children: renderProjectChart() }, - { label: '构建产物大小分析图', key: 'file-size', children: renderFileSizeChart() }, - { label: '版本构建性能图', key: 'version-build', children: renderBuildChart() }, + { + label: '构建产物大小分析图', + key: 'file-size', + disabled: true, + children: renderFileSizeChart(), + }, + { + label: '版本构建性能图', + key: 'version-build', + disabled: true, + children: renderBuildChart(), + }, ]; const tabBarExtraContent = () => { diff --git a/apps/web/src/views/home/components/chartModal/projectChart/index.tsx b/apps/web/src/views/home/components/chartModal/projectChart/index.tsx index 41c560a..3e6ab1d 100644 --- a/apps/web/src/views/home/components/chartModal/projectChart/index.tsx +++ b/apps/web/src/views/home/components/chartModal/projectChart/index.tsx @@ -26,14 +26,14 @@ export default function ProjectChart(props: IProps) { const { data } = props; const { taskList, versionNameList, maxLength } = data || {}; // echarts 顶部选择展示的版本 - const [legendSelectedMap, setLegendSelectedMap] = useState({}); + const [legendSelectedMap, setLegendSelectedMap] = useState({}); useEffect(() => { if (versionNameList?.length) { const _map = { ...legendSelectedMap }; for (let i = 0; i < versionNameList.length; i++) { - // 默认选择前三个 - _map[versionNameList[i]] = i < 3; + // 默认选择前两个 + _map[versionNameList[i]] = i < 2; } setLegendSelectedMap(_map); } diff --git a/apps/web/src/views/home/components/patchDataModal/index.tsx b/apps/web/src/views/home/components/patchDataModal/index.tsx index 960d58c..07d6240 100644 --- a/apps/web/src/views/home/components/patchDataModal/index.tsx +++ b/apps/web/src/views/home/components/patchDataModal/index.tsx @@ -39,6 +39,12 @@ export default function PatchDataModal(props: IProps) { }); }; + // 输入框的回车事件 + const handleInputEnter = (e: any) => { + // 中文输入法输入时回车,keyCode 是 229;光标在输入框直接回车,keyCode 是 13 + !loading && e.keyCode === 13 && handleOk(); + }; + return ( - + void; - onCancel: () => void; + onCancel: (needFetch: boolean) => void; } export default function ScheduleModal(props: IProps) { @@ -20,6 +20,7 @@ export default function ScheduleModal(props: IProps) { const [form] = Form.useForm(); const [formLoading, setFormLoading] = useState(false); const [saving, setSaving] = useState(false); + const [_isFreeze, setIsFreeze] = useState(false); const [runLoading, setRunLoading] = useState(false); const yiceRole = localStorage.getItem('yice-role'); @@ -37,6 +38,7 @@ export default function ScheduleModal(props: IProps) { API.getVersion({ versionId }) .then((res) => { const { cron, isFreeze, note } = res.data || {}; + setIsFreeze(isFreeze); setTimeout(() => { form.setFieldsValue({ cron, isFreeze, note }); }, 200); @@ -57,7 +59,7 @@ export default function ScheduleModal(props: IProps) { }) .finally(() => { setRunLoading(false); - onCancel(); + onCancel(false); }); }; @@ -69,7 +71,7 @@ export default function ScheduleModal(props: IProps) { API.updateScheduleConf({ projectId: project?.projectId, versionId, ...values }) .then(() => { message.success('保存成功!'); - onCancel(); + onCancel(_isFreeze !== values.isFreeze); }) .finally(() => { setSaving(false); @@ -121,7 +123,7 @@ export default function ScheduleModal(props: IProps) {
- + @@ -154,7 +156,7 @@ export default function ScheduleModal(props: IProps) { forceRender destroyOnClose footer={renderButtons()} - onCancel={onCancel} + onCancel={() => onCancel(false)} >
diff --git a/apps/web/src/views/home/components/taskTable/index.tsx b/apps/web/src/views/home/components/taskTable/index.tsx index 531a64d..fcb34e8 100644 --- a/apps/web/src/views/home/components/taskTable/index.tsx +++ b/apps/web/src/views/home/components/taskTable/index.tsx @@ -92,7 +92,7 @@ export default function TaskTable(props: IPros) { }, [projectId, versionId]); const handleAutoRefreshData = () => { - !versionListLoading && !loading && fetchData(); + setRunTime(new Date().getTime()); }; /** @@ -108,6 +108,8 @@ export default function TaskTable(props: IPros) { */ const fetchData = () => { if (!projectId && !versionId) return; + if (versionListLoading || loading) return; + setLoading(true); const params = { projectId, @@ -339,10 +341,10 @@ export default function TaskTable(props: IPros) { return (
操作 - + setScheduleOpen(false)} + onCancel={(needFetch: boolean) => { + setScheduleOpen(false); + // 冻结/解除冻结 后需要刷新版本列表 + needFetch && getVersions(!versionList.length); + }} /> ); diff --git a/apps/web/src/views/home/components/versionModal/index.tsx b/apps/web/src/views/home/components/versionModal/index.tsx index 0d381a9..7ba3714 100644 --- a/apps/web/src/views/home/components/versionModal/index.tsx +++ b/apps/web/src/views/home/components/versionModal/index.tsx @@ -28,7 +28,14 @@ export default function VersionModal(props: IProps) { const [deleting, setDeleting] = useState(false); const [saving, setSaving] = useState(false); const [devopsShiLiId, setDevopsShiLiId] = useState(undefined); - const [devopsShiLiList, setDevopsShiLiList] = useState([]); + const [envList, setEnvList] = useState([]); + const [envGroupList, setEnvGroupList] = useState([]); + + // hostList 的 value 需要和 hostUrlList 的 value 同步修改 + const hostList = [ + { label: '7.0.x', value: 100_000 }, + { label: '6.3.x', value: 100_001 }, + ]; const yiceRole = localStorage.getItem('yice-role'); @@ -57,30 +64,37 @@ export default function VersionModal(props: IProps) { }); }; - // 获取项目下的 devops 实例列表 + // 获取项目下的环境列表 const getShiLis = () => { setShiliFetching(true); API.getShiLis({ devopsProjectIds }) .then((res) => { - setDevopsShiLiList( + const devopsEnvList = res.data?.map((item: any) => { return { label: item.label, value: item.id, }; - }) || [] - ); + }) || []; + setEnvList(hostList.concat(devopsEnvList)); + setEnvGroupList([ + { label: '主机环境', options: hostList }, + { + label: 'devops 环境', + options: devopsEnvList, + }, + ]); }) .finally(() => { setShiliFetching(false); }); }; - // 选择了某个 devops 实例 + // 选择了某个环境 const handleSelect = (value: any) => { setFormLoading(true); setDevopsShiLiId(value); - const { label: name } = devopsShiLiList.find((item) => item.value === value) || {}; + const { label: name } = envList.find((item) => item.value === value) || {}; API.getDevopsUrl({ shiliId: value }) .then(({ data = {} }) => { const { portalfront: url, loginUrl, username, password } = data; @@ -172,11 +186,11 @@ export default function VersionModal(props: IProps) { const devopsShiLiIdDeleted = isEdit && - devopsShiLiList.length && + envList.length && devopsShiLiId && - !devopsShiLiList.map((item) => item.value).includes(devopsShiLiId); + !envList.map((item) => item.value).includes(devopsShiLiId); const validateStatus = devopsShiLiIdDeleted ? 'error' : ''; - const help = devopsShiLiIdDeleted ? '当前绑定的 devops 实例已被删除' : ''; + const help = devopsShiLiIdDeleted ? '当前绑定环境已被删除' : ''; return (