搜索结果列表页面开发

This commit is contained in:
付民康
2025-03-12 18:41:20 +08:00
commit 7cebe8fc00
739 changed files with 88149 additions and 0 deletions

16
.editorconfig Normal file
View File

@@ -0,0 +1,16 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

7
.env Normal file
View File

@@ -0,0 +1,7 @@
VITE_APP_TITLE = '新gitcode'
VITE_TEST_REPOID = 34
VITE_SECRET_KEY = 'SA!nUNPZ5o!OSV&B'
VITE_SECRET_IV = 'SA!nwwwZ5o!OSV&B'
# 用户模块前缀
VITE_PASSPORT_PREFIX = '/uc'

36
.env.development Normal file
View File

@@ -0,0 +1,36 @@
# 开发环境配置
VITE_ENV = 'development'
# 主域名
VITE_HOST = 'https://test.gitcode.net'
# 接口地址
VITE_API_HOST = 'https://test.gitcode.net'
# devPress接口地址
VITE_DEV_API_HOST = 'https://test.gitcode.net'
# devPress地址
VITE_DEV_HOST = 'https://test.gitcode.net'
# 仓库文件上传域名
VITE_FILE_HOST = 'https://test.gitcode.net'
# 仓库文件下载域名
VITE_DOWNLOAD_HOST = 'https://test.gitcode.net'
# csdn登陆绑定地址
VITE_CSDN_URL = 'https://test.gitcode.net/oauth/login/csdn'
# 组织社区跳转地址
VITE_ORG_COMMUNITY = 'https://test.gitcode.net'
# 静态资源域名
VITE_STATIC_HOST = 'https://test.gitcode.net'
# 主页搜索子应用
VITE_CHILD_HOMEWEB_HOST = 'https://test.gitcode.net/child/homeweb-app/'
# 用户中心子应用
VITE_USER_CENTER_HOST = 'https://test.gitcode.net/child/user-center/'
# ai-copilot 子应用
VITE_COPILOT_HOST = 'https://test.gitcode.net/child/aichat-app/'

38
.env.loc Normal file
View File

@@ -0,0 +1,38 @@
# 开发环境配置
VITE_ENV = 'loc'
# 主域名
VITE_HOST = 'https://test.gitcode.net'
# 接口地址
VITE_API_HOST = 'https://test.gitcode.net'
# devPress接口地址
VITE_DEV_API_HOST = 'https://test.gitcode.net'
# devPress地址
VITE_DEV_HOST = 'https://test.gitcode.net'
# 仓库文件上传域名
VITE_FILE_HOST = 'https://test.gitcode.net'
# 仓库文件下载域名
VITE_DOWNLOAD_HOST = 'https://test.gitcode.net'
# csdn登陆绑定地址
VITE_CSDN_URL = 'https://test.gitcode.net/oauth/login/csdn'
# 组织社区跳转地址
VITE_ORG_COMMUNITY = 'https://test.gitcode.net'
# 静态资源域名
VITE_STATIC_HOST = 'https://test.gitcode.net'
# 主页搜索子应用
VITE_CHILD_HOMEWEB_HOST = 'https://local.gitcode.net:8001/child/homeweb-app'
# 用户中心子应用
VITE_USER_CENTER_HOST = 'https://local.gitcode.net:8002'
# ai-copilot 子应用
VITE_COPILOT_HOST = 'https://local.gitcode.net:8003/child/aichat-app'

38
.env.pre Normal file
View File

@@ -0,0 +1,38 @@
# 预发环境配置
VITE_ENV = 'pre'
# 主域名
VITE_HOST = 'https://pre.gitcode.com'
# 接口地址
VITE_API_HOST = 'https://pre-web-api.gitcode.com'
# devPress接口地址
VITE_DEV_API_HOST = 'https://gitcode.com'
# devPress地址
VITE_DEV_HOST = 'https://gitcode.com'
# 仓库文件上传域名
VITE_FILE_HOST = 'https://pre.gitcode.com'
# 仓库文件下载域名
VITE_DOWNLOAD_HOST = 'https://raw.gitcode.com'
# csdn登陆绑定地址 暂时无
VITE_CSDN_URL = 'https://pre-web-api.gitcode.com/oauth/login/csdn'
# 组织社区跳转地址
VITE_ORG_COMMUNITY = 'https://gitcode.com'
# 静态资源域名
VITE_STATIC_HOST = 'https://pre.gitcode.com'
# 主页搜索子应用
VITE_CHILD_HOMEWEB_HOST = 'https://pre-homepage-app.gitcode.com'
# 用户中心子应用
VITE_USER_CENTER_HOST = 'https://pre-usercenter-app.gitcode.com'
# ai-copilot 子应用
VITE_COPILOT_HOST = 'https://pre-copilot-app.gitcode.com'

38
.env.production Normal file
View File

@@ -0,0 +1,38 @@
# 生产环境配置
VITE_ENV = 'production'
# 主域名
VITE_HOST = 'https://gitcode.com'
# 接口地址
VITE_API_HOST = 'https://web-api.gitcode.com'
# devPress接口地址
VITE_DEV_API_HOST = 'https://gitcode.com'
# devPress地址
VITE_DEV_HOST = 'https://gitcode.com'
# 仓库文件上传域名
VITE_FILE_HOST = 'https://gitcode.com'
# 仓库文件下载域名
VITE_DOWNLOAD_HOST = 'https://raw.gitcode.com'
# csdn登陆绑定地址 暂时无
VITE_CSDN_URL = 'https://web-api.gitcode.com/oauth/login/csdn'
# 组织社区跳转地址
VITE_ORG_COMMUNITY = 'https://gitcode.com'
# 静态资源域名
VITE_STATIC_HOST = 'https://cdn-static.gitcode.com'
# 主页搜索子应用
VITE_CHILD_HOMEWEB_HOST = 'https://homepage-app.gitcode.com'
# 用户中心子应用
VITE_USER_CENTER_HOST = 'https://usercenter-app.gitcode.com'
# ai-copilot 子应用
VITE_COPILOT_HOST = 'https://copilot-app.gitcode.com'

6
.eslintignore Normal file
View File

@@ -0,0 +1,6 @@
node_modules
build
dist
public
.vscode
vite.config.ts

190
.eslintrc.cjs Normal file
View File

@@ -0,0 +1,190 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution');
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
parserOptions: {
ecmaVersion: 'latest'
},
rules: {
'vue/multi-word-component-names': 'off', // 检查文件名称是否为多单词
'vue/singleline-html-element-content-newline': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/no-v-html': 'off',
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ['error', 'always', { 'null': 'ignore' }],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [1, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'always'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
};

39
.gitignore vendored Normal file
View File

@@ -0,0 +1,39 @@
# Logs
stats.html
logs
dist.zip
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
src/views/Demo
/cypress/videos/
/cypress/screenshots/
/docker/conf/default.conf
# Editor directories and files
.vscode
!.vscode/extensions.json
!.vscode/settings.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# 定义文件
components.d.ts
# 组件汇总文件,仅限开发本地浏览
component.md

8
.prettierrc.json Normal file
View File

@@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": true,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 120,
"trailingComma": "none"
}

62
README.md Normal file
View File

@@ -0,0 +1,62 @@
# gitcode-v2
架构:基于[create-vue](https://github.com/vuejs/create-vue)构建vite+vue3+pinia+scss
组件库:[Vue DevUI](https://vue-devui.github.io/)
# 规范
- 使用eslint保存自动格式化
- 页面和组件文件夹命名及引用为大驼峰IssueIssueItem其他文件夹小驼峰common
- 代码内变量方法名为小驼峰issueNum
- css类名为蛇形submit-btn-color
- 分支命名(关键字/模块/功能fix/mr/bigfile-issue-create
```
关键字包括feat、 hotfix、refactor等类型
```
- commit提交规范feat完成issue创建功能
```
feat 新增功能
fix: 修复 bug
docs: 仅仅修改了文档,比如 README, CHANGELOG, CONTRIBUTE等等
style: 仅仅修改了空格、格式缩进、逗号等等,不改变代码逻辑
refactor: 代码重构,没有加新功能或者修复 bug
perf: 优化相关,比如提升性能、体验
test: 测试用例,包括单元测试、集成测试等
chore: 改变构建流程、或者增加依赖库、工具等
revert: 回滚到上一个版本
```
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
# 安装依赖
npm install
```
### start
```sh
npm run dev # 开发
npm run prod # 生产
```
### build
```sh
npm run build:dev # 开发
npm run build:prod # 生产
```
### Lint with [ESLint](https://eslint.org/)
```sh
npm run lint
```

25
env.d.ts vendored Normal file
View File

@@ -0,0 +1,25 @@
// / <reference types="vite/client" />
declare module 'dayjs/esm/locale/zh-cn'
declare module 'dayjs/plugin/timezone'
import type { DefineComponent } from 'vue';
declare module 'canvas-confetti';
declare module '*.vue' {
const component: DefineComponent<{}, {}, any>;
export default component;
}
declare global {
interface Window { page_ref: string; }
}
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'
declare module 'js-cookie'

41
index.html Normal file
View File

@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<link rel="icon" href="https://cdn-static.gitcode.com/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="//homepage-app.gitcode.com" crossorigin />
<link rel="dns-prefetch" href="//homepage-app.gitcode.com">
<link rel="dns-prefetch" href="//usercenter-app.gitcode.com">
<link rel="dns-prefetch" href="//res.hc-cdn.com">
<!-- <meta name="referrer" content="no-referrer"> -->
<title>可信开源代码库</title>
<style type="text/css">
.icon {
width: 1em; height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
<script type="text/javascript" src="https://cdn-static.gitcode.com/js/gitcode-icon.js"></script>
<script type="text/javascript" src="https://cdn-static.gitcode.com/js/event-msg.min.0.0.2.js"></script>
<script type="text/javascript" src="https://cdn-static.gitcode.com/js/lottie.min.js" defer></script>
<script type="text/javascript" src="https://cdn-static.gitcode.com/js/furion.js" defer></script>
<!-- baidu统计 -->
<script>
var _hmt = _hmt || [];
_hmt.push(['_setAutoPageview', false]);
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?62047c952451105d57bab2c4af9ce85b";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</html>

9715
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

77
package.json Normal file
View File

@@ -0,0 +1,77 @@
{
"name": "gitcode-v2",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "vite --mode development",
"dev-loc": "vite --mode loc --open https://local.gitcode.net",
"pre": "vite --mode pre",
"prod": "vite --mode production",
"build:dev": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode development",
"build:test": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode test",
"build:pre": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode pre",
"build:prod": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode production",
"analysis": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode analysis",
"preview": "vite preview",
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"@devui-design/icons": "^1.3.0",
"@micro-zoe/micro-app": "1.0.0-rc.3",
"@sentry/vue": "^7.101.1",
"@types/crypto-js": "^4.1.1",
"@vueuse/core": "^10.2.1",
"axios": "^1.6.8",
"canvas-confetti": "^1.9.2",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.9",
"devui-theme": "^0.0.7",
"dompurify": "^3.0.5",
"js-cookie": "^3.0.5",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
"lottie-web": "^5.12.2",
"markdown-it": "^14.1.0",
"mitt": "^3.0.1",
"mockjs": "^1.1.0",
"normalize.css": "^8.0.1",
"overlayscrollbars": "^2.3.1",
"pinia": "^2.1.3",
"qs": "^6.11.2",
"sortablejs": "^1.15.0",
"swiper": "^10.3.1",
"vue": "^3.3.4",
"vue-devui": "^1.6.7",
"vue-router": "^4.2.2",
"yaml": "^2.4.1"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.2.0",
"@tsconfig/node18": "^2.0.1",
"@types/canvas-confetti": "^1.6.4",
"@types/mockjs": "^1.0.7",
"@types/node": "^18.17.1",
"@types/three": "^0.155.1",
"@vitejs/plugin-basic-ssl": "^1.0.1",
"@vitejs/plugin-legacy": "^4.1.1",
"@vitejs/plugin-vue": "^4.2.3",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/tsconfig": "^0.4.0",
"autoprefixer": "^10.4.14",
"eslint": "^9.22.0",
"eslint-plugin-vue": "^9.11.0",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.27",
"prettier": "^2.8.8",
"rollup-plugin-visualizer": "^5.9.2",
"sass": "^1.63.6",
"tailwindcss": "^3.3.3",
"typescript": "~5.0.4",
"unplugin-vue-components": "^0.26.0",
"vite": "^4.5.2",
"vue-tsc": "^1.6.5"
}
}

7
postcss.config.js Normal file
View File

@@ -0,0 +1,7 @@
// eslint-disable-next-line no-undef
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -0,0 +1,3 @@
# Tip
> 此文件夹保存了lottie的图片资源请勿删除

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
// 埋点统计
!function(x, n) {
window[n] = window[n] || {};
window[n].config = {
appId: "B890DF389DB3442F8BD2BF08280848ED",setting: "api,jsTrack,uba,longtask,rtti",hashMode: true,smartJsErr: false,
};
var o = document.createElement('script');
o.src = x, o.async = !0;
var d = document.body.firstChild;
document.body.insertBefore(o, d);
}('https://res.hc-cdn.com/FurionSdk/furion-cdn.min.js', '__fr');

228
src/App.vue Normal file
View File

@@ -0,0 +1,228 @@
// eslint-disable-next-line vue/name-property-casing
<script setup lang="ts">
import { RouterView } from 'vue-router';
import { ref, onMounted, onBeforeUnmount, watchEffect } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { addEventListener, clearEvent } from '@/utils/eventBus';
import { useLogin } from './utils/hooks/useLogin';
import { useNotification } from './utils/hooks/useNotice';
import { useAccount } from './utils/hooks/useAccount';
import { useAccModal } from './utils/hooks/useAccModal';
import { NotificationService } from 'vue-devui/notification';
import { Message } from 'vue-devui/message';
import { getOrgInfo } from '@/views/Org/hooks/orgInfo';
import cookie from 'js-cookie';
import { useGlobalInfoStore } from '@/stores/Global';
import dayjs from 'dayjs';
import { getLoginConfig } from './api/user';
const globalInfo = useGlobalInfoStore();
const { login, unMount, isMounted } = useLogin();
const { openModal, closeModal, isMountedModal } = useAccModal();
const { notice } = useNotification();
const { RemoveInfo } = useAccount();
const status = ref(false);
const isPending = ref(false);
const router = useRouter();
const route = useRoute();
const toNotice = () => {
if (localStorage.getItem('validator_email') === 'invalid') {
notice();
}
};
const checkoutFirstTime = () => {
const uuid = cookie.get('uuid_tt_dd');
const firstTime = cookie.get('gitcode_first_time');
if (uuid && !firstTime) {
const expireDate = new Date(`${dayjs().year() + 2}-01-01 00:00:00`);
const expirationUTC = new Date(
Date.UTC(
expireDate.getFullYear(),
expireDate.getMonth(),
expireDate.getDate(),
expireDate.getHours(),
expireDate.getMinutes(),
expireDate.getSeconds()
)
);
const domainMatch = (location.host.match(/(gitcode..+)/) || []) as string[];
cookie.set('gitcode_first_time', dayjs().format('YYYY-MM-DD HH:mm:ss'), { expires: expirationUTC, domain: domainMatch[1] });
}
};
onMounted(() => {
/** pc端刷新窗口 */
toNotice();
addEventListener('logout', (options) => {
const token = localStorage.getItem('access_token');
if (!status.value) {
status.value = true;
if (isMounted()) {
setTimeout(() => {
status.value = false;
}, 2000);
} else {
NotificationService.open({
type: 'success',
title: 'Gitcode 提示',
content: token ? '你的登录信息已过期,请重新登录!' : '登录之后才能开启全新体验哦',
onClose: () => {
status.value = false;
}
});
}
token && RemoveInfo();
const data = typeof options === 'boolean' ? { Authorization: options } : options;
login(data);
}
});
addEventListener('login', (options) => {
login(options);
});
/** 403刷新页面一次 */
addEventListener('forbiddenRefresh', () => {
// 暂时跳转组织创建
if (route.path === '/org/create') {
localStorage.removeItem('refresh_count');
return;
}
if (!isPending.value) {
isPending.value = true;
if (!localStorage.getItem('refresh_count') && route.name !== '403') {
localStorage.setItem('refresh_count', 'pending');
router.go(0);
} else {
Message.warning({
message: '权限不足',
onClose: () => {
localStorage.removeItem('refresh_count');
}
});
}
}
});
/** mobile暂定全部重定向为首页 */
addEventListener('notice', toNotice);
window.addEventListener('message', (event) => {
if (event.origin === (import.meta as any).env.VITE_HOST) {
if (event.data.type === 'success') {
if (isMountedModal()) {
closeModal();
}
if (isMounted()) {
unMount();
}
if (event.data?.path) {
router.replace(event.data?.path);
} else {
router.go(0);
}
} else if (event.data.type === 'fail') {
Message.warning(event.data.message || '授权失败');
}
}
});
/** 获取用户组织配额权限 */
if (!localStorage.getItem('group_quota')) {
const { getUserCreateOrg } = getOrgInfo();
getUserCreateOrg();
}
checkoutFirstTime();
});
watchEffect(async() => {
if (route?.query?.isLogin && !localStorage.getItem('access_token')) {
if (!isMountedModal()) {
const cache_timeStamp = localStorage.getItem('cache_timeStamp');
const currentTimestamp = Date.now();
const oneDayMilliseconds = 24 * 60 * 60 * 1000;
// 获取不加防打扰的配置
let loginList = [];
if (route?.query?.isLogin !== '1') {
const res = await getLoginConfig();
loginList = res?.data?.data || [];
}
// isLogin为配置字符串时一直弹窗
if (loginList.includes(route?.query?.isLogin) || !cache_timeStamp || (Number(cache_timeStamp) + oneDayMilliseconds) < currentTimestamp) {
setTimeout(() => {
localStorage.setItem('cache_timeStamp', currentTimestamp.toString());
openModal();
}, 1000);
}
}
}
// 注册来源utm_source保存
if (route?.query?.utm_source) {
const currentTime = Date.now();
localStorage.setItem('utm_source_sign_time', currentTime.toString());
localStorage.setItem('utm_source_sign', JSON.stringify(route?.query?.utm_source));
}
});
onBeforeUnmount(() => {
clearEvent();
window.removeEventListener('message', () => {});
});
</script>
<template>
<RouterView :class="`g-theme-${globalInfo.globalTheme}`" />
</template>
<style lang="scss">
.global-notification {
&-mobile {
.devui-notification {
right: 15px;
left: 15px;
width: #{calc(100vw - 30px )};
top: 60px;
&__title {
padding: 0;
}
}
.devui-notification-item-container {
background: rgba(255, 255, 255, 1);
box-sizing: border-box;
padding: 15px;
opacity: 1;
.devui-notification__item {
padding: 0;
}
}
}
&-pc {
.devui-notification {
width: 296px;
right: 22px;
top: 60px;
&__title {
padding: 0;
}
}
.devui-notification-item-container {
background: rgba(255, 255, 255, 1);
box-sizing: border-box;
padding: 22px;
opacity: 1;
.devui-notification__item {
padding: 0;
}
}
}
.devui-notification__message {
margin-left: 0;
}
.icon-close {
font-size: 0 !important;
&:before {
content: ''
}
}
}
</style>

60
src/api/analysis/index.ts Normal file
View File

@@ -0,0 +1,60 @@
import request from '@/utils/request';
import type { AxiosResponse } from 'axios';
import type { CommitCountData, RepoCountData, TrendData } from '@/api/analysis/types';
// 获取项目统计
export function getRepoCount(params: { project_id: string; statistics?: boolean }): Promise<AxiosResponse<RepoCountData>> {
return request({
url: `/api/v2/projects/${params.project_id}`,
method: 'get',
params
});
}
// 获取仓库趋势统计数据
export function getTrendCount(params: { project_id: string; branch_name: string; }): Promise<AxiosResponse<TrendData>> {
return request({
url: `/api/v2/projects/${params.project_id}/repository/commit_statistics`,
method: 'get',
params
});
}
// 获取仓库语言统计数据
export function getLangCount(params: { project_id: string; }): Promise<AxiosResponse<{label: string; value: number;}[]>> {
return request({
url: `/api/v2/projects/${params.project_id}/languages`,
method: 'get',
params
}, {
customError: true
});
}
// 获取仓库提交活跃度数据
export function getCommitCount(params: { project_id: string; branch_name: string; }): Promise<AxiosResponse<CommitCountData>> {
return request({
url: `/api/v2/projects/${params.project_id}/repository/graph`,
method: 'get',
params
});
}
// 获取仓库分支提交线路图
export function getCommitNetwork(params: { project_id: string; ref_name: string; filter_ref: string; }): Promise<AxiosResponse<any>> {
return request({
url: `/api/v2/projects/${params.project_id}/repository/network`,
method: 'get',
params
});
}
// 数据刷新,记录执行人
export function postRepoStatistics(project_id: string, data: object): Promise<any> {
return request({
url: `/api/v2/projects/${project_id}/repository/statistics`,
method: 'post',
data
}, {
customError: true
})
}

54
src/api/analysis/types.ts Normal file
View File

@@ -0,0 +1,54 @@
export type RepoCountData = {
tag_count: number;
branch_count: number;
release_count: number;
statistics: {
commit_count?: string;
storage_size?: string;
repository_size?: string;
lfs_objects_size?: string;
job_artifacts_size?: string;
};
}
export type TrendData = {
commits: Commit[];
statistics: Statistic[];
total: number;
}
type Commit = {
author_name: string;
date: Date;
}
type Statistic = {
id: number;
project_id: number;
branch: string;
user_name: string;
add_lines: number;
delete_lines: number;
commit_count: number;
created_at: Date;
updated_at: Date;
}
export type CommitCountData = {
authors: number;
commit_per_day: number;
commits: CommitData[];
duration: number;
end_date: string;
start_date: string;
total: number;
}
export type CommitData = {
parents: Array<Array<number | string>>;
author: any;
time: number;
space: number;
refs: any;
id: string;
date: string;
message: string;
}

57
src/api/branch/index.ts Normal file
View File

@@ -0,0 +1,57 @@
import request from '@/utils/request';
import * as types from '@/api/branch/types';
import { reqCatch } from '@/utils/catch';
// 获取分支概览
export function getBranchesOverview(params: types.commonBranchReqType): Promise<types.commonBranchResType> {
return reqCatch(() => request({
url: `/api/v2/internal/projects/${params.repoId}/repository/branch_overview`,
method: 'get',
params: params
}), params);
}
// 获取分支列表
export function getBranches(params: types.commonBranchReqType): Promise<types.commonBranchResType> {
if (!params.view) {
params.view = 'simple';
}
return reqCatch(() => request({
url: `/api/v2/projects/${params.repoId}/repository/branches`,
method: 'get',
params: {
...params,
search: params?.search?.substring(0, 100) || ''
}
}), params);
}
// 创建分支
export function createBranches(data: types.commonBranchReqType): Promise<types.commonBranchResType> {
return reqCatch(() => request({
url: `/api/v2/projects/${data.repoId}/repository/branches`,
method: 'post',
data
}), data);
}
// 删除分支
export function deleteBranches(data: types.commonBranchReqType): Promise<types.commonBranchResType> {
return reqCatch(() => request({
url: `/api/v2/projects/${data.repoId}/repository/branches`,
method: 'delete',
params: data
}), data);
}
// 检测是否为分支
export function checkBranches(params: types.commonBranchReqType): Promise<types.commonBranchResType> {
const { project_id } = params;
delete params.project_id;
return reqCatch(() => request({
url: `/api/v2/projects/${project_id}/repository/branches/check`,
method: 'get',
params
}), params);
}

18
src/api/branch/types.ts Normal file
View File

@@ -0,0 +1,18 @@
import { type errorType, type resCatch } from '@/api/types/common';
import type { repoType } from '@/api/types/common';
export interface createBranchReqType extends repoType{
branch: string,
ref: string,
description?: string;
relatedIds?: string[];
[propName: string]: any;
}
export interface commonBranchReqType {
[propName: string]: any;
}
export interface commonBranchResType extends resCatch {
[propName: string]: any;
}

80
src/api/cla/index.ts Normal file
View File

@@ -0,0 +1,80 @@
import request from '@/utils/request';
import * as types from '@/api/cla/types';
// 签署CLA
export function signCla(data: types.signClaReqType): Promise<any> {
return request({
url: `/api/v2/cla/sign/add`,
method: 'post',
data
});
}
// 签署CLA详情
export function getClaInfo(params: types.paramsObj): Promise<any> {
return request({
url: `/api/v2/cla/sign/info`,
method: 'get',
params
}, {
customError: true
});
}
// 本人已签署CLA详情
export function getClaInfoDetail(params: types.paramsObj): Promise<any> {
return request({
url: `/api/v2/cla/sign/detail`,
method: 'get',
params
}, {
customError: true
});
}
// 获取组织里面用户已签署CLA详情
export function getGroupClaInfoDetail(params: types.paramsObj): Promise<any> {
return request({
url: `/api/v2/cla/${params.group_id}/detail`,
method: 'get',
params
}, {
customError: true
});
}
// 组织下的cla列表
export function getGroupClaList(params: types.paramsObj): Promise<any> {
return request({
url: `/api/v2/cla/${params.group_id}/list`,
method: 'get',
params
});
}
// 组织下的cla列表
export function setGroupClaStatus(params: types.paramsObj): Promise<any> {
return request({
url: `/api/v2/cla/${params.group_id}/status`,
method: 'put',
params
});
}
// 组织下的cla列表
export function deleteGroupCla(params: types.paramsObj): Promise<any> {
return request({
url: `/api/v2/cla/${params.group_id}/del`,
method: 'delete',
params
});
}
// 已签署CLA协议的用户列表
export function getClaUsers(params: types.paramsObj): Promise<any> {
return request({
url: `/api/v2/cla/${params.group_id}/signUsers`,
method: 'get',
params: params.params
});
}
// CLA协议历史版本列表
export function getClaVersion(params: types.paramsObj): Promise<any> {
return request({
url: `/api/v2/cla/getClaHistory`,
method: 'get',
params
});
}

19
src/api/cla/types.ts Normal file
View File

@@ -0,0 +1,19 @@
export interface signClaReqType {
claId: string,
version: string,
sourceUrl: string,
userId: string,
userName: string,
realName: string,
email: string,
phone: string,
status: number,
payload: string,
sign: string,
[x:string]: any
}
export interface paramsObj {
[x:string]: any
}

142
src/api/commit/index.ts Normal file
View File

@@ -0,0 +1,142 @@
import request from '@/utils/request';
import * as types from '@/api/commit/types';
import { reqCatch } from '@/utils/catch';
// 修改检视意见
export function editDiscussions(data: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v1/projects/${data.repoId}/repository/commits/${data.commitId}/discussions/${data.discussionId}`,
method: 'post',
data
});
}
export function editDiscussionsByNoteId(data: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v1/projects/${data.repoId}/repository/commits/${data.commitId}/discussions/${data.discussionId}/notes/${data.note_id}`,
method: 'put',
data
});
}
export function deleteDiscussionsByNoteId(data: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v1/projects/${data.repoId}/repository/commits/${data.commitId}/discussions/${data.discussionId}/notes/${data.note_id}`,
method: 'delete',
data
});
}
export function getRepoCommits(params: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v1/projects/${params.repoId}/repository/commits`,
method: 'get',
params
});
}
export function addRepoCommits(data: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v1/projects/${data.repoId}/repository/commits`,
method: 'post',
data
}, {
customError: true
});
}
export function getRepoCommitsDetail(params: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v1/projects/${params.repoId}/repository/commits/${params.commitId}`,
method: 'get',
params: {
auth_current_project: params.auth_current_project
}
});
}
export function addRepoCommitsComments(data: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v1/projects/${data.repoId}/repository/commits/${data.commitId}/comments`,
method: 'post',
data
});
}
export function getRepoCommitsComments(data: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v1/projects/${data.repoId}/repository/commits/${data.commitId}/comments`,
method: 'get',
params: data
});
}
export function getRepoCommitsDiff(data: types.commonCommitReqType): Promise<any> {
return reqCatch(() => request({
url: `/api/v1/projects/${data.repoId}/repository/commits/${data.commitId}/diff`,
method: 'get',
params: data
}), data);
}
export function getRepoCommitsFileDiff(repoId, commitId, data: types.commonCommitReqType): Promise<any> {
return reqCatch(() => request({
url: `/api/v1/projects/${repoId}/repository/commits/${commitId}/file_diff`,
method: 'get',
params: data
}), data);
}
export function getRepoMergeRequests(data: types.commonCommitReqType): Promise<any> {
return reqCatch(() => request({
url: `/api/v1/projects/${data.repoId}/repository/commits/${data.commitId}/merge_requests`,
method: 'get',
data
}), data);
}
export function getCommitCommentDetail(data: types.commonCommitReqType): Promise<any> {
return reqCatch(() => request({
url: `/api/v1/projects/${data.repoId}/repository/commits/${data.commitId}/discussions/${data.discussion_id}/notes/${data.note_id}`,
method: 'get',
data
}), data);
}
// commit revert
export function commitRevert(repoId: string, commitId: string, data: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v1/projects/${repoId}/repository/commits/${commitId}/revert`,
method: 'post',
data
});
}
// commit cherry-pick
export function commitCherryPick(repoId: string, commitId: string, data: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v1/projects/${repoId}/repository/commits/${commitId}/cherry_pick`,
method: 'post',
data
});
}
export function getCommitMsgRegexTemplate(params: types.commonCommitReqType): Promise<any> {
return request({
url: `/api/v2/projects/${params.repoId}/common/commitMsgRegexTemplate`,
method: 'get',
params
});
}
// 保存commit设置
export function updateCommitSetting(data: types.commonCommitReqType, repoId: string): Promise<any> {
return request({
url: `/api/v2/projects/${repoId}/project_git_hook`,
method: 'put',
data
});
}
export function getCommitSetting(repoId: string): Promise<any> {
return request({
url: `/api/v2/projects/${repoId}/project_git_hook`,
method: 'get'
});
}

9
src/api/commit/types.ts Normal file
View File

@@ -0,0 +1,9 @@
import { type errorType } from '@/api/types/common';
export interface commonCommitReqType {
[propName: string]: any;
}
export interface commonCommitResType extends errorType {
[propName: string]: any;
}

32
src/api/common/index.ts Normal file
View File

@@ -0,0 +1,32 @@
import request from '@/utils/request';
import * as types from '@/api/common/types';
import { reqCatch } from '@/utils/catch';
export function upload(data: types.commonReqType): Promise<types.commonResType> {
return request({
url: `/api/v1/upload`,
method: 'post',
data
});
}
// 当前用户-项目权限
export function getRepoPermission(params: { repo_id: string }) {
const { repo_id } = params;
return reqCatch(() => request({
url: `/api/v1/projects/${repo_id}/role`,
method: 'get'
}), params);
}
// 当前用户-组织权限
export function getOrgPermission(params:{group_id:string}): Promise<any> {
const { group_id } = params;
return reqCatch(() => request({
url: `/api/v2/groups/${group_id}`,
method: 'get',
params
}, {
customError: true
}));
}

9
src/api/common/types.ts Normal file
View File

@@ -0,0 +1,9 @@
import { type errorType } from '@/api/types/common';
export interface commonReqType {
[propName: string]: any;
}
export interface commonResType extends errorType {
[propName: string]: any;
}

View File

@@ -0,0 +1,93 @@
import { ref } from 'vue';
import { useAccountStore } from '@/stores/user';
import { orgInfoStore } from '@/stores/Org/index';
import { repoInfoStore } from '@/stores/Repo/index';
import { getSettingsValues } from '@/api/repo';
import { getOrgDiscussionSettings } from '@/api/org';
import { useRepoId } from '@/utils/hooks/useRepoId';
import type {
repoAndOrgSettingDictType
} from '@/api/discussion/types';
/**
* 获取用户信息+是否登录
*/
export function useDiscussGetUserInfo() {
const { isLogin = false, accountInfo: userInfo = {}} = useAccountStore();
return { isLogin, userInfo };
}
/**
* 查询讨论模块是否开启,返回组织/项目id用于讨论接口请求
* @param source_type 1 组织2项目
* @param orgNamespace 组织 namespace
* 项目使用 useRepoId 获取 namespace
*/
export function useDiscussionOpen(source_type = 1, orgNamespace = '') {
const discussOpen = ref('0'); // 讨论模块是否打开0关闭1打开
const id = ref(''); // 项目/组织id
const project_id = ref(''); // 项目fullpath不带%2F
async function getDiscussionStatus() {
if (source_type === 1) {
// 组织讨论模块状态查询
const { orgInfo } = orgInfoStore();
const { module_setting } = orgInfo;
// 有 store 数据,从 store 取
if (orgNamespace === orgInfo.name && module_setting?.group_id) {
id.value = module_setting.group_id;
discussOpen.value = module_setting.modules.find(
(e: repoAndOrgSettingDictType) => e.key === 'DISCUSSION'
)?.value || '0';
} else {
// 无 store 数据,接口获取
const res = await getOrgDiscussionSettings({ orgId: orgNamespace });
if (!res.error) {
const resData = res?.data;
id.value = resData.group_id;
const discussStatus = resData.modules.find(
(e: repoAndOrgSettingDictType) => e.key === 'DISCUSSION'
).value; // 组织讨论是否开启, '0'关闭,'1'开启
if (discussStatus === '1') {
discussOpen.value = '1';
return;
}
}
}
} else {
const { repoInfo } = repoInfoStore();
const { module_setting } = repoInfo;
// 完整路径,供上传使用
const { repoId: fullRepoPath } = useRepoId('/');
fullRepoPath && (project_id.value = fullRepoPath.value);
// 有 store 数据,从 store 取
if (module_setting?.repo_id) {
id.value = module_setting.repo_id;
discussOpen.value = module_setting.modules.find(
(e: repoAndOrgSettingDictType) => e.key === 'DISCUSSION'
)?.value || '0';
} else {
// 无 store 数据,接口获取
const { repoId } = useRepoId();
const res = await getSettingsValues({
repoId: repoId.value
});
if (!res.error) {
const resData = res?.data?.data;
id.value = resData.repo_id;
const discussStatus = resData.modules.find(
(e: repoAndOrgSettingDictType) => e.key === 'DISCUSSION'
).value; // 项目讨论是否开启, '0'关闭,'1'开启
if (discussStatus === '1') {
discussOpen.value = '1';
return;
}
}
}
}
}
return { id, discussOpen, project_id, getDiscussionStatus };
}

477
src/api/discussion/index.ts Normal file
View File

@@ -0,0 +1,477 @@
import request from '@/utils/request';
import * as types from '@/api/discussion/types';
import { reqCatch } from '@/utils/catch';
import type { categoryType } from '@/api/discussion/types';
// ---------------------------- discussion CRUD ----------------------------- //
// 新增讨论
export function discussSave(data: types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss',
method: 'post',
data
}), data);
}
// discussion 列表
export function discussList(data: types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/page',
method: 'post',
data
}), data);
}
// 删除讨论
export function discussDelete(data: {id:string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss',
method: 'delete',
data
}), data);
}
// 更新讨论
export function discussUpdate(data: types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss',
method: 'put',
data
}), data);
}
// ---------------------------- discussion 详情操作 ----------------------------- //
// discuss 详情
export function discussDetail(data: {source_id: string, source_type:number, serial_number:string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/detail',
method: 'post',
data
}), data);
}
// 讨论新建-组织可 @ 成员列表
// TODO: 暂未提供
export function discussOrgMembers(data: types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/org/v1/member/list',
method: 'post',
data
}), data);
}
// 讨论新建 - 项目可 @ 成员列表
export function discussRepoMembers(params: { repoId: string, page?: number, per_page?: number }): Promise<any> {
const { repoId, ...param } = params;
return reqCatch(() => request({
url: `/api/v1/projects/${repoId}/members/all`,
method: 'get',
params: Object.assign({ page: 1, per_page: 10 }, param)
}), params);
}
// 讨论详情,更改 discuss 关联标签
export function discussChangeRelatedLabels(data:{discuss_id:string;label:string[]}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/label',
method: 'post',
data
}), data);
}
// 查询讨论关联用户列表,需要登录
export function discussDetailRelatedUsers(params:{source_id:string}) {
const { source_id } = params;
return reqCatch(() => request({
url: `/api/v1/discuss/relateUser/${source_id}`,
method: 'get'
}), params);
}
// 查询讨论最近活动用户,不需要登录
export function discussDetailRecentActiveUsers(params:{source_id:string}) {
const { source_id } = params;
return reqCatch(() => request({
url: `/api/v1/discuss/recentActivity/${source_id}`,
method: 'get'
}), params);
}
// discussion 讨论-总列表置顶/取消置顶
export function discussPin(data:{id: string;is_pin: 0|1}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/changePin',
method: 'post',
data
}), data);
}
// discussion 分类置顶/取消置顶
export function disussTypePin(data:{id: string;is_pin: 0|1}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/changeCatePin',
method: 'post',
data
}), data);
}
// 关闭/重新打开 讨论
export function discussClose(data:{id: string;state: number}): Promise<any> {
// 讨论的状态0打开1正常关闭2过期关闭3:重复关闭
return reqCatch(() => request({
url: '/api/v1/discuss/changeState',
method: 'post',
data
}), data);
}
// 讨论锁定/解锁
export function disussionLock(data:{id: string;is_lock: 0|1}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/changeLock',
method: 'post',
data
}), data);
}
// 更换已创建讨论的分类 - 侧边栏操作
export function discussChangeType(data:{id: string;category_id: string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/changeCate',
method: 'post',
data
}), data);
}
// 讨论-投票
export function discussVote(data:{discuss_id:string;option_id:string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/vote',
method: 'post',
data
}), data);
}
// 讨论 - 点赞
// targetType - 点赞的主体类型1讨论2评论3:评论回复
export function discussLike(data:{target_id:string; target_type:number}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/like',
method: 'post',
data
}), data);
}
// 讨论 - 取消点赞
// targetType - 点赞的主体类型1讨论2评论3:评论回复
export function discussUnLike(data:{target_id:string; target_type:number}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/unlike',
method: 'post',
data
}), data);
}
// ---------------------------- discussion 评论操作 ----------------------------- //
// 评论列表
export function commentList(data:{discuss_id: string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/comment/page',
method: 'post',
data
}), data);
}
// 新增评论
export function commentSave(data:types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/comment',
method: 'post',
data
}), data);
}
// 编辑评论
export function commentUpdate(data:types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/comment',
method: 'put',
data
}), data);
}
// 删除评论
export function commentDelete(data:{id:string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/comment',
method: 'delete',
data
}), data);
}
// 标记评论或者回复为答案
export function commentRemark(data:{id: string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/comment/remark',
method: 'post',
data
}), data);
}
// 取消标记评论或者回复为答案
export function commentUnremark(data:{id: string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/comment/unremark',
method: 'post',
data
}), data);
}
// ---------------------------- discussion 评论-回复 操作 ----------------------------- //
// 查询评论的回复列表
export function replyList(data:{parent_id: string, page:number; size:number }): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/comment/reply/page',
method: 'post',
data
}), data);
}
// 新增回复
export function replySave(data:types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/comment/reply',
method: 'post',
data
}), data);
}
// 编辑回复
export function replyUpdate(data:types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/comment/reply',
method: 'put',
data
}), data);
}
// 删除回复
export function replyDelete(data:{id:string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/comment/reply',
method: 'delete',
data
}), data);
}
// ---------------------------- 分类type CRUD ----------------------------- //
// 获取讨论分类的基础类型(字典)
export function categoryBasicType(params:types.commonDiscussionReqType) {
return reqCatch(() => request({
url: `/api/v1/discuss/category/type`,
method: 'get'
}), params);
}
// 获取某个项目或仓库下的所有讨论分类
export function getAllTypes(params: {id: string;source_type:number}) {
const { id, source_type } = params;
return reqCatch(() => request({
url: `/api/v1/discuss/category/list/${id}/${source_type}`,
method: 'get'
}), params);
}
// 获取某个项目或者仓库下的所有讨论分类和分组
// 用于「管理内容分类」页
export function getAllSectionAndTypes(params: {source_id: string, source_type:number}) {
const { source_id, source_type } = params;
return reqCatch(() => request({
url: `/api/v1/discuss/category/all/${source_id}/${source_type}`,
method: 'get'
}), params);
}
// 新增讨论分类 type
export function typeSave(data:types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/category',
method: 'post',
data
}), data);
}
// 讨论分类 type 详情
export function typeDetail(params: {id: string|undefined}):Promise<any> {
const { id } = params;
return reqCatch(() => request({
url: `/api/v1/discuss/category/detail/${id}`,
method: 'get'
}), params);
}
// 更新 type
export function typeUpdate(data:types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/category',
method: 'put',
data
}), data);
}
// 删除讨论分类 type
export function typeDelete(data:{id: string, transfer_id?:string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/category',
method: 'delete',
data
}), data);
}
// ---------------------------- section CRUD ----------------------------- //
// 新增 section
export function sectionSave(data:types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/section',
method: 'post',
data
}), data);
}
// section 详情
export function sectionDetail(params: {id: string|undefined}) {
const { id } = params;
return reqCatch(() => request({
url: `/api/v1/discuss/section/detail/${id}`,
method: 'get'
}), params);
}
// 更新 section
export function sectionUpdate(data:types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/section',
method: 'put',
data
}), data);
}
// 删除 section
export function sectionDelete(data:{id: string}): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/section',
method: 'delete',
data
}), data);
}
// 根据分组 id 获取下面所有内容分类
export function sectionOwnCategory(params: {section_id: string}) {
const { section_id } = params;
return reqCatch(() => request({
url: `/api/v1/discuss/category/section/${section_id}`,
method: 'get'
}), params);
}
// 查询仓库/组织下的讨论分组
export function getAllSections(params: {source_id: string; source_type:number}) {
const { source_id, source_type } = params;
return reqCatch(() => request({
url: `/api/v1/discuss/section/list/${source_id}/${source_type}`,
method: 'get'
}), params);
}
// ----------------------------------- else --------------------------//
// 组织标签列表
// TODO: 组织还没有标签
export function orgLabelList(params: {group_id:string}): Promise<any> {
const { group_id } = params;
return reqCatch(() => request({
url: `/api/v4/groups/${group_id}/labels`,
method: 'get',
params: { page: 1, per_page: 20 }
}), params);
}
// 仓库标签列表
export function repoLabelList(params: {project_id:string}): Promise<any> {
const { project_id } = params;
return reqCatch(() => request({
url: `/api/v1/projects/${project_id}/labels`,
method: 'get',
params: { page: 1, per_page: 20 }
}), params);
}
// 当前用户-项目权限
export function getRepoPermission(params: { repo_id: string }) {
const { repo_id } = params;
return reqCatch(() => request({
url: `/api/v1/projects/${repo_id}/role`,
method: 'get'
}), params);
}
// 当前用户-组织权限
export function getOrgPermission(params:{group_id:string}): Promise<any> {
const { group_id } = params;
return reqCatch(() => request({
url: `/api/v2/groups/${group_id}`,
method: 'get',
params
}, {
customError: true
}));
}
// 获取社区热心榜单
export function getAnswerRank(params: {source_id: string, source_type:number}): Promise<any> {
const { source_id, source_type } = params;
return reqCatch(() => request({
url: `/api/v1/discuss/answerSort/${source_id}/${source_type}`,
method: 'get'
}), params);
}
// ------------------------------ Dashboard 我的讨论,我参与的讨论 ---------------------------------------------------//
// 我创建的讨论列表
export function myCreatedDiscuss(data:types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/my/page',
method: 'post',
data
}), data);
}
// 我参与的讨论列表
export function myJoineddDiscuss(data:types.commonDiscussionReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/discuss/join/page',
method: 'post',
data
}), data);
}
// 获取评论原始数据
export function getDiscussionOriginalData(id: string) {
return reqCatch(() => request({
url: `/api/v1/discuss/comment/origin_detail/${id}`,
method: 'get',
params: {}
}));
}
// 获取评论详情, 子评论的话, 同时获取父级评论信息
export function getDiscussionDetail(id: string) {
return reqCatch(() => request({
url: `/api/v1/discuss/comment/detail/${id}`,
method: 'get',
params: {}
}));
}

208
src/api/discussion/types.ts Normal file
View File

@@ -0,0 +1,208 @@
import { type errorType } from '@/api/types/common';
export interface commonDiscussionReqType {
[propName: string]: any;
}
export interface commonDiscussionResType extends errorType {
[propName: string]: any;
}
export interface commonDictType {
label: string;
value: string;
desc?: string; // 描述
color?: string;
hover_color?: string;
children?: any[];
}
export interface commonPaginationType {
page: number;
size: number;
}
export interface discussionListItemType {
id: string; // 讨论id
title: string;
section_id?: string;
category_id?: string;
category_type?: number; // 讨论类型4种,1-开放讨论2-问答3-公告4-投票
category_icon?:string;
category_name?: string;
comment_total?: number; // 评论总数
reply_total?: number; // 回复总数
like_total?: number | null;
is_like?: boolean; // 是否已点赞: true 已点赞false 未点赞
is_lock?: number; // 是否锁定01
is_pin?: number; // 是否置顶01
pin_date?: string;
is_category_pin?: number; // 是否分类置顶
pin_category_date?: string;
is_closed?: number; // 是否关闭
closed_date?: string;
is_answered?: number; // 回答是否采纳,01
label?: string[]; // labels
serial_number?: number; // 顺序号
created_by?: string; // 创建者id
created_by_user_name?: string;
created_by_user_photo?: string;
created_date?: string;
last_modified_date?: string;
category:categoryType; // 分类信息
source_type?:number; // 组织1项目2
source_id?:string;
}
export interface RadioOption<T> {
value: T;
label: string;
}
export interface repoAndOrgSettingDictType {
key:string;
type:string;
value:string;
};
// 讨论分类 || 讨论分组 itemType
export interface discussionTypeOrSection {
id: string;
icon: string;
title: string;
desc?: string;
answerAcceptEnable?: boolean;
isGroup: boolean;
categoryType?:number;
}
export interface categoryType {
id: string; // categoryId
category_name: string;
category_desc?: string;
category_type: number; // 讨论类型4种,1-开放讨论2-问答3-公告4-投票,不过现在有个专门的接口来查
section_id?: string; // 所属分组
category_icon: string; // icon
}
export interface sectionType {
id:string;
section_name:string;
section_icon:string;
}
export interface sectionOwnCategoryType extends sectionType {
category_list: categoryType[];
}
export interface sectionItemType {
unSection?: categoryType[];
section: sectionOwnCategoryType[];
}
export interface discussDetailType {
id:string;
category_id:string;
category?:categoryType;
created_by?:string;
created_date?:string;
created_by_user_name?:string;
created_by_user_photo?:string;
serial_number:number;
title:string;
content:string;
md_content:string;
is_lock:number; // 是否锁定10
is_pin:number;
pin_date?:string;
is_category_pin:number;
pin_category_date?:string;
is_closed:number; // 是否关闭10
closed_date?:string;
is_answered:number;
comment_total:number;
reply_total?:number;
like_total?:number;
is_like?:boolean;
question?:questionInfoType;
options?:quesitonOptionType[];
is_vote?:boolean; // 是否投过票
option_id?:string; // 投过票的id
label?:string[]; // 关联的 labels
is_edit?:boolean; // 投票类型的讨论 - 更新时是否变更了投票内容(标题 + 选项)
}
export interface commentType {
id:string;
content?:string;
md_content:string;
discuss_id?:string;
parent_id?:string;
serial_number?:number;
source_id?:string;
source_type?:number;
last_modified_date?:string;
last_modified_by?:string;
created_by?:string;
created_date?:string;
created_by_user_name?:string;
created_by_user_photo?:string;
ip?:string;
is_hide?:number; // 是否隐藏评论
reply_total?:number;
like_total?:number;
is_like?:boolean; // true:已点赞false:未点赞
is_deleted?:number;
is_remark?: number; // 是否采纳为答案10:否
replyCover?: any;
}
export interface questionInfoType {
created_by:string;
created_date:string;
id:string;
last_modified_by?:string;
last_modified_date?:string;
question:string; // 投票的标题
vote_total:number; // 投票参与总人数
}
// 投票选项信息
export interface quesitonOptionType {
created_by:string;
created_date:string;
id:string; // 投票选项id
last_modified_by?:string;
last_modified_date?:string;
option_order:number; // 投票选项顺序
vote_id:string;
vote_option:string;
vote_total:number;
vote_total_percent:number; // 选项投票百分比
}
export interface ISidebar {
id?:string; // discuss id,详情页才显示参与者和操作按钮组
labelDicts?:commonDictType[]; // 标签字典
checkedLabelIds?:string[]; // 已关联 label ids
checkedLabels?:commonDictType[]; // 要渲染的已选label list
setLabels?:Function; // emit 关联标签
categoryDicts?:commonDictType[];
checkedCategoryId?:string;
checkedCategory?:commonDictType;
changeCategory?:Function;
participators?:any[];
}
export interface userInfoType {
domain_id?: string
email?: string
id?: string
mobile?: string
nickname?: string
username?: string
access_token?: string
refresh_token?: string
xauth_token?: string
[x: string]: any
}

105
src/api/home/index.ts Normal file
View File

@@ -0,0 +1,105 @@
import request from '@/utils/request';
import * as types from '@/api/home/types';
import { reqCatchV2, type catchRt } from '@/utils/catch';
// 获取banner
export function getBanner(): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/banner`,
method: 'get'
});
}
// 获取活跃社区
export function getCommunity(): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/active_community`,
method: 'get'
});
}
// 获取精选项目
export function getSelectedRepo(): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/selected_projects`,
method: 'get'
});
}
// 获取运营广告
export function getAdvertisement(): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/advertisement`,
method: 'get'
});
}
// 获取推荐项目列表
export function getRecommendedRepos(): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/recommended_projects`,
method: 'get'
});
}
// 获取活跃组织列表
export function getActiveOrganization(): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/active_organization`,
method: 'get'
});
}
// 活跃社区项目列表
export function getCommunityActiveRepos(): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/community_active_repos`,
method: 'get'
});
}
// 活跃社区项目列表
export function getDynamicRemarks(): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/dynamic_remarks`,
method: 'get'
});
}
// 首页搜索
export function homeSearchProject(params: {search:string}): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/projects/search`,
method: 'get',
params
});
}
// 首页全球精选开源组织
export function globalFeaturedGroups(): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/groups/global/featured`,
method: 'get'
});
}
// 全球精选开源项目
export function globalFeaturedProjects(params:{
group_id:string
page:number
per_page:number
}): Promise<types.commonHomeResType> {
return request({
url: `/api/v1/home_page/projects/global/featured`,
method: 'get',
params
});
}
// 获取搜索历史记录
export function getSearchHistory(params: object): catchRt<types.commonHomeResType> {
return reqCatchV2(() => request({
url: `/api/v1/search/searchHistory`,
method: 'get',
params
}));
}
// 删除搜索历史记录
export function delSearchHistory({ thread_id }:{thread_id:string}): catchRt<types.commonHomeResType> {
return reqCatchV2(() => request({
url: `/api/v1/search/searchHistory/${thread_id}`,
method: 'delete'
}));
}

30
src/api/home/types.ts Normal file
View File

@@ -0,0 +1,30 @@
import { type errorType } from '@/api/types/common';
export interface commonHomeReqType extends errorType {
[propName: string]: any;
}
export interface commonHomeResType extends errorType {
[propName: string]: any;
}
// 搜索项目信息
export interface projectSearchInfo {
id: number;
description: string;
name: string;
namespace: string;
name_with_namespace: string;
path: string;
path_with_namespace: string;
web_url: string;
star_count: number;
forks_count: number;
starred: true;
created_at: string;
last_activity_at: string;
main_repository_language: string[];
star_count_seven: number;
license?: string;
topic?: {topic_id:string, name:string}[]
}

218
src/api/issue/index.ts Normal file
View File

@@ -0,0 +1,218 @@
import request from '@/utils/request';
import * as types from '@/api/issue/types';
import { reqCatch, reqCatchV2, type catchRt } from '@/utils/catch';
export function createIssue(data: types.createIssueReqType): Promise<types.createIssueResType> {
return request({
url: `/api/v1/issue/${data.project_id}/issues`,
method: 'post',
data
});
}
export function deleteIssue(params: types.createIssueReqType): Promise<types.createIssueResType> {
return request({
url: `/api/v1/issue/${params.project_id}/issues/${params.issue_iid}`,
method: 'delete'
});
}
export function updateIssue(data: types.updateIssueReqType): Promise<types.updateIssueResType> {
const { project_id, issue_iid } = data;
delete data.project_id;
delete data.issue_iid;
return request({
url: `/api/v1/issue/${project_id}/issues/${issue_iid}`,
method: 'put',
data
});
}
// 关闭或打开issue
export function updateIssueStat(data: types.updateIssueStatReqType): Promise<types.updateIssueStatResType> {
const { project_id, issue_iid } = data;
delete data.project_id;
delete data.issue_iid;
return request({
url: `/api/v1/issue/${project_id}/issues/${issue_iid}/close`,
method: 'put',
data
});
}
export function fetchIssue(params: types.fetchIssueReqType): Promise<types.fetchIssueResType> {
return request({
url: `/api/v1/issue/${params.project_id}/issues/${params.issue_iid}`,
method: 'get'
});
}
// 项目issue列表
export function fetchIssueList(params: types.fetchIssueListReqType): Promise<types.fetchIssueListResType> {
return request({
url: `/api/v1/issue/${params.project_id}/issues`,
method: 'get',
params
});
}
export function createIssueDiscussions(data: types.createIssueDiscussionsReqType): Promise<types.createIssueDiscussionsResType> {
return request({
url: `/api/v1/issue/${data.project_id}/issues/${data.issue_iid}/discussions`,
method: 'post',
data
});
}
export function updateIssueDiscussions(data: types.updateIssueDiscussionsReqType): Promise<types.updateIssueDiscussionsResType> {
return request({
url: `/api/v1/projects/${data.project_id}/issues/${data.issue_iid}/notes/${data.note_id}`,
method: 'put',
data
});
}
export function deleteIssueDiscussions(params: types.deleteIssueDiscussionsReqType): Promise<types.deleteIssueDiscussionsResType> {
return request({
url: `/api/v1/projects/${params.project_id}/issues/${params.issue_iid}/notes/${params.note_id}`,
method: 'delete',
params
});
}
export function fetchIssueDiscussions(params: types.fetchIssueDiscussionsResType): Promise<types.fetchIssueDiscussionsResType> {
return request({
url: `/api/v1/issue/${params.project_id}/issues/${params.issue_iid}/discussions`,
method: 'get',
params
});
}
// 获取issue单条评论
export function fetchIssueNote(params: types.fetchIssueDiscussionsResType): Promise<types.fetchIssueDiscussionsResType> {
return request({
url: `/api/v1/projects/${params.project_id}/issues/${params.issue_iid}/notes/${params.note_id}`,
method: 'get'
});
}
// 回复issue评论
export function freplyIssueDiscussions(data: types.createIssueReqType): Promise<types.createIssueResType> {
return request({
url: `/api/v1/issue/api/v4/projects/${data.project_id}/issues/${data.issue_iid}/discussions/${data.discussion_id}/notes`,
method: 'post',
data
});
}
// issue参与者
export function issueParticipants(data: types.issueParticipantsResType): Promise<types.issueParticipantsReqType> {
return request({
url: `/api/v1/issue/${data.project_id}/issues/${data.issue_iid}/participants`,
method: 'get'
});
}
// issue 精选
export function pinIssue(params: types.pinIssueReqType): Promise<types.pinIssueResType> {
return request({
url: `/api/v1/featured/${params.type}`,
method: 'post',
params
});
}
export function deletePinIssue(params: types.deletePinIssueReqType): Promise<types.deletePinIssueResType> {
return request({
url: `/api/v1/featured/${params.type}`,
method: 'delete',
params
});
}
// 精选排序
export function sortPinIssue(data): Promise<types.pinIssueListResType> {
const { type, group_id, body } = data;
return request({
url: `/api/v1/featured/${type}/resort?group_id=${group_id}`,
method: 'put',
data: body
});
}
export function pinIssueList(params: types.pinIssueListReqType): Promise<types.pinIssueListResType> {
return request({
url: `/api/v1/featured/projects/${params.project_id}/issues`,
method: 'get'
});
}
// 我的issue列表
export function myIssueList(params: types.fetchIssueListReqType): Promise<types.fetchIssueListResType> {
return request({
url: `/api/v1/issues`,
method: 'get',
params
});
}
// 我的issue列表数量
export function myIssueListState(params: types.myIssueListStateReptype): Promise<types.myIssueListStateRestype> {
return request({
url: `/api/v1/issues/statistics`,
method: 'get',
params
});
}
// 组织的issue列表
export function groupIssueList(params: types.fetchIssueListResType): Promise<types.fetchIssueListResType> {
const { group_id } = params;
delete params.group_id;
return request({
url: `/api/v1/groups/${group_id}/issues`,
method: 'get',
params
});
}
// 获取issue关联的PR列表
export function getIssuePRList(params: types.fetchIssueListResType): Promise<types.fetchIssueListResType> {
const { project_id, issue_iid } = params;
delete params.project_id;
delete params.issue_iid;
return request({
url: `/api/v1/issue/${project_id}/issues/${issue_iid}/linked_merge_requests`,
method: 'get',
params
});
}
// issue关联PR
export function issueRelatePR(data: types.updateIssueReqType): Promise<types.fetchIssueListResType> {
return reqCatch(
() => request({
url: `/api/v1/issue/${data.project_id}/issues/${data.issue_id}/merge_request/${data.merge_request_id}/linked_merge_requests`,
method: 'post'
})
,
data
);
}
// issue取消关联PR
export function issueDeletePR(params: types.updateIssueReqType): Promise<types.fetchIssueListResType> {
return reqCatch(
() => request({
url: `/api/v1/issue/${params.project_id}/issues/${params.issue_id}/linked_merge_requests/${params.merge_request_id}`,
method: 'delete'
})
,
params
);
}
// 获取issue模版列表
export function fetchIssueTemplateList(project_id: string): Promise<Record<string, any>> {
return request({
url: `/api/v2/projects/${project_id}/repository/template/issue`,
method: 'get',
params: {}
}).catch((e) => {
return { data: [], error_code: e };
});
}

322
src/api/issue/types.ts Normal file
View File

@@ -0,0 +1,322 @@
export interface createIssueReqType {
project_id?: string;
issue_iid?: number;
title?: string;
description?: string;
updated_at?: string;
state_event?: 'reopen' | 'close';
assignee_id?: number;
assignee_ids?: string[];
milestone_id?: number;
labels?: ILabel[] | string[];
due_date?: string;
confidential?: boolean;
discussion_locked?: true;
created_at?: string;
issue_category?: string;
issue_stage?: string;
issue_severity?: string;
pbi_id?: number;
proposer_id?: string[];
[propName: string]: any;
}
export interface createIssueResType extends IIssue {
[propName: string]: any;
}
export interface deleteIssueReqType {
project_id: string;
issue_iid: number;
[propName: string]: any;
}
export interface deleteIssueResType {
[propName: string]: any;
}
export interface createIssueDiscussionsResType extends IIssue {
[propName: string]: any;
}
export interface createIssueDiscussionsReqType {
project_id: string;
issue_iid: number;
[propName: string]: any;
}
export interface fetchIssueResType {
project_id: string;
issue_iid: number;
[propName: string]: any;
}
export interface fetchIssueReqType extends IIssue {
[propName: string]: any;
}
export interface fetchIssueListReqType {
project_id: string;
state?: string;
sort?: string;
scope?: string;
search?: string;
page?: number;
per_page?: number;
[propName: string]: any;
}
export interface fetchIssueListResType extends IIssue {
[propName: string]: any;
}
export interface myIssueListStateReptype {
state: string;
[propName: string]: any;
}
export interface myIssueListStateRestype extends IIssue {
[propName: string]: any;
}
export interface issueParticipantsResType {
project_id: string;
issue_iid: number;
[propName: string]: any;
}
export interface issueParticipantsReqType extends IAuthor {
[propName: string]: any;
}
export interface fetchIssueDiscussionsResType {
project_id: string;
issue_iid: number;
type: 'user';
[propName: string]: any;
}
export interface fetchIssueDiscussionsReqType extends Idiscussions {
[propName: string]: any;
}
export interface updateIssueReqType extends createIssueReqType {
[propName: string]: any;
}
export interface updateIssueResType extends IIssue {
[propName: string]: any;
}
export interface updateIssueStatReqType extends createIssueReqType {
discussions?: string;
[propName: string]: any;
}
export interface updateIssueStatResType extends IIssue {
[propName: string]: any;
}
export interface updateIssueDiscussionsReqType {
project_id: string;
issue_iid: number;
note_id: string;
[propName: string]: any;
}
export interface updateIssueDiscussionsResType {
[propName: string]: any;
}
export interface deleteIssueDiscussionsReqType {
project_id: string;
issue_iid: number;
note_id: string;
[propName: string]: any;
}
export interface deleteIssueDiscussionsResType {
[propName: string]: any;
}
export interface pinIssueReqType {
type: 'project_issue';
resource_id: number | string;
[propName: string]: any;
}
export interface pinIssueResType {
[propName: string]: any;
}
export interface deletePinIssueReqType {
type: 'project_issue';
group_id: string;
resource_id: string;
[propName: string]: any;
}
export interface deletePinIssueResType {
[propName: string]: any;
}
export interface sortPinIssueReqType {
type: 'project_issue';
group_id: string;
body: string;
[propName: string]: any;
}
export interface sortPinIssueResType {
[propName: string]: any;
}
export interface pinIssueListReqType {
project_id: string;
[propName: string]: any;
}
export interface pinIssueListResType {
object_id: string,
type: string,
resource_id: string,
nextResource_id: string
[propName: string]: any;
}
// 用户
export interface IAuthor {
id: number;
name: string;
username: string;
state: 'active' | string;
avatar_url: string;
avatar_path?: string;
email?: string;
name_cn: string;
web_url: string;
nick_name?: string;
tenant_name?: string;
avatar?: string;
nickname?: string;
is_member?: string;
}
// 项目
export interface IProject {
id: number;
description?: string;
name: string;
name_with_namespace: string;
path: string;
path_with_namespace: string;
develop_mode?: 'normal' | string;
created_at: string;
updated_at?: string;
archived: false;
is_kia: false;
ssh_url_to_repo: string;
http_url_to_repo: string;
web_url: string;
readme_url?: string;
product_id?: string;
product_name?: string;
}
// issue
export interface IIssue {
id?: number;
iid?: number;
project_id?: number;
title?: string;
description?: string;
editIng?: boolean;
saveIng?: boolean;
editText?: string;
state?: 'opened' | 'closed' | 'all';
created_at?: string;
updated_at?: string;
closed_at?: string;
closed_by?: string;
labels?: ILabel[];
milestone?: string;
assignees?: [];
author?: IAuthor;
assignee?: string;
user_notes_count?: number;
merge_requests_count?: number;
confidential?: boolean;
discussion_locked?: boolean;
web_url?: string;
time_stats?: {
time_estimate?: string
total_time_spent?: string
human_time_estimate?: string
human_total_time_spent?: string
};
project_path_with_namespace?: string;
project?: IProject;
root_project_id?: string;
subscribed?: boolean;
related_merge_request?: string;
linked_merge_requests?: [];
related_note_params?: null;
[propName: string]: any;
}
// 评论
export interface INote {
id: number | string;
type: 'DiscussionNote' | string;
body: string;
attachment?: null;
author: IAuthor;
created_at: string;
updated_at: string;
system?: boolean;
noteable_id: number;
noteable_type: 'Issue' | string;
commit_id?: string;
resolvable?: boolean;
is_reply?: boolean;
resolved_by?: null;
noteable_iid: number;
discussion_id: string;
project: string;
diff_file?: null;
diff: string;
archived: boolean;
review_categories?: null;
review_categories_cn: string;
review_categories_en: string;
review_modules?: null;
severity: 'suggestion';
severity_cn: '建议' | string;
severity_en: 'Suggestion' | string;
file_path?: string;
line?: string;
assignee?: string;
proposer: IAuthor;
}
// 评论
export interface Idiscussions extends INote {
id: string | number,
individual_note?: boolean,
notes: INote[],
project_id: number,
project_full_path: string,
deleted_file?: null,
new_file?: null,
added_lines?: null,
removed_lines?: null,
issue?: null,
merge_request_version_params?: null,
amode?: null,
bmode?: null
}
// 标签
export interface ILabel {
color: string;
description: string;
expires_at?: string
id: number
is_expired: boolean;
name: string;
text_color: string;
}

47
src/api/labels/index.ts Normal file
View File

@@ -0,0 +1,47 @@
import request from '@/utils/request';
import { reqCatch } from '@/utils/catch';
import type { ProjectLabelsReqType, LabelsReqType } from './types';
const defaultPages = {
page: 1,
per_page: 10
};
/** 获取项目labels */
export function getProLabels(params: ProjectLabelsReqType): Promise<any> {
const { project_id, ...conf } = params;
return reqCatch(() => request({
url: `/api/v1/projects/${project_id}/labels`,
params: Object.assign({ ...defaultPages }, conf)
}), params);
}
/** 新增项目label */
export function createProjectLabels(data: LabelsReqType) {
const { project_id, ...conf } = data;
return reqCatch(() => request({
url: `/api/v1/projects/${project_id}/labels`,
data: Object.assign({ ...conf }),
method: 'post'
}), data);
}
/** 编辑项目标签 */
export function editProjectLabels(data: LabelsReqType & { new_name: string }) {
const { project_id, ...conf } = data;
return reqCatch(() => request({
url: `/api/v1/projects/${project_id}/labels`,
data: conf,
method: 'put'
}), data);
}
/** 删除标签 */
export function deleteProjectLabels(data: { project_id: string, name: string }) {
const { project_id, name } = data;
return reqCatch(() => request({
url: `/api/v1/projects/${project_id}/labels?name=${name}`,
method: 'delete'
}));
}

19
src/api/labels/types.ts Normal file
View File

@@ -0,0 +1,19 @@
export interface ProjectLabelsReqType {
project_id: string;
search?: string
sort?: 'asc' | 'desc'
include_expired?: boolean
most_active_ones?: boolean
view?: 'simple' | 'basic' | 'detail'
page?: number
per_page?: number
}
export interface LabelsReqType {
project_id: string;
name: string
color: string
description: string
priority?: number // 优先级
expires_at?: string // 过期时间
}

185
src/api/merge/index.ts Normal file
View File

@@ -0,0 +1,185 @@
import request from '@/utils/request';
import * as types from '@/api/merge/types';
const removeParamsPathId = (data: types.commonMergeReqType): types.commonMergeReqType => {
delete data.project_id;
delete data.merge_request_iid;
delete data.discussion_id;
delete data.note_id;
delete data.group_id;
delete data.note_id;
return data;
};
const urlPre = '/api/v1/projects/';
const httpGet = (url: string, params: types.commonMergeReqType): Promise<types.commonMergeResType> => request({
url: urlPre + url,
method: 'get',
params
});
const httpPost = (url: string, data: types.commonMergeReqType): Promise<types.commonMergeResType> => request({
url: urlPre + url,
method: 'post',
data
}, { customError: true });
const httpPut = (url: string, data: types.commonMergeReqType): Promise<types.commonMergeResType> => request({
url: urlPre + url,
method: 'put',
data
}, { customError: true });
const httpDel = (url: string, data: types.commonMergeReqType): Promise<types.commonMergeResType> => request({
url: urlPre + url,
method: 'delete',
data
}, { customError: true });
// 创建合并请求
export const createMerge = data => httpPost(`${data.repoId}/merge_requests`, data);
// 修改合并请求
export const putMerge = data => httpPut(`${data.repoId}/isource/merge_requests/${data.iid}`, data);
// 修改审核人
export const putApprovers = data => httpPut(`${data.repoId}/merge_requests/${data.iid}/approval_approvers`, data);
// 修改检视人
export const putReviewers = data => httpPut(`${data.repoId}/merge_requests/${data.iid}/approval_reviewers`, data);
// 详情已分配合并人列表
export const assignees = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/assignees`, data);
// 详情分配合并人(筛选项)
export const assigneeCandidates = data => httpGet(`${data.repoId}/merge_requests/assignee_candidates`, data);
// 详情获取已分配检视人
export const approvalReviewers = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/approval_reviewers`, data);
export const updateApprovalReviewers = data => httpPut(`${data.repoId}/merge_requests/${data.iid}/approval_reviewers`, data);
// 详情获取已分配检视人(筛选项)
export const approvalReviewersOption = params => httpGet(`${params.repoId}/merge_requests/approval_reviewers`, params);
// 详情获取已关联issue
export const fetchPRIssueList = params => httpGet(`${params.project_id}/merge_requests/${params.merge_request_iid}/e2e_issues`, params);
export const updateIssueList = params => httpPut(`${params.project_id}/isource/merge_requests/${params.merge_request_iid}`, params);
// 列表页 获取审视人(不关联mr)
export const fetchApprovalReviewers = params => httpGet(`${params.repoId}/merge_requests/reviewers`, params);
// 列表页 获取审视人(不关联mr)
// 获取pr模版
export const fetchPrTemplate = (params:{ project_id: string }) => request({
url: `/api/v2/projects/${params.project_id}/repository/template/pr`,
method: 'get'
});
// 获取pr 门禁默认设置人员
export const fetchPrSetDefaultPerson = (params: types.commonMergeReqType) => httpGet(`${params.repoId}/create_merge_requests/person_liable`, params);
// 创建时搜索门禁人员列表
export const searchPrSetPerson = (params: types.commonMergeReqType) => httpGet(`${params.repoId}/merge_requests_create/search_person_liable`, params);
// 获取已经设置门禁人员列表 汇总 评审人,审查人,测试人
export const fetchPrExaminePerson = (params: types.commonMergeReqType) => httpGet(`${params.repoId}/merge_requests/${params.iid}/person_liable`, params);
// 搜索 门禁设置人员
export const searchPrExaminePerson = (params: types.commonMergeReqType | { merge_request_iid:string; source_branch: string; target_branch: string;
search_type: string; target_project_id: string; project_id:string, approval_type: string; search: string; page: number; per_page: number;
}) => httpGet(`${params.repoId}/merge_requests/${params.iid}/search_person_liable`, params);
// 获取门禁配置 汇总版 评审人,审查人,测试人
export const fetchPrExaminerules = (params: types.commonMergeReqType) => httpGet(`${params.repoId}/merge_requests/${params.iid}/person_liable_rules`, params);
// 指定配置各个门禁人员配置
export const editPrExaminePerson = (data: types.commonMergeReqType) => request({
url: `/api/v1/projects/${data.repoId}/merge_requests/${data.iid}/person_liable`,
method: 'put',
data
});
// 审查门禁
export const examineApproval = (data:types.commonMergeReqType & {action_type:'approve'|'reset'}) => request({
url: `/api/v1/projects/${data.repoId}/merge_requests/${data.iid}/approval`,
method: 'put',
data
});
// 测试门禁
export const examineTester = (data:types.commonMergeReqType & {action_type:'pass'|'reset'}) => request({
url: `/api/v1/projects/${data.repoId}/merge_requests/${data.iid}/approval_test`,
method: 'put',
data
});
// 合并
export const merge = data => httpPut(`${data.repoId}/merge_requests/${data.iid}/merge`, data);
// 关闭
export const closeMerge = data => httpPut(`${data.repoId}/isource/merge_requests/${data.iid}`, data);
// 仓库MR创建者列表
export const users = data => httpGet(`${data.repoId}/merge_requests/users`, data);
// 项目MR列表
export const getMergeRequests = data => httpGet(`${data.repoId}/isource/merge_requests`, data);
export const getMergeListCount = data => httpGet(`${data.repoId}/isource/merge_requests/count`, data);
// 我的MR 列表
export const getMyMergeRequests = (params: object) => request({ url: '/api/v1/merge_requests', method: 'get', params });
// 组织 mr 列表
export const getMyOrgMergeRequests = (params: object) => request({ url: `/api/v1/groups/${params.group_id}/merge_requests`, method: 'get', params });
// 合并请求详情 @param view:[simple,basic]
export const mergeDetail = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/internal`, data);
// 讨论列表
export const mrDiscussions = data => httpGet(`${data.project_id}/merge_requests/${data.merge_request_iid}/discussions`, removeParamsPathId(data));
// 获取评论详情
export const getMrNote = data => httpGet(`${data.project_id}/merge_requests/${data.merge_request_iid}/notes/${data.note_id}`, removeParamsPathId(data));
// 创建评论 - 代码评论 - 有解决状态
export const addMRDiscussion = data => httpPost(`${data.project_id}/merge_requests/${data.merge_request_iid}/discussions`, removeParamsPathId(data));
// 更新 评论
export const updateMRDiscussion = data => httpPut(`${data.project_id}/merge_requests/${data.merge_request_iid}/discussions/${data.discussion_id}`, removeParamsPathId(data));
// 创建评论 没有 解决状态
export const addMRDiscussionNote = data => httpPost(`${data.project_id}/merge_requests/${data.merge_request_iid}/notes`, removeParamsPathId(data));
// 修改评论
export const putDiscussionsNotes = data => httpPut(`${data.project_id}/merge_requests/${data.merge_request_iid}/notes/${data.note_id}`, data);
// 创建回复评论
export const replayDiscussionsNote = data => httpPost(`${data.project_id}/merge_requests/${data.merge_request_iid}/discussions/${data.discussion_id}/notes`, data);
// export const updateReplayDiscussionsNote = data => httpPut(`${data.project_id}/merge_requests/${data.merge_request_iid}/discussions/${data.discussion_id}/notes/${data.note_id}`, data);
// 删除 mr 评论
export const delMRDiscussionsNote = (data) => request({
url: `/api/v1/projects/${data.project_id}/merge_requests/${data.merge_request_iid}/notes/${data.note_id}`,
method: 'delete'
});
// 代码评论 - 没有解决状态
export const postNotes = data => httpPost(`${data.repoId}/merge_requests/${data.iid}/notes`, data);
// 文件提交记录 commit 记录 - 查库
export const commits = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/commits`, data);
// 检查列表 (合并门禁)
export const mergeableState = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/mergeable_state`, data);
// 文件差异 查库
export const changes = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/changes`, data);
// 文件差异目录
export const changesTrees = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/changes_trees`, data);
// revert
export const revert = data => httpPost(`${data.repoId}/merge_request/${data.iid}/revert`, data);
// cherry-pick
export const cherryPick = data => httpPost(`${data.repoId}/merge_request/${data.iid}/cherry_pick`, data);
// // issue关联MR
// export const revert = data => httpPut(`${data.repoId}/isource/merge_requests/${data.iid}`, data);
// // MR详情获取关联issue
// export const e2eIssues = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/e2e_issues`, data);
export const versions = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/versions`, data);
// 获取评审人数
export const getReviewers = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/reviewer_rules`, data);
// discussions
export const getDis = data => httpGet(`${data.repoId}/merge_requests/${data.iid}/comments_by_line`, data);
export const postDis = data => httpPost(`${data.repoId}/merge_requests/${data.iid}/discussions`, data);
export const putDis = data => httpPut(`${data.repoId}/merge_requests/${data.iid}/discussions/${data.disId}`, data);
export const postNote = data => httpPost(`${data.repoId}/merge_requests/${data.iid}/discussions/${data.disId}/notes`, data);
export const putNote = data => httpPut(`${data.repoId}/merge_requests/${data.iid}/notes/${data.noteId}`, data);
export const delNote = data => httpDel(`${data.repoId}/merge_requests/${data.iid}/notes/${data.noteId}`, data);
export const diffLines = data => httpGet(`${data.repoId}/repository/diff_lines`, data);
// 检视意见统计信息与门禁信息
export const statistic = data => httpGet(`${data.repoId}/merge_requests/statistic`, data);
export const conflict_files = data => httpGet(`${data.repoId}/merge_requests/conflict_files`, data);
export const convertMrComment = data => httpPut(`${data.repoId}/merge_requests/${data.iid}/approval_reviewers`, data);
// 变基rebase
export const changeMrRebase = data => httpPut(`${data.repoId}/merge_requests/${data.iid}/rebase`, data);
// 重新打开
export const reOpen = data => httpPut(`${data.repoId}/isource/merge_requests/${data.iid}`, data);
// MR详情审核人审核通过/拒绝/撤销按钮
export const putApproval_review = data => request({
url: `/api/v1/projects/${data.repoId}/merge_requests/${data.iid}/approval_review`,
method: 'put',
data
});
// 最新一次流水线 show_job =true
export const actual_head_pipeline = (repoId, iid, data) => httpGet(`${repoId}/merge_requests/${iid}/actual_head_pipeline`, data);
export const quality = (repoId, pipeId) => httpGet(`${repoId}/pipelines/${pipeId}/quality`);
export const diverged_commits_count = (repoId, iid) => httpGet(`${repoId}/merge_requests/${iid}/diverged_commits_count`);

46
src/api/merge/types.ts Normal file
View File

@@ -0,0 +1,46 @@
import { type errorType } from '@/api/types/common';
export interface commonMergeReqType {
repoId: string
iid: string
[propName: string]: any;
}
export interface commonMergeResType extends errorType {
[propName: string]: any;
}
export interface IMergeableState {
'merge_request_id': number, // 合并请求ID
'state': boolean,
'status_without_user_auth': boolean, // 无用户授权的状态
'conflict_passed': boolean, // 冲突通过
'branch_missing_passed': boolean, // 分支缺失通过
'non_ff_passed': boolean, // 非快进通过
'mr_state_passed': boolean, // 合并请求状态通过
'merged_by_user_passed': boolean, // 用户合并通过
'work_in_progress_passed': boolean, // 工作进展通过
'resolve_discussion_passed': boolean, // 解决讨论通过
'ci_state_passed': boolean, // CI状态通过
'merge_by_self_passed': boolean, // 自我合并通过
'can_force_merge': boolean, // 可以强制合并
'approval_reviewers_required_passed': boolean, // 需要审批的审查者通过
'merge_request_switch': {
'review_mode': 'string', // 审查模式
'merge_method': 'string', // 合并方法
'only_allow_merge_if_all_discussions_are_resolved': boolean, // 只有在解决所有讨论后才允许合并
'disable_merge_by_self': boolean, // 禁止自我合并
'only_allow_merge_if_pipeline_succeeds': boolean, // 只有在管道成功后才允许合并
'disable_squash_merge': boolean, // 禁止压缩合并
'squash_merge_with_no_merge_commit': boolean, // 无合并提交的压缩合并
'approval_required_reviewers_count': number, // 需要审批的审查者数量
'approval_required_reviewers_branch': 'string', // 需要审批的审查者分支
'add_notes_after_merged': boolean, // 合并后添加注释
'mark_auto_merged_mr_as_closed': boolean, // 将自动合并的MR标记为已关闭
'can_force_merge': boolean, // 可以强制合并
'can_reopen': boolean // 可以重新开放
},
'reason': {}, // description
'can_not_reopen': boolean, // 不能重新开放
'check_tasks_num': number // 检查事项总数
}

View File

@@ -0,0 +1,11 @@
import request from '@/utils/request';
import * as types from '@/api/milestone/types';
// 里程碑详情
export function getMilestones(params: types.commonMilestoneReqType): Promise<types.commonMilestoneResType> {
return request({
url: `/api/v1/projects/${params.project_id}/milestones/${params.milestone_id}`,
method: 'get'
});
}

View File

@@ -0,0 +1,28 @@
import { type errorType } from '@/api/types/common';
export interface commonMilestoneReqType {
project_id:string;
milestone_id:string;
[propName: string]: any;
}
export interface commonMilestoneResType extends errorType{
[propName: string]: any;
}
export interface IMilestone {
id: number,
iid: number,
project_id: number,
title: string,
description: string,
due_date?: string,
progress?: number
state: 'active' | string,
created_at: string,
updated_at?: string,
start_date?: string,
web_url: string,
issues_count: number,
merge_requests_count: number,
}

59
src/api/notice/index.ts Normal file
View File

@@ -0,0 +1,59 @@
import request from '@/utils/request';
import type { AxiosResponse } from 'axios';
import type { MessageListData } from '@/views/Notice/components/types';
// 获取用户未读消息数
export function getUnreadCount(params: { [propName: string]: any }): Promise<AxiosResponse<{ all: number; issue: number; mr: number; }>> {
return request({
url: '/api/v1/internal/messages/count_unread',
method: 'get',
params
});
}
// 设置消息为已读
export function setRead(data: { message_ids: number[] }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/internal/messages/set_read',
method: 'put',
data
});
}
// 获取用户消息列表
type MessageListQuery = {
page?: number;
pageSize?: number;
status?: string;
message_type?: string;
reason?: string;
creator_id?: number;
search?: string;
project_id?: number;
[propName: string]: any;
}
export function getMessageList(params: MessageListQuery): Promise<AxiosResponse<MessageListData[]>> {
return request({
url: '/api/v1/internal/messages',
method: 'get',
params
});
}
// 获取项目列表
export function getMessageRepoList(params: { page_num?: number; page_size?: number; search?: string; }): Promise<AxiosResponse<{ project_full_path: string; project_id: number; unread_count?: number; }[]>> {
return request({
url: '/api/v1/internal/messages/projects',
method: 'get',
params
});
}
/** 获取邀请相关未读信息 */
export function getMessageCount() {
return request({
url: '/api/v1/user/notify/targetInfo',
method: 'get',
params: {}
});
}

124
src/api/org/devIndex.ts Normal file
View File

@@ -0,0 +1,124 @@
import request from '@/utils/request';
import * as types from '@/api/org/types';
import { reqCatch, type ReqReturn } from '@/utils/catch';
// 获取自定义menu菜单
export function getCustomMenuList({ namespace, onlyCustomNav = true }): Promise<any> {
return request({
url: `/v1/namespace_page/custom/nav?domain=${namespace}&onlyCustomNav=${onlyCustomNav}`,
method: 'get',
apiType: 'devApi'
});
}
// 组织主页-关注社区
export function joinCommunity(data: types.createGroupReqType): Promise<any> {
return request({
url: `/api/v1/follow`,
method: 'post',
data
});
}
// 组织主页-取消关注社区
export function unJoinCommunity(data: types.createGroupReqType): Promise<any> {
return request({
url: `/api/v1/follow`,
method: 'delete',
params: data
});
}
// 组织主页-获取文章
export function getArticle(data: types.createGroupReqType): Promise<any> {
return request({
url: `/v1/plus/group/home/article`,
method: 'get',
params: data,
apiType: 'devApi'
});
}
// 组织主页-获取组织社区是否被关注
export function getCommunityAttentionStatus(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v1/follow/hasFollowed`,
method: 'get',
params: data
});
}
// 组织主页-社区最新活动
export function getActivity(data: types.createGroupReqType): Promise<any> {
return request({
url: `/v1/plus/group/home/activityLive`,
method: 'get',
params: data,
apiType: 'devApi'
});
}
// 组织主页-获取技术文章数
export function getArticleTotle(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/v1/namespace_article/tech-article-count`,
method: 'get',
params: data,
apiType: 'devApi'
});
}
// 组织主页-获取社区粉丝数
export function getfansTotle(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/v1/member/user/count`,
method: 'get',
params: data,
apiType: 'devApi'
});
}
// 组织主页-获取技术文章数和粉丝数
export function getArticleAndFansTotle(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/groups/${data.orgId}/stats`,
method: 'get',
params: data
});
}
// 组织主页-获取运营广告
export function getAdvertisement(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/v1/namespace_page/banner`,
method: 'get',
params: data,
apiType: 'devApi'
});
}
// 刷新devpress登录转态
export function getLoginState(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/v1/check/login`,
method: 'get',
apiType: 'devApi'
});
}
// 退出devpress社区
export function devLogout(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/v1/logout`,
method: 'get',
apiType: 'devApi'
});
}
/* 组织的关注用户 */
export function getGroupFollows(params: types.commonGroupReqType): Promise<types.commonGroupResType> {
return reqCatch(() => request({
url: '/api/v1/follow/getGroupFollows',
method: 'get',
params
}));
}

495
src/api/org/index.ts Normal file
View File

@@ -0,0 +1,495 @@
import request from '@/utils/request';
import * as types from '@/api/org/types';
import { reqCatch, type ReqReturn } from '@/utils/catch';
export function createOrg(data: types.createGroupReqType): Promise<any> {
return request({
url: `/api/v2/groups`,
method: 'post',
data
});
}
export function getOrg(params: types.commonGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/groups/${params.orgId}`,
method: 'get',
params
});
}
// 获取/搜索组织
export function getOrgs(params: types.commonGroupReqType): Promise<ReqReturn<types.commonGroupResType>> {
return reqCatch(() => request({
url: `/api/v2/groups`,
method: 'get',
params
}));
}
export function setOrg(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/groups/${data.orgId}`,
method: 'put',
data
});
}
export function deleteOrg(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/groups/${data.orgId}`,
method: 'delete'
});
}
// 查询登录用户是否关注某组织
export function checkHasFollowed(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: '/api/v1/follow/hasFollowed',
method: 'get',
params: data
});
}
// 获取组织下所有项目
export function getOrgProjectList(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/groups/${data.orgId}/projects`,
method: 'get',
params: data
});
}
// 查询组织项目精选
export function getOrgHandpickProjectList(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v1/featured/project/${data.type}`,
method: 'get',
params: data
});
}
// 项目精选重排序
export function reorderSelectedItems(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v1/featured/${data.type}/resort`,
method: 'put',
data
});
}
// 查询组织path是否重复
export function inquireOrgPathIsRepeat(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/groups/path_suggestion`,
method: 'get',
params: data
}, { customError: true });
}
// 组织讨论设置回显
export function getOrgDiscussionSettings(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/groups/${data.orgId}/module/setting`,
method: 'get',
params: data
}, {
customError: true
});
}
// 组织讨论设置保存
export function saveOrgDiscussionSettings(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/groups/${data.orgId}/module/setting`,
method: 'put',
data
});
}
// 获取组织语言
export function getOrgLanguages(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/groups/${data.orgId}/languages`,
method: 'get',
params: data
}, {
customError: true
});
}
// 查询组织首页运营内容
export function getOrgOperationContent(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v1/devpress/group/${data.orgId}/home_operation`,
method: 'get',
params: data
});
}
// 判断是否绑定csdn账号
export function isBindCsdnCount(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v1/user/csdn-identity`,
method: 'get',
params: data
});
}
// 申请社区
export function applicantCommunity(data: types.createGroupReqType): Promise<any> {
return request({
url: `/api/v1/devpress/${data.orgId}`,
method: 'post',
data
});
}
// 注销社区
export function deleteCommunity(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v1/devpress/${data.orgId}`,
method: 'delete'
});
}
// 社区基本信息
export function getCommunityInfo(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v1/devpress/${data.orgId}/info`,
method: 'get'
});
}
// 转移组织
export function transferOrg(data: types.createGroupReqType): Promise<any> {
return request({
url: `/api/v4/groups/${data.orgId}/transfer`,
method: 'post',
data
});
}
// 判断用户是否能创建组织
export function checkUserCreateOrg(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/groups/quota`,
method: 'get',
params: data
});
}
export function getOrgMemberList(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v1/groups/${data.orgId}/members/list`,
method: 'get'
});
}
/** 组织邀请成员 */
export function createInvite(data: { group_id: string, conf: Record<string, any> }) {
const { group_id, conf } = data;
return reqCatch(() => request({
url: `/api/v1/invitation/${group_id}/invite`,
method: 'post',
data: {
...conf,
source_type: '0'
}
}));
}
export function checkInvite(data: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v1/invitation/check`,
method: 'get',
params: data
});
}
export function acceptInvite(token: string) {
return request({
url: `/api/v1/invitation/members/${token}/accept`,
method: 'put'
});
}
export function revokeInvite(token: string): Promise<types.commonGroupResType> {
return request({
url: `/api/v1/invitation/members/${token}/revoke`,
method: 'delete'
});
}
/** 获取组织下的成员 */
export function getOrgMembers(data: { group_id: string, page?: number, per_page?: number, query?: string }) {
return request({
url: `/api/v1/groups/${data.group_id}/members/list`,
method: 'get',
params: data
});
}
/** 获取组织下的待邀请成员 */
export function getMembersInvite(data: { group_id: string, page: number, per_page: number }) {
return reqCatch(() => request({
url: `/api/v1/groups/${data.group_id}/members/invite`,
method: 'get',
params: data
}));
}
/** 移除组织内的用户 */
export function removeGroupUser(data: { group_id: string, username: string }) {
const { group_id, username } = data;
return reqCatch(() => request({
url: `/api/v1/groups/${group_id}/members/${username}`,
method: 'delete'
}));
}
/** 撤销组织中的成员邀请 */
export function retractGroupInvite(data: { group_id: string, username: string }) {
const { group_id, username } = data;
return reqCatch(() => request({
url: `/api/v1/invitation/${group_id}/0/members/${username}/revoke`,
method: 'delete'
}));
}
/** 退出当前组织 */
export function exitGroup(data: { group_id: string }) {
const { group_id } = data;
return reqCatch(() => request({
url: `/api/v1/groups/${group_id}/leave`,
method: 'delete'
}));
}
/** 设置组织中成员的权限 */
export function setGroupUserLevel(data: { group_id: string, username: string, access_level: '30' | '50' | '10' }) {
const { group_id, username, access_level } = data;
return reqCatch(() => request({
url: `/api/v1/groups/${group_id}/members/${username}`,
method: 'put',
data: { access_level }
}));
}
/** 精准搜索匹配组织中的成员 */
export function toSearchGroupMember(group_id: string, username: string) {
return reqCatch(() => request({
url: `/api/v1/groups/${group_id}/members/${username}`
}));
}
/* 查询path是个人还是组织 */
export function getPathType(params: types.createGroupReqType): Promise<types.commonGroupResType> {
return request({
url: '/api/v2/groups/path_suggestion',
method: 'get',
params
});
}
/** 获取用量以及存储相关 */
export function getOrgStock(group_id: string) {
return reqCatch(() => request({
url: `/api/v1/namespaces/${group_id}/statistic`
}));
}
/** 创建组织成员邀请链接 **/
export function createGroupMemberLink(data: { namespace: string } & types.MemberInviteLinkProps) {
const { namespace, ...config } = data;
return reqCatch(() => request({
url: `/api/v1/group/${namespace}/invite/link`,
method: 'post',
data: config
}));
}
/** 删除组织成员邀请链接 */
export function deleteMemberInviteLink(namespace: string, inviteId: string) {
return reqCatch(() => request({
url: `/api/v1/group/${namespace}/${inviteId}/invite/link`,
method: 'delete'
}));
}
/** 查询组织成员邀请链接列表 */
export function getMemberInviteLinks(params: { namespace: string, page?: number, per_page?: number }) {
const { namespace, ...pager } = params;
return reqCatch(() => request({
url: `/api/v1/${namespace}/invite/link`,
params: Object.assign({ page: 1, per_page: 10 }, pager)
}));
}
/** 修改组织成员邀请链接 **/
export function updateGroupMemberLink(data: { namespace: string, inviteId: string } & types.MemberInviteLinkProps) {
const { namespace, inviteId, ...config } = data;
return reqCatch(() => request({
url: `/api/v1/group/${namespace}/${inviteId}/invite/link`,
method: 'put',
data: config
}));
}
/** 接受组织邀请链接 */
export function acceptGroupInvite(invite_code: string) {
return reqCatch(() => request({
url: `/api/v1/${invite_code}/invite/accept`
}));
}
/** 查看组织邀请链接待接受成员列表 */
export function getAcceptGroupMember(params: { namespace: string, page?: number, per_page?: number }) {
const { namespace, ...pager } = params;
return reqCatch(() => request({
url: `/api/v1/${namespace}/invite/accept/member`,
params: Object.assign({ page: 1, per_page: 10 }, pager)
}));
}
/** 审核组织链接访问的成员 */
export function checkGroupLinkMember(data: { namespace: string, id:number, access_level: string, member_expires_at?: string, audit: '0' | '2' }) {
const { namespace, id, ...conf } = data;
return reqCatch(() => request({
url: `/api/v1/group/${namespace}/${id}/invite/audit`,
method: 'put',
data: conf
}));
}
/** 删除链接访问组织的成员 */
export function removeGroupLinkMember(namespace: string, id: number) {
return reqCatch(() => request({
url: `/api/v1/group/${namespace}/${id}/invite/audit`,
method: 'delete'
}));
}
/** 模糊搜索匹配相关组织 */
export function getFuzzyGroups(params: { name?: string, path?: string, description?: string, page?:number, per_page?:number, orderBy?: 'name' | 'path' | 'id' | 'created_at' | 'updated_at', sort: 'asc' | 'desc'}) {
const { page, per_page, ...param } = params;
return reqCatch(() => request({
url: '/api/v2/groups/search/list',
params: { ...param, ...Object.assign({ page: 1, per_page: 10 }, { page, per_page }) }
}));
}
// 新建CLA协议
export function claAdd(data: types.commonGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/cla/${data.orgId}/add`,
method: 'post',
data
});
}
// 编辑CLA协议
export function claUpdate(data: types.commonGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/cla/${data.orgId}/update`,
method: 'put',
data
});
}
// 获取CLA协议详情
export function claDetail(params: types.commonGroupReqType): Promise<types.commonGroupResType> {
return request({
url: `/api/v2/cla/detail`,
method: 'get',
params
});
}
/* 组织webhooks对应接口开始 */
/** 获取项目分支webhook */
export function getRepoWebhooks(params: { repoId: string | null; conf: Record<string, any> }) {
return reqCatch(
() =>
request({
url: `/api/v2/groups/${params.repoId}/hooks`,
params: params.conf
}),
params
);
}
/** 新增webhook配置 */
export function createWebhook(data: { repoId: string | number | null; conf: Record<string, any> }) {
return reqCatch(
() =>
request(
{
url: `/api/v2/groups/${data.repoId}/hooks`,
data: data.conf,
method: 'post'
},
{
customError: true
}
),
data
);
}
/** 编辑webhook */
export function editWebhook(data: { repoId: string | null; hook_id: string; conf: Record<string, any> }) {
const { repoId, hook_id, conf } = data;
return reqCatch(() =>
request({
url: `/api/v2/groups/${repoId}/hooks/${hook_id}`,
method: 'put',
data: conf
})
);
}
/** 获取webhook详情 */
export function getWebhookDetail(data: { repoId: string | null; hook_id: string }) {
const { repoId, hook_id } = data;
return reqCatch(() =>
request({
url: `/api/v2/groups/${repoId}/hooks/${hook_id}`
})
);
}
/** 获取webhook请求日志 */
export function getWebhookLogs(data: { repoId: string | null; hook_id: string; page?: number; per_page?: number }) {
const { repoId, hook_id, ...param } = data;
return reqCatch(() =>
request({
url: `/api/v2/groups/${repoId}/hooks/${hook_id}/logs`,
params: Object.assign({ page: 1, per_page: 10 }, param)
})
);
}
/** 获取项目webhook日志详情 */
export function getWebhookLogDetail(data: { repoId: string | null; hook_id: string; id: string }) {
const { repoId, hook_id, id } = data;
return reqCatch(() =>
request({
url: `/api/v2/groups/${repoId}/hooks/${hook_id}/logs/${id}`
})
);
}
/** 删除webhook */
export function deleteWebHook(data: { repoId: string | null; hook_id: string }) {
const { repoId, hook_id } = data;
return reqCatch(() =>
request({
url: `/api/v2/groups/${repoId}/hooks/${hook_id}`,
method: 'delete'
})
);
}
/* 组织webhooks对应接口结束 */
/** 获取组织默认设置 */
export function getOrgDefaultSetting(params: { group_id: string }) {
return reqCatch(() => request({
url: `/api/v2/groups/${params.group_id}`,
method: 'get'
}));
}
/** 更新组织默认设置 */
export function updateOrgDefaultSetting(data: types.commonGroupReqType) {
const { group_id } = data;
delete data.group_id;
return reqCatch(() => request({
url: `/api/v2/groups/${group_id}/ext/setting`,
method: 'put',
data
}));
}

24
src/api/org/types.ts Normal file
View File

@@ -0,0 +1,24 @@
import { type errorType } from '@/api/types/common';
import type { ComputedRef } from 'vue';
export interface createGroupReqType {
[propName: string]: any;
}
export interface commonGroupReqType {
[propName: string]: any;
repoId?: string | number | string[];
orgId?: string | number | string[] | ComputedRef<string | string[]>;
}
export interface commonGroupResType extends errorType {
[propName: string]: any;
}
export interface MemberInviteLinkProps {
access_level: number | string,
audit_status: 0 | 1 | string,
url_expires_at?:string,
member_expires_at?:string,
remark?:string
}

34
src/api/release/index.ts Normal file
View File

@@ -0,0 +1,34 @@
import request from '@/utils/request';
import * as types from '@/api/release/types';
import { reqCatchV2, type catchRt } from '@/utils/catch';
import type { CommonWithPageReqType } from '@/utils/types';
export function createRelease(data: types.createReleaseReqType): Promise<types.createReleaseReqType> {
return request({
url: `/api/v1/projects/${data.repoId}/releases`,
method: 'post',
data
});
}
export function getReleases(params: types.getReleasesType): catchRt<CommonWithPageReqType<types.getReleaseResType[]>> {
return reqCatchV2(() => request({
url: `/api/v1/projects/${params.repoId}/releases`,
method: 'get',
params
}));
}
export function getReleaseDetail(params: types.getReleaseDetailReqType): Promise<types.getReleaseDetailReqType> {
return request({
url: `/api/v1/projects/${params.repoId}/releases/${params.tag_name}`,
method: 'get',
params
});
}
export function deleteRelease(data: types.commonReleaseResType): Promise<types.commonReleaseResType> {
return request({
url: `/api/v1/projects/${data.repoId}/releases/${data.tag_name}`,
method: 'delete',
data
});
}

102
src/api/release/types.ts Normal file
View File

@@ -0,0 +1,102 @@
import { releaseType; type errorType } from '@/api/types/common';
export interface getReleasesType extends releaseType {
/**
* 当前页码
*/
page?: string;
/**
* 每页的项目数
*/
per_page?: string;
}
export interface commonReleaseResType extends errorType {
[propName: string]: any;
}
export interface createReleaseReqType {
tag_name: string;
name: string;
description: string;
ref: string;
assets?: {
links: [
{
name: string;
url: string
}
]
};
[propName: string]: any;
}
export interface getReleaseDetailReqType {
tag_name: string;
name: string;
description?: string;
[propName: string]: any;
}
interface Author {
id: number;
name: string;
username: string;
iam_id: string;
state: string;
avatar_url: string;
avatar_path: string;
email: string;
name_cn: string;
web_url: string;
nick_name: string;
tenant_name: string;
}
interface Commit {
id: string;
message: string;
parent_ids:string[];
authored_date: string;
author_name: string;
author_email: string;
committed_date: string;
committer_name: string;
committer_email: string;
open_gpg_verified: true;
verification_status: number;
gpg_primary_key_id: string;
short_id: string;
created_at: string;
title: string;
author_avatar_url: string;
committer_avatar_url: string;
relate_url: {
related_id: string;
related_url: string
}[]
}
export interface getReleaseResType {
tag_name: string;
description: string;
name: string;
description_html: string;
created_at: string;
can_delete: true;
can_edit: true;
can_download: true;
author:Author;
commit:Commit;
assets: {
count: number;
sources:
{
format: string;
url: string
}[];
links:
{
id: number;
name: string;
url: string;
external: true
}[];
}
}

1544
src/api/repo/index.ts Normal file

File diff suppressed because it is too large Load Diff

209
src/api/repo/types.ts Normal file
View File

@@ -0,0 +1,209 @@
import { VISIBILITY } from '@/constant/enum';
import { type forkType, type errorType, type repoType } from '@/api/types/common';
import { type TypeAll } from '@/utils/types';
export interface createRepoReqType {
name: string;
path: string;
import_url?:string;
description?: string;
visibility?: VISIBILITY;
}
export interface createRepoResType extends errorType {
[propName: string]: any;
}
export interface commonRepoReqType extends repoType {
[propName: string]: any;
}
export interface forkRepoReqType extends forkType {
[propName: string]: any;
name?: string;
namespace?: number;
need_sync_settings?: string[];
path?: string;
fork_from_project_id?: string;
}
export interface commonRepoResType extends errorType {
name: string // 项目名称
default_branch: string // 项目默认分支
path: string // 仓库路径
description: string // 项目描述
ci_config_path?: string // ci配置文件路径
issues_enabled?: boolean // 是否启用问题追踪器
merge_requests_enabled?: boolean // 是否启用合并请求
wiki_enabled?: boolean // 是否启用wiki
jobs_enabled?: boolean // 是否启用作业
snippets_enabled?: boolean // 是否启用代码片段
shared_runners_enabled?: boolean // 是否为该项目启用共享Runner
resolve_outdated_diff_discussions?: boolean // 是否在推送时自动解决合并请求差异讨论
container_registry_enabled?: boolean // 是否为该项目启用容器注册表
lfs_enabled?: boolean // 是否为该项目启用Git LFS
visibility: 'private' | 'internal' | 'public' // 项目可见性级别
security?: 'secret_top' | 'secret' | 'secret_outer' | 'confidential' | 'internal' | 'open_source' // 项目安全级别
visibility_level?: number // 项目在devclound中的可见性级别
public_builds?: boolean // 是否执行公共构建
request_access_enabled?: boolean // 是否允许用户请求成员访问权限
only_allow_merge_if_pipeline_succeed?: boolean // 仅在管道后成功允许
only_allow_merge_if_all_discussions_are_resolved?: boolean // 仅在所有讨论都已解决后允许合并
tag_list?: string[] // 标签列表
avatar?: string[] // 头像列表
printing_merge_request_link_enabled?: boolean // 从命令行推送时是否显示创建/查看合并请求的链接
merge_method?: 'ff' | 'rebase_merge' | 'merge' // 合并请求时使用的合并方法
iright_snapshot?: string // iright应用信息
initialize_with_readme?: boolean // 是否使用Readme.md初始化项目
initialize_with_gitignore?: string // 选择添加.gitignore模板
initialize_with_license?: string // 选择添加license模板
partition?: string // 分区
[x: string]: any
}
export interface commonRepoBranchResType {
description: string // 分支描述
name: string // 分支名称
protected: boolean // 是否受到分支保护
merged: boolean // 是否合并
default: boolean // 是否为默认分支
[x: string]: any
}
// 项目用户角色权限
export interface IRole {
'id': number,
'username': string,
// 管理员 50开发30 浏览者10
'access_level': 50 | 30 | 10,
'project': {
// 安全级别
'security_level': 40
},
'committer_system_from'?: boolean
}
// 获取贡献者的返回
export interface ContributorReqType {
additions:number;
commits:number;
deletions:number;
email:string;
name:string;
}
interface User {
id:number;
username:string;
nickname:string;
avatar:string;
skill:any[]
}
interface Ext {
liveId:string;
coverImg:string;
isRecommend:boolean;
isHot:true;
}
// 精选内容的返回
export interface SelectedArticleReqType {
nsId:number;
mediaAid:string;
type:number;
title:string;
desc:string;
customDomain:string;
startAt:string;
endAt:string;
status:number;
ext:Ext;
user:User;
}
// 相关搜索关键词返回
export type HotSearchKeyReqType = TypeAll<'name'|'link', string>;
// 通知类型返回
export interface RepoNoticeReqType {
count:number;
custom_watching:any;
watch_type:string;
}
export interface RepoWikiReqType {// wiki创建更新文件请求参数
repo_path: string,
name: string,
file_path?: string,
commit_message: string,
content: string,
currUserId?: string
}
export interface WikiFileResType {// wiki详情返回
name:string;
path:string;
size: number,
encoding:string;
blob_id:string;
file_type:string;
commit_history_count:string;
last_commit_id:string;
author_name:string;
committed_date:string;
content:string;
}
export interface WikiListReqType {// wikilist请求参数
repo_path:string;
page?:number;
per_page?:number;
}
export interface WikiListResType {// wikilist返回
author_name:string;
name:string;
avatar?:string;
committed_date:string;
}
export interface RepoWikiHistoryReqType {// wiki历史版本请求参数
file_path:string,
repo_path: string,
page?: number,
per_page?: number,
}
export interface WikiHistoryResType {// wiki历史版本返回
id:string;
message:string;
parent_ids:string[];
authored_date:string;
author_name:string;
author_email:string;
committed_date:string;
committer_name:string;
committer_email:string;
open_gpg_verified: boolean;
verification_status: number;
gpg_primary_key_id:string;
short_id:string;
created_at:string;
title:string;
author_avatar_url:string;
committer_avatar_url:string;
relate_url: {
related_id:string;
related_url:string;
}[]
}
export interface archiveType extends repoType {
sha: string;
archive_format: string;
}
export interface MemberInviteLinkProps {
access_level: number | string,
audit_status: 0 | 1 | string,
url_expires_at?:string,
member_expires_at?:string,
remark?:string
}
export interface DiscussionPreviewProps {
discussion: string,
}
export interface DiscussionCommentProps {
type: 1 | 2 | 3 | 4,
discussionId: string | number,
}

11
src/api/report/index.ts Normal file
View File

@@ -0,0 +1,11 @@
import request from '@/utils/request';
// 数据上报
export function report(eventId: string, data: object, headers: object = {}): Promise<any> {
return request({
url: `/api/v1/report?event_id=${eventId}`,
method: 'post',
data,
headers
});
}

53
src/api/settings/index.ts Normal file
View File

@@ -0,0 +1,53 @@
import { reqCatchV2, type catchRt } from '@/utils/catch';
import request from '@/utils/request';
import type { userCreateSSHKeyReqType, generalSearchReqType, getUserSSHKeyResType, sshKeyid } from './types';
import Mock from 'mockjs';
// 获取镜像信息
export function getMirrorData(params: any): Promise<any> {
return Promise.resolve([(Mock.mock({
'isOpen': false,
'dataList': [
{
type: 0,
add: 'http:6',
success: 1,
time: 2
},
{
type: 1,
add: 'http:fdsjoijfsdoijdfsiojfsdiojoidsfoijfdsijo',
success: 0,
time: 2
}]
}))
]);
}
// 创建用户SSHKey
export function createUserSSH(sshKey: userCreateSSHKeyReqType): catchRt<any> {
const reqForm = new FormData();
reqForm.append('key', sshKey.keyValue);
reqForm.append('title', sshKey.keyName);
return reqCatchV2(() => request({
url: `/api/v1/user/keys`,
method: 'post',
data: reqForm
}, { customError: true }));
}
// 查询用户SSHKey列表
export function getUserSSHList(searchParams: generalSearchReqType): catchRt<getUserSSHKeyResType[]> {
return reqCatchV2(() => request({
url: `/api/v1/user/keys`,
method: 'get',
params: searchParams
}));
}
// 删除用户SSHKey
export function deleteSSHKey(key_id:sshKeyid, title:string): catchRt<any> {
return reqCatchV2(() => request({
url: `/api/v1/user/keys/${key_id}`,
method: 'delete',
params: { title: title }
}));
}

51
src/api/settings/types.ts Normal file
View File

@@ -0,0 +1,51 @@
import type { SSHData } from '@/components/SecretKeyItem/types';
export interface ITransSSHKey {
keyName: string;
keyValue: string;
writable: boolean;
}
// 用户创建SSHKey请求参数
export interface userCreateSSHKeyReqType {
keyName: string;
keyValue: string;
permissions: string;
expireTime: string;
}
// 通用列表查询参数
export interface generalSearchReqType {
page: number;
per_page: number;
search: string;
}
// 用户SSHKey接口返回
export interface getUserSSHKeyResType {
id: string | number;
key: string;
title: string;
created_at: string;
}
export type sshKeyid = SSHData['id'];
export interface Log {
type: string;
operator: string;
logInfo: string;
createdTime: string;
}
export interface LogFilter {
type?: string;
operator?: string;
logInfo?: string;
range?: [Date | '', Date | ''];
}
export interface LogSource {
(pageSize: number, pageIndex: number, logFilter: LogFilter): Promise<Log[]>
}
export interface UserRepo {
organization: string;
repoName: string;
repoSize: string;
isMine: boolean;
}

35
src/api/storage-apis.ts Normal file
View File

@@ -0,0 +1,35 @@
import type { IRequestCache } from "@/utils/apiStorage";
const TIMEOUT = 5000;
const RETRY = 2;
export const storageApis: IRequestCache[] = [
{
url: '/api/v1/issues',
timeout: 5000,
retry: RETRY,
method: 'get',
excludeStatusCode: [401,403, 404]
},
{
url: '/api/v1/merge_requests',
timeout: TIMEOUT,
retry: RETRY,
method: 'get',
excludeStatusCode: [401,403, 404]
},
{
url: '/api/v1/projects/{projectId}/isource/merge_requests',
timeout: TIMEOUT,
retry: RETRY,
method: 'get',
excludeStatusCode: [401,403, 404]
},
{
url: '/api/v1/issue/{projectId}/issues',
timeout: TIMEOUT,
retry: RETRY,
method: 'get',
excludeStatusCode: [401,403, 404]
}
]

53
src/api/tags/index.ts Normal file
View File

@@ -0,0 +1,53 @@
import request from '@/utils/request';
import * as types from '@/api/tags/types';
export function createTag(data: types.createTagReqType): Promise<types.createTagReqType> {
return request({
url: `/api/v1/projects/${data.repoId}/repository/tags`,
method: 'post',
data
});
}
export function getTags(params: types.getTagsReqType): Promise<any> {
return request({
url: `/api/v1/projects/${params.repoId}/repository/tags`,
method: 'get',
params
});
}
export function getTagDetail(params: types.tagDetailType): Promise<types.tagDetailType> {
return request({
url: `/api/v1/projects/${params.repoId}/repository/tags/${params.tag_name}`,
method: 'get',
params
});
}
export function deleteTag(params: types.tagDetailType): Promise<types.tagDetailType> {
return request({
url: `/api/v1/projects/${params.repoId}/repository/tags/${params.tag_name}`,
method: 'delete',
params
});
}
// 获取未发布版本的tag列表
export function getUnreleasedTags(params: types.tagDetailType): Promise<types.tagDetailType> {
return request({
url: `/api/v1/projects/${params.repoId}/releases/linktags`,
method: 'get',
params
});
}
export function createTagAuth(project_path: string): Promise<any> {
return request({
url: `/api/v2/projects/get_create_tag_setting`,
method: 'get',
params: {
project_path
}
});
}

48
src/api/tags/types.ts Normal file
View File

@@ -0,0 +1,48 @@
import { tagType, type errorType } from '@/api/types/common';
export interface getTagsReqType extends tagType {
/**
* 用户ID或用户名
*/
creator?: string;
/**
* 返回按照名称name、更新时间updated或创建时间created字段排序
*/
order_by?: string;
/**
* 当前页码
*/
page?: string;
/**
* 每页的项目数
*/
per_page?: string;
/**
* 返回与搜索条件匹配的标签列表
*/
search?: string;
/**
* 返回排序为升序asc或降序desc
*/
sort?: string;
/**
* 仅返回标签名称
*/
view?: string;
}
export interface tagDetailType extends tagType {
[propName: string]: any;
}
export interface commonTagsResType extends errorType {
[propName: string]: any;
}
export interface createTagReqType {
tag_name: string;
ref: string;
message?: string;
release_description?: string;
[propName: string]: any;
}

35
src/api/types/common.ts Normal file
View File

@@ -0,0 +1,35 @@
export interface errorType {
error_code?: number;
error_code_name?: string;
error_message?: string;
trace_id?: string;
}
export interface repoType {
repoId?: string;
}
export interface orgType {
groupId: string;
}
export interface commitType extends repoType {
commitId: string;
}
export interface tagType extends repoType {
tag_name?: string;
}
export interface forkType extends repoType {
forked_from_id?: string;
}
export interface releaseType extends repoType {
tag_name?: string;
}
export interface resCatch {
error: any;
data: any;
}

0
src/api/types/login.ts Normal file
View File

697
src/api/user/index.ts Normal file
View File

@@ -0,0 +1,697 @@
import request from '@/utils/request';
import { reqCatch } from '@/utils/catch';
import { fileToBlob } from '@/utils/index';
import type { RegisterReqType, UserProfileReqType, UserPreferenceReqType, UserRepoReqType, LoginPassword, LoginMobile, UserProfileResType, UserProfile, OrgData, FollowerData } from './types';
import { reqCatchV2, type catchRt } from '@/utils/catch';
import { AES, enc, mode, pad } from 'crypto-js';
import type { AxiosResponse } from 'axios';
import type { ProfileRepoItemResData } from '@/views/User/hooks/useRepoList';
/** 帐号密码登录 */
export function toLogin(data: LoginPassword): Promise<any> {
const key = enc.Utf8.parse((import.meta as any).env.VITE_SECRET_KEY);
const iv = enc.Utf8.parse((import.meta as any).env.VITE_SECRET_IV);
const cryptoCode = AES.encrypt(data.password, key, {
iv,
mode: mode.CBC,
padding: pad.Pkcs7
});
const userInfo = {
username: data.username,
password: cryptoCode.toString()
};
return reqCatch(() => request({
url: '/api/v1/user/oauth/login',
method: 'post',
data: userInfo,
headers: {
'content-type': 'application/x-www-form-urlencoded'
}
}), userInfo);
}
/** 验证码登录 */
export function loginByMobile(data: Exclude<LoginMobile, 'type'>): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/user/oauth/login/mobile',
method: 'post',
data,
headers: {
'content-type': 'application/x-www-form-urlencoded'
}
}));
}
/** 获取gitcode手机号验证码 */
export function verifyRegisterCode(data: { mobile: string, type: 'REGISTER' | 'ATTACH_MOBILE', raw_data?: string }): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/user/sms/send/codeByBiz',
method: 'post',
data: {
biz_enum: data.type,
mobile: data.mobile,
raw_data: data.raw_data || ''
}
}));
}
/** 获取华为手机号验证码 */
export function verifyHwCode(data: { mobile: string }): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/user/sendVeriCode',
method: 'post',
data
}));
}
/** gitcode手机号验证注册 */
export function registerByMobile(data: RegisterReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/user/register',
method: 'post',
data
}));
}
/**
* 华为云手机号验证注册
* @deprecated at 2023.11.02 精简注册
*/
export function registerBind(data: { mobile: string, user_id: string, mask: string, verificationcode: string }): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/user/registerIAM',
method: 'post',
data
}));
}
/** 快捷注册短信验证 */
export function getQuickLoginMsg(data: { mobile: string, biz_enum?: string }): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/user/sms/send/codeByBiz',
method: 'post',
data: {
mobile: data.mobile,
biz_enum: data.biz_enum || 'LOGIN'
}
}));
}
/** 手机号快捷注册 */
export function quickRegister(data: RegisterReqType): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/user/quickRegister',
method: 'post',
data: data
}));
}
/** 获取手机或者邮箱验证码 */
export function getMobileEmailCode(mobile_email: string) {
return reqCatch(() => request({
url: `/api/v1/user/forgetCode?mobile_email=${mobile_email}`
}));
}
/** 登录重置密码 */
export function resetUserPassword(data: { mobile_email: string, password: string, code: string }) {
return reqCatch(() => request({
url: '/api/v1/user/forgetPassword',
method: 'post',
data
}));
}
/** 退出登录 */
export function toLogout() {
return reqCatch(() => request({
url: '/api/v1/user/oauth/logout',
method: 'post'
}));
}
/** 获取第三方绑定信息 */
export function getBindUserInfo(platform: 'csdn' | 'gitee' | 'github' | 'atomgit', code: string, state: string, signup_type: string) {
return reqCatch(() => request({
url: `/api/v1/oauth/callback/${platform}`,
params: { code, state, signup_type }
}));
}
/** 第三方登录绑定手机号 */
export function bindAuthMobile(data: { user_id: string, mask: string, identity_id: string, mobile: string, verificationcode: string, signup_type: string }) {
return reqCatch(() => request({
url: '/api/v1/oauth/attach/mobile',
method: 'post',
data
}));
}
/** 模糊查询用户信息 */
export function fuzzyFindUserInfo(usernameOrEmail: string) {
return reqCatch(() => request({
url: '/api/v1/findUser/fuzzy',
params: { usernameOrEmail }
}));
}
/** 查询用户名是否已存在 */
export function checkUsername(username: string) {
return reqCatch(() => request({
url: '/api/v1/user/checkSameUser',
params: { username }
}));
}
// 获取当前用户所有命名空间
export function getNamespaces(params: any): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/groups',
method: 'get',
params
}), params);
}
// 获取当前用户fork的所有命名空间
export function getForkGroups(params: any): Promise<any> {
return reqCatch(() => request({
url: `/api/v2/projects/${params.repoId}/fork_groups/page`,
method: 'get',
params
}), params);
}
// 获取当前用户所有命名空间
export function getManageableGroups(params: any): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/user_groups/manageable_groups',
method: 'get',
params
}), params);
}
export function postUploadAvatar(params: any): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/obs/user/avatar',
method: 'get'
}), params);
}
export function postUploadImage(params: any): Promise<any> {
return reqCatch(() => request({
url: '/api/v1/obs/image',
method: 'post',
data: params
}), params);
}
// 封装公共文件上传方法
export async function uploadFile(fileInfo: any, isAvatar: boolean, fileType: string = '') {
try {
if (fileInfo.length > 0) {
const file = fileInfo[0];
const params = {
object_key: `${location.pathname}/` + file.name,
file_type: file.name.split('.')[1],
is_avatar: isAvatar
};
let res;
if (isAvatar) {
res = await postUploadAvatar(params);
} else {
params.content_type = fileType;
res = await postUploadImage(params);
}
const blob: any = await fileToBlob(file);
let url = '';
let uploadParams: any = {};
for (const key in res.data.data) {
url = key;
uploadParams = res.data.data[key];
}
const imgRes = await fetch(url, {
method: 'put',
body: blob,
headers: {
'Content-Type': uploadParams['Content-Type'],
'x-obs-acl': uploadParams['x-obs-acl'],
'Host': uploadParams['Host']
}
});
if (imgRes.status === 200) {
return uploadParams['cdn-img-addr'];
} else {
return '';
}
}
} catch (err) {
return err;
}
};
export function findUser(data: object | null): Promise<object | null> {
return request({
url: '/api/v1/findUser/condition',
method: 'get',
params: data
});
};
// 更新用户基本信息
export function updateUserProfile(data: UserProfileReqType | UserPreferenceReqType | UserRepoReqType): catchRt<UserProfileResType> {
return reqCatchV2(() => request({
url: '/api/v1/user/setting/save',
method: 'post',
data
}));
}
// 查询用户信息
export function getUserProfile(params: { username: string, type?: string }): Promise<AxiosResponse<UserProfile>> {
return request({
url: '/api/v1/user/setting/profile',
method: 'get',
params
});
}
// 查询用户活动
export function queryUserActivities(params: any): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/events',
method: 'get',
params
}, { customError: true });
}
// 查询用户活动-新接口
export function queryUserActivitiesNew(params: any): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/events/user',
method: 'get',
params
}, { customError: true });
}
// 查询用户项目
export function queryUserRepos(params: { user_id: string;[propName: string]: any; }): Promise<AxiosResponse<ProfileRepoItemResData[]>> {
return request({
url: `/api/v1/featured/project/profile_project?group_id=${params.username}`,
method: 'get',
params
});
}
// 查询用户创建的项目
export function queryUserCreateRepos(params: { user_name: string; search?: string, [propName: string]: any; }): Promise<AxiosResponse<ProfileRepoItemResData[]>> {
return request({
url: `/api/v1/profile/${params.user_name}/created_projects`,
method: 'get',
params
});
}
// 查询用户关注的项目
export function queryUserStarredRepos(params: { user_name: string;[propName: string]: any; }): Promise<AxiosResponse<ProfileRepoItemResData[]>> {
return request({
url: `/api/v1/profile/${params.user_name}/starred_projects`,
method: 'get',
params
}, { customError: true });
}
// 更新项目状态
export function updateRepoStatus(params: { type: string; group_id: string; resource_id: string; }): Promise<AxiosResponse<any>> {
return request({
url: `/api/v1/featured/${params.type}`,
method: 'post',
params
});
}
// 移除对应类型项目
export function removeRepoStatus(params: { type: string; group_id: string; resource_id: string; }): Promise<AxiosResponse<any>> {
return request({
url: `/api/v1/featured/${params.type}`,
method: 'delete',
params
});
}
// 查询用户关注数
export function getUserFollows(params: { username: string }): Promise<AxiosResponse<number>> {
return request({
url: '/api/v1/follow/followingCount',
method: 'get',
params
});
}
// 查询用户粉丝数
export function getUserFollowers(params: { username: string; followType: string; }): Promise<AxiosResponse<number>> {
return request({
url: '/api/v1/follow/followersCount',
method: 'get',
params
});
}
// 查询用户粉丝数和关注数
export function getUserFollowerCounts(params: { username: string; }): Promise<AxiosResponse<{ follow_count: number; fans_count: number }>> {
return request({
url: '/api/v1/follow/userBaseInfo',
method: 'get',
params
}, { customError: true });
}
// 查询登录用户是否关注某用户
export function checkHasFollowed(params: { username: string; otherUsername: string; followType: number }): Promise<AxiosResponse<boolean>> {
return request({
url: '/api/v1/follow/hasFollowed',
method: 'get',
params
});
}
// 查询特定用户组织列表
export function getUserOrgans(params: { user_name: string; page: number; per_page: number }): Promise<AxiosResponse<{ content: OrgData[] }>> {
return request({
url: `/api/v1/groups/${params.user_name}/list`,
method: 'get',
params
});
}
// 查询特定用户的贡献图
export function queryUserContributes(params: {
username: string;
period?: string;
year?: string;
}): Promise<AxiosResponse<{ [propName: string]: number }>> {
return request({
url: `/api/v1/events/${params.username}/contributions`,
method: 'get',
params
}, { customError: true });
}
// 关注某用户
export function followUser(params: { username: string; followedUsername: string; followType: number }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/follow',
method: 'post',
data: params
});
}
// 取消关注某用户
export function unfollowUser(params: { username: string; unfollowUsername: string; followType: number; }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/follow',
method: 'delete',
params
});
}
// 获取用户邮箱列表
export function getEmailList(params: { username: string; }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user/getEmailList',
method: 'get',
params
});
}
export function getEmailListForCombobox(params: { username: string; }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user/getEmailListForCombobox',
method: 'get',
params
});
}
// 设置并更新邮箱
export function setVerifyEmail(params: { objectId: string }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user/verifyEmail',
method: 'get',
data: params
});
}
// 删除用户设置邮箱
export function deleteEmail(params: { email: string; }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user/deleteEmail',
method: 'delete',
params
});
}
// 更新主邮箱设置
export function updateEmail(params: { username: string; email: string }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user/updateEmail',
method: 'put',
data: params
});
}
// 发送更新邮箱验证码接口
export function sendEmailVeriCode(params: { username: string; email: string; }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user/sendEmailVeriCode',
method: 'post',
data: params
});
}
// 发送更新邮箱验证码接口
export function verifyCodeEmail(params: { code: string; email: string; }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user/verifyCodeEmail',
method: 'put',
params: params
});
}
// 设置密码
export function setPassword(params: { password: string; username: string; }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user/setPassword',
method: 'post',
data: params
});
}
// 修改密码
export function updatePassword(params: { origin_password: string; password: string; username: string; }): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user/updatePassword',
method: 'post',
data: params
});
}
// 判断是否有设置密码
export function passwordAvailable(): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user/passwordAvailable',
method: 'get'
});
}
// 获取当前用户加入的组织
export function getMyGroupsList(params: any): Promise<AxiosResponse<any>> {
return request({
url: '/api/v1/user_groups/related_me',
method: 'get',
params
});
}
/** 退出组织 */
export function leaveGroups(params: any): Promise<AxiosResponse<any>> {
return request({
url: `/api/v1/groups/${params.orgId}/leave`,
method: 'delete'
});
}
// 获取用户访问令牌列表
export function getImpersonationTokens(params: any): Promise<AxiosResponse<any>> {
return request({
url: `/api/v1/user/getImpersonationTokens`,
method: 'get',
params
});
}
// 创建用户访问令牌
export function addImpersonationTokens(params: any): Promise<AxiosResponse<any>> {
return request({
url: `/api/v1/user/${params.username}/impersonation_tokens`,
method: 'post',
data: params
});
}
// 删除用户访问令牌
export function deleteImpersonationTokens(params: any): Promise<AxiosResponse<any>> {
return request({
url: `/api/v1/user/${params.username}/impersonation_tokens/${params.id}`,
method: 'delete',
params: { name: params.name }
});
}
// 活动会话列表
export function getLatest(params: any): Promise<AxiosResponse<any>> {
return request({
url: `/api/v1/user/activity-session/latest`,
method: 'get'
});
}
// 删除活动会话
export function deleteOffline(params: any): Promise<AxiosResponse<any>> {
return request({
url: `/api/v1/user/activity-session/offline`,
method: 'put',
params
});
}
// 获取用户参与的项目
export function getUserProject(params: any): Promise<AxiosResponse<any>> {
return request({
url: `/api/v1/user_projects/related_me`,
method: 'get',
params
});
}
// 获取用户粉丝列表
export function getFollowersList(params: { username: string; pageNum: number; pageSize: number; }): Promise<AxiosResponse<{ content: FollowerData[]; total: number; }>> {
return request({
url: '/api/v1/follow/followers',
method: 'get',
params
}, { customError: true });
}
// 搜索用户列表
export function searchUserList(params: { keyword?: string; pageNum: number; pageSize: number; }): Promise<AxiosResponse<{ content: any[]; total: number; }>> {
return request({
url: '/api/v1/user/search',
method: 'get',
params
}, { customError: true });
}
// 获取用户关注列表
export function getFollowingList(params: { username: string; pageNum: number; pageSize: number; }): Promise<AxiosResponse<{ content: FollowerData[]; total: number; }>> {
return request({
url: '/api/v1/follow/followingList',
method: 'get',
params
}, { customError: true });
}
// 获取用户语言集合
export function getUserLangData(params: { type: string; user_name: string; }): Promise<AxiosResponse<string[]>> {
return request({
url: `/api/v1/profile/${params.user_name}/project_languages`,
method: 'get',
params
}, { customError: true });
}
// 获取用户关注的项目动态推送
export function getUserConcernEvents(params?: any): catchRt<any> {
return reqCatchV2(() => request({
url: '/api/v1/events/follower_events',
method: 'get',
params
}));
}
// 获取用户被邀请的项目列表
export function getUserInviteRepo(params?: any): Promise<AxiosResponse<string[]>> {
return request({
url: `/api/v1/invite/sourcePage`,
method: 'get',
params
}, { customError: true });
}
// 获取用户绑定的三方信息
export function getUserIdentity(params?: any): catchRt<any> {
return reqCatchV2(() => request({
url: '/api/v1/user/identity/list',
method: 'get',
params
}));
}
// 用户绑定三方平台
export function bindUserIdentity(data?: any): catchRt<any> {
return reqCatchV2(() => request({
url: '/api/v1/user/identity',
method: 'post',
data
}));
}
// 第三方平台解绑
export function unBindUserIdentity(data?: any): catchRt<any> {
return reqCatchV2(() => request({
url: '/api/v1/user/identity',
method: 'delete',
data
}));
}
// 获取当前用户的手机号
export function getLoginMobile(params?: any): catchRt<any> {
return reqCatchV2(() => request({
url: '/api/v1/user/mobile',
method: 'get',
params
}));
}
// 用户账号注销
export function userAccountDel(params?: any): catchRt<any> {
return reqCatchV2(() => request({
url: '/api/v1/user/del',
method: 'delete',
params
}));
}
// 获取第三方atomgit账号使用流水线
export function getAtomgitIdentity(): catchRt<any> {
return reqCatchV2(() => request({
url: '/api/v1/user/identity/atomgit',
method: 'get'
}));
}
// 获取登录弹窗配置
export function getLoginConfig(): catchRt<any> {
return reqCatchV2(() => request({
url: '/api/v1/config/isLogin',
method: 'get'
}));
}
// 获取登陆token
export function getUserToken(): catchRt<any> {
return reqCatchV2(() => request({
url: '/api/v1/user/oauth/token',
method: 'get'
}, {
customError: true
}));
}
// 获取用户信息
export function getUserInfo(): catchRt<any> {
return reqCatchV2(() => request({
url: '/api/v1/user/oauth/userInfo',
method: 'get'
}, {
customError: true
}));
}

185
src/api/user/types.ts Normal file
View File

@@ -0,0 +1,185 @@
export interface LoginMobile {
type: 'verifyCode'
mobile: string
code: string
}
export interface LoginPassword {
type: 'password'
username: string
password: string
}
export interface RegisterMobile {
type: 'register'
username: string
mobile: string
password: string
verificationcode: string
nickname: string
}
export type LoginReqType = 'register' | 'verifyCode' | 'password'
export interface RegisterReqType {
username: string
mobile: string
email?: string
nickname: string
password?: string
verificationcode?: string
[x: string]: any
}
export interface LoginResType {
domain_id?: string
email?: string
id?: string
mobile?: string
nickname?: string
username?: string
access_token?: string
refresh_token?: string
xauth_token?: string
}
export interface Profile {
setting_private: boolean;
website: string;
description: string;
location: string;
company: string;
email_private: boolean;
email?: string;
show_email?: string;
github_account: string;
bg_image: string;
}
export interface preferenceProfile {
highlight: string;
tab_space_len: number;
}
export interface repoProfile {
default_branch: string;
}
// 获取用户基本信息
export interface UserProfileResType {
profile: Profile;
nickname: string;
avatar: string;
}
// 用户修改资料参数
export interface UserProfileReqType {
profile: Partial<Profile>;
nickname: string;
avatar: String;
}
// 用户修改偏好设置参数
export interface UserPreferenceReqType {
profile: Partial<preferenceProfile>;
type: string;
}
// 用户修改项目设置参数
export interface UserRepoReqType {
profile: Partial<repoProfile>;
type: string;
}
// 用户详细信息
export interface UserProfile {
profile: Profile;
nickname: string;
nick_name?: string;
username: string;
fans: null;
concerns: null;
avatar: string;
}
// 组织信息
export interface OrgData {
id: number;
path: string;
name: string;
avatar_url: null;
full_path: string;
full_name: string;
web_url: string;
}
// 关注用户列表信息
export interface FollowerData {
user_id?: string;
follow_id?: string;
follow_type?: number;
ip: string;
remark?: string;
is_friend?: number;
create_time?: string;
avatar?: string;
nick_name?: string;
username?: string;
description?: string;
location?: string;
groupname?: string;
website?: string;
}
// 参数的项目接口信息
export interface projectItems {
star_count: number;
forks_count: number;
watch_count: null | number;
import_star_count: number;
import_forks_count: number;
import_watch_count: number;
id: number;
description: string;
name: string;
name_with_namespace: string;
path: string;
path_with_namespace: null | string;
develop_mode: string;
created_at: null | string;
updated_at: null | string;
archived: boolean;
is_kia: null | string;
ssh_url_to_repo: string;
http_url_to_repo: string;
web_url: string;
readme_url: null | string;
product_id: null | string;
product_name: null | string;
license_url: null | string;
license: null | string;
namespace: string;
namespace_info: {
id: number;
name: string;
path: string;
develop_mode: string;
region: null | string;
cell: null | string;
kind: string;
full_path: string;
full_name: string;
parent_id: null | string;
visibility_level: number;
enable_file_control: boolean;
owner_id: number;
},
mirror_project_data: null | string;
visibility: string;
open_issues_count: number;
open_merge_requests_count: number;
open_change_requests_count: number;
starred: boolean;
last_activity_at: Date;
main_repository_language: Array<string>;
forked_from_project: null | string;
permissions: number;
member_count: number;
repository_size: number;
topic_names: null | string;
is_recommend: number;
}

318
src/assets/css/devui.scss Normal file
View File

@@ -0,0 +1,318 @@
/* devui css override */
// d-layout
div.devui-layout__header {
flex: none;
}
div.devui-layout__content {
flex: 1;
min-height: auto;
min-width: 0;
}
ul.devui-menu-vertical {
.devui-menu-item {
background: transparent;
align-items: center;
}
.devui-menu-item-select {
background: var(--color-CG300) !important;
border-radius: var(--border-radius);
&:after {
display: none;
}
}
}
.devui-input-slot__suffix > span {
color: var(--devui-text);
}
div.devui-tooltip {
z-index: var(--devui-z-index-pop-up, 1060);
background-color: var(--devui-feedback-overlay-bg, #464d6e);
border-radius: var(--devui-border-radius-feedback, 4px);
}
/* 隐藏必选符号 */
// .devui-form__label--required:before {
// display: none;
// content: '';
// }
// d-skeleton-item
.devui-skeleton-item {
&.devui-skeleton-item--square {
border-radius: var(--border-radius);
}
}
// d-tree
.devui-tree {
&__node,
&__node-title {
color: var(--color-font) !important;
}
}
// d-editor
.devui-code-editor {
.monaco-editor {
.line-numbers {
color: var(--color-lighter);
}
}
}
.devui-splitter {
&__collapse {
background-color: var(--color-lighter) !important;
}
}
// tab
.devui-menu-horizontal {
.devui-menu-item {
span {
font-weight: 400;
color: var(--color-light);
}
}
.devui-menu-item-select,
.devui-menu-active-parent,
.devui-menu-overflow-container:hover,
.devui-menu-item:hover {
span {
color: var(--color-light);
}
&:after {
background-color: var(--color-font) !important;
}
}
}
.devui-icon--operable.devui-icon__container {
display: inline-flex;
align-items: center;
}
.devui-menu-vertical {
.devui-menu-item:hover {
background-color: $devui-list-item-hover-bg;
border-radius: var(--border-radius);
}
}
// input输入框icon
.devui-input {
&__container {
i.icon {
&:before {
color: var(--color-CG500);
}
}
}
}
// date-range组件
.devui-range-date-picker-pro {
.devui-range-date-picker-pro__range-picker-icon {
svg {
width: 14px;
height: 14px;
}
}
}
// modal
.devui-modal {
&__header {
height: 40px !important;
}
}
// textarea 文字计数颜色
.devui-textarea__show-count {
color: var(--color-lighter) !important;
}
.devui-progress__content .devui-progress__line {
background: var(--color-CG300, #e4e9f0);
}
// radio button
.devui-radio-button {
&.active {
background-color: var(--color-primary) !important;
border-color: var(--color-primary) !important;
color: white;
}
}
// button
button.devui-button--solid--primary {
background-color: #5e7ce0;
border: none;
}
button.devui-button--solid--danger {
background-color: var(--devui-contrast, #c7000b);
border: none;
}
button.devui-button--outline {
background-color: #fff;
}
// 次要按钮样式
button.devui-button--solid--secondary {
border: var(--devui-btn-common-border-color) solid 1px;
border-radius: 4px;
background: #D1D1D1;
&:hover,
&:active,
&:focus {
border: var(--devui-btn-common-border-color) solid 1px;
color: var(--devui-text);
background: linear-gradient(0deg, rgba(188, 188, 208, 0.1) 0%, rgba(188, 188, 208, 0.1) 100%), var(--White, #FFF);
}
}
// d-avatar
.devui-avatar {
vertical-align: middle;
display: inline-flex;
align-items: center;
margin-top: auto;
margin-bottom: auto;
img {
background-color: white;
}
&.devui-avatar-square {
img,
.devui-avatar--style {
border-radius: var(--border-radius) !important;
}
&.radius-big {
img,
.devui-avatar--style {
border-radius: 8px !important;
}
}
}
}
.devui-result {
&__title {
color: var(--color-light);
}
&__desc {
color: var(--color-light);
}
&__extra {
color: var(--color-lighter);
}
}
.devui-tree {
&__node {
&-content {
&--value-wrapper {
div {
white-space: nowrap;
word-break: keep-all;
text-overflow: ellipsis;
overflow: hidden;
}
}
}
}
}
.devui-tabs__nav--slider > li.active {
text-shadow: none;
}
.devui-table {
&__tbody {
tr {
td {
border-bottom: 1px solid var(--color-border-light);
}
&:first-of-type {
td {
border-top: none;
&:first-of-type {
border-top-left-radius: var(--border-radius);
}
&:last-of-type {
border-top-right-radius: var(--border-radius);
}
}
}
&:last-of-type {
td {
border-bottom: none;
&:first-of-type {
border-bottom-left-radius: var(--border-radius);
}
&:last-of-type {
border-bottom-right-radius: var(--border-radius);
}
}
}
}
}
}
.devui-breadcrumb {
&__separator {
margin: 0 2px;
}
}
// .devui-input--error,.devui-select__selection--error,.devui-textarea--error {
// background-color: #fff;
// }
.devui-editable-select .devui-editable-select__inner {
max-height: 300px;
}
.devui-link-hover {
&:hover {
color: var(--devui-link) !important;
}
}
.devui-textarea__show-count {
color: var(--devui-text) !important;
}
//.devui-form__label-span {
// color: var(--devui-text) !important;
// font-size: 16px !important;
// line-height: 22px;
// font-weight: 500;
//}
.devui-checkbox {
padding: 3px 0;
}
.devui-radio__wrapper {
padding: 3px 0;
}
.devui-checkbox__label-text {
font-size: 16px;
}
.devui-radio.devui-radio--md span .devui-radio__label {
font-size: 16px;
}
.devui-radio-group div.devui-radio__wrapper {
height: auto;
}
.devui-radio__wrapper label.devui-radio {
display: flex;
align-items: center;
}
.button-content {
// font-weight: 600;
}
.devui-checkbox span.devui-checkbox__material {
border-color: var(--checkbox-border-color);
}
circle.devui-radio__material-outer {
stroke: var(--checkbox-border-color);
}
.devui-table--lg tbody>tr.devui-table__row>td,
.cardlist-item-padding {
padding: 16px 20px;
}

View File

@@ -0,0 +1,458 @@
// markdown
.dp-md-view {
pre {
position: relative;
code {
padding-right: 32px!important;
}
}
.md-view-copy-icon {
cursor: pointer;
position: absolute;
right: 8px;
top: 9px;
&:hover {
opacity: 0.5;
}
}
}
.g-md-container {
:deep(.md-toolbar-container) {
padding-right: 88px;
}
:deep(.dp-editor-md-preview-container.dp-md-view summary) {
cursor: pointer;
}
position: relative;
.g-md-preview-btn {
position: absolute;
top: 12px;
right: 16px;
color: var(--color-lighter);
&:hover {
:deep(.button-content) {
color: var(--color-primary) !important;
}
}
}
.g-md-upload-btn {
position: absolute;
left: 710px;
top: 10px;
cursor: pointer;
:deep(.devui-icon__container) {
display: inline-flex;
justify-content: center;
align-items: center;
}
:deep(.icon) {
color: var(--devui-icon-text, #71757f);
}
}
:deep(.devui-fullscreen) {
z-index: 999 !important;
}
}
:deep(.dp-md-container) {
border: none;
.CodeMirror {
border-radius: 3px;
pre {
word-break: break-all;
}
}
}
.dp-editor-md-preview-container.dp-md-view {
word-break: break-all;
line-height: normal;
* {
box-sizing: border-box;
}
/* 文章正文 */
p {
font-size: 14px;
color: var(--color-G900);
font-weight: normal;
line-height: 26px;
margin: 0;
overflow-x: auto;
overflow: hidden;
}
p:has(+ pre) {
margin-bottom: 8px;
}
span,
p span {
line-height: 1.5;
}
/* 加粗 */
strong {
font-weight: bold;
}
/* 斜体 */
i,
cite,
em,
var,
address,
dfn {
font-style: italic;
}
/* 上标 */
sup {
left: 2px;
}
/* 下标 */
sub {
margin: 0 2px;
}
/* 标题通用格式 */
h1,
h2,
h3,
h4,
h5,
h6 {
color: var(--color-G900);
margin: 0.67em 0;
font-weight: 600;
}
h1 {
font-size: 22px;
line-height: 32px;
margin-top: 24px;
margin-bottom: 16px;
}
h2 {
font-size: 20px;
line-height: 30px;
}
h3 {
font-size: 18px;
line-height: 28px;
}
h4 {
font-size: 16px;
line-height: 26px;
}
h5 {
font-size: 16px;
line-height: 24px;
}
h6 {
font-size: 16px;
line-height: 24px;
}
h1 code {
font-size: 28px;
}
h2 code {
font-size: 24px;
}
h3 code {
font-size: 22px;
}
h4 code {
font-size: 20px;
}
h5 code {
font-size: 18px;
}
h6 code {
font-size: 16px;
}
/* 列表(有序,无序) */
ul,
ol {
margin: 0 0 8px 0;
padding: 0;
font-size: 14px;
overflow: hidden;
overflow-x: auto;
color: var(--color-CG600);
}
li {
margin: 4px 0 0 18px;
}
ol,
ol > li {
list-style-type: decimal !important;
// 表达式,修复有序列表序号展示不全的问题
:nth-child(n+10){
margin-left: 24px;
}
:nth-child(n+100){
margin-left: 30px;
}
}
ul,
ul > li {
list-style-type: disc;
font-size: 14px;
margin-right: 11px;
color: var(--color-G900);
}
ol ul,
ol ul > li,
ul ul,
ul ul li {
// list-style: circle;
font-size: 14px;
list-style: none;
margin-left: 16px;
}
ul ul ul,
ul ul ul li,
ol ol,
ol ol > li,
ol ul ul,
ol ul ul > li,
ul ol,
ul ol > li {
list-style: square;
}
/* 任务列表 */
.task-list-item {
list-style: none;
margin: 8px 0 0 0;
}
.task-list-item label {
margin-left: 4px;
}
input[type=checkbox]+label, label+a {
vertical-align: middle;
}
input[type=checkbox]+label {
margin-left: 5px;
}
/* 图片 */
img {
margin: 8px 0;
max-width: 100%;
display: inline-block;
}
/* 引用 */
blockquote {
display: block;
padding: 16px;
margin: 0 0 24px;
border-left: 8px solid #dddfe4;
background: #eef0f4;
overflow: auto;
word-break: break-word !important;
}
blockquote ul,
blockquote ol {
margin-bottom: 0;
padding: 0;
font-size: 14px;
line-height: 22px;
}
blockquote ul li {
margin-bottom: 0;
}
blockquote ol li {
margin-bottom: 0;
}
/* 引用 - 文字 */
blockquote p {
font-size: 14px;
line-height: 22px;
color: #555666;
font-weight: normal;
margin-bottom: 0;
}
/* 分割线 */
hr {
margin: 24px 0;
border: none;
border-bottom: solid #ddd 1px;
}
/* 表格 */
tbody {
border: 0;
}
table tr {
border: 0;
border-top: 1px solid #ddd;
background-color: white;
}
table {
border-collapse: collapse;
display: table;
width: 100%;
text-align: center;
margin-bottom: 24px;
}
tbody {
border: 0;
}
table tr:nth-child(2n) {
background-color: #f7f7f7;
}
table tr th,
table tr td {
font-size: 14px;
color: #4f4f4f;
line-height: 22px;
border: 1px solid #ddd;
padding: 8px;
word-break: normal !important;
vertical-align: middle;
}
table tr th code,
table tr td code {
white-space: normal;
word-break: normal !important;
}
table tr th {
font-weight: bold;
background-color: #eff3f5;
}
/* 目录列表 */
dl {
margin: 24px;
}
dl dt {
margin: 8px;
font-weight: bold;
}
dl dd {
margin: 0 0 8px 40px;
}
dl dt dd {
margin: 8px;
}
/* pre */
pre {
margin-bottom: 24px;
white-space: pre-wrap;
padding: 0;
}
pre code {
// color: unset;
color: var(--color-G900);
}
/* 代码块字体 */
code,
kbd,
pre,
samp {
font-size: 14px;
line-height: 22px;
color: var(--color-G900);
}
code {
color: #c7254e;
// background-color: #f9f2f4;
background-color: var(--color-G200);
border-radius: 4px;
padding: 6px;
// display: inline;
}
kbd {
padding: 2px 8px;
border: 1px solid rgba(63, 63, 63, 0.25);
box-shadow: 0 1px 0 rgba(63, 63, 63, 0.25);
background-color: #fff;
color: #333;
border-radius: 4px;
display: inline-block;
margin: 0 2px;
white-space: nowrap;
}
/* 超链接 */
a {
// color: #4ea1db;
color: var(--color-B600);
text-decoration: none;
}
a:hover,
a:focus {
// color: #ca0c16;
color: var(--color-B600);
text-decoration: underline;
}
a:visited {
// color: #6795b5;
color: var(--color-B600);
}
/* abbr */
abbr[title],
abbr[data-original-title] {
cursor: help;
border-bottom: 1px dotted #999;
}
/* toc TODO: devui 尚未支持 */
.toc {
font-size: 18px;
line-height: 24px;
margin: 0 0 24px;
padding: 0;
}
.toc ul {
margin: 0 0 8px;
padding: 0;
}
.toc ul ul {
padding-left: 24px;
}
.toc ul li {
list-style-type: none;
margin: 8px 0 0 24px;
}
/* 脚注 TODO: devui 尚未支持*/
.footnote {
vertical-align: top;
position: relative;
top: -4px;
font-size: 12px;
}
.footnotes ol li {
font-size: 14px;
line-height: 22px;
margin: 0 0 8px 24px;
}
}

49
src/assets/css/jyh.scss Normal file
View File

@@ -0,0 +1,49 @@
/* devui css override */
// d-layout
.jyh-form {
.devui-form__label-span {
color: #595959;
font-family: HarmonyOS Sans SC;
font-weight: regular;
font-size: 14px;
line-height: 32px;
letter-spacing: 0px;
text-align: left;
}
.devui-form__label--start {
text-align: right;
}
.devui-form__item--horizontal {
margin-bottom: 0;
}
.jyh-form-operation {
margin-left: 20px !important;
}
}
.jyh-table {
.devui-table__cell {
color: #191919;
font-family: HarmonyOS Sans SC;
font-weight: regular;
font-size: 14px;
line-height: 22px;
letter-spacing: 0px;
text-align: left;
}
.devui-table__cell a {
cursor: pointer;
color: #0A59F7;
font-family: HarmonyOS Sans SC;
font-weight: regular;
font-size: 14px;
line-height: 22px;
letter-spacing: 0px;
text-align: left;
}
.devui-table__row td {
padding-top: 10px !important;
padding-bottom: 10px !important;
}
}

458
src/assets/css/main.scss Normal file
View File

@@ -0,0 +1,458 @@
/* 引入全局css变量 */
@import './variable.css';
@import './devui.scss';
@import './theme.scss';
@import './jyh.scss';
@import './mixins/index.scss';
/* 引入tailwindCSS */
@tailwind base;
@tailwind components;
@tailwind utilities;
// 基础CSS
html,
body,
#app {
height: 100%;
-webkit-font-smoothing: antialiased;
// scorll 事件失效 overflow-y: overlay
}
html {
overflow-y: scroll; // html本身没有滚动 为了防止自定义滚动条出现时界面抖动,需要预留轨道
}
html body {
background-color: $devui-global-bg;
font-size: var(--text-sm);
color: var(--color-font);
}
input::placeholder,
textarea::placeholder {
color: var(--color-lighter);
}
// 解决滚动条占用内容宽度
// html {
// overflow-y: scroll;
// }
// :root {
// overflow-y: auto;
// overflow-x: hidden;
// }
// :root body {
// position: absolute;
// }
// body {
// width: 100vw;
// overflow: hidden;
// }
// 兼容火狐浏览器
:focus-visible {
outline: none;
}
// 自定义class
.g-border {
border: 1px solid var(--devui-line);
border-radius: var(--border-radius);
&-light {
border: 1px solid var(--color-border-light);
border-radius: var(--border-radius);
}
}
.g-card,
.g-content-card {
background-color: $devui-base-bg;
box-shadow: $devui-shadow-length-base $devui-light-shadow;
border-radius: var(--border-radius);
}
.g-main-content {
line-height: 30px;
}
.g-sub-content {
line-height: 20px;
}
.g-border-bottom {
border-bottom: solid 1px var(--color-G200);
}
.g-icon-pointer {
cursor: pointer;
&:hover {
color: var(--color-link) !important;
}
}
.g-border-radius-top-no {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.g-icon-right {
vertical-align: middle;
margin-right: 4px;
}
.g-icon-left {
vertical-align: middle;
margin-left: 8px;
}
.g-drop-menu {
width: 100px;
padding: 0 16px;
}
.g-mid-line {
width: 0.5px;
height: 16px;
background: var(--color-border-light);
}
.g-row-line {
height: 1px;
width: 100%;
background: var(--color-G300);
}
.g-max-width {
width: 90%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.g-font-bold {
font-weight: 600;
}
.g-label-font {
.devui-form__label {
font-weight: 500;
}
}
/* 滚动条样式自定义 */
body::-webkit-scrollbar, body>* ::-webkit-scrollbar {
width: 6px;
height: 4px;
}
body::-webkit-scrollbar-thumb, body>* ::-webkit-scrollbar-thumb {
border-radius: 8px;
background-color: var(--devui-disabled-text);
&:hover{
background-color: var(--devui-placeholder)
}
}
body::-webkit-scrollbar-track {
background: transparent;
}
body::-webkit-scrollbar-corner {
background: transparent;
}
.clearfix {
&:after {
content: '';
clear: both;
visibility: hidden;
display: block;
}
}
.space-y-20 > *:not(:last-child) {
margin-bottom: 20px;
}
/* 分隔符 | */
.g-delimiter {
display: inline-block;
width: 1px;
height: 20px;
background: var(--color-G300);
vertical-align: middle;
}
.g-input-border {
.devui-input__wrapper:not(.devui-input--focus) {
border-color: var(--devui-line, #d7d8da);
}
.devui-input-slot__prepend,
.devui-input-slot__append {
border-color: var(--devui-line, #d7d8da);
}
}
.devui-select__dropdown .devui-select__dropdown--empty {
padding: 4px 8px;
}
/* 输入框 去掉hover效果*/
.devui-input__wrapper:not(.devui-input--error):not(.devui-input--disabled):not(.devui-input--focus):hover {
border-color: var(--devui-line, #d7d8da);
}
/* 多行文本输入框 去掉hover效果*/
.devui-textarea:not(.devui-textarea--error):not(.devui-textarea--disabled):not(.devui-textarea--focus):hover {
border-color: var(--devui-line, #d7d8da);
}
/* 自动补全输入框 去掉hover效果*/
.devui-auto-complete-input__wrapper:not(.devui-auto-complete--disabled):not(.devui-auto-complete-input__wrapper--error):hover {
border-color: var(--devui-line, #d7d8da);
}
/* 可输入下拉选择框 去掉hover效果*/
.devui-editable-select-input__wrapper:not(.devui-editable-select-input__wrapper--disabled):not(.devui-editable-select-input__wrapper--focus):hover {
border-color: var(--devui-line, #d7d8da);
}
/* 分页 去掉hover效果*/
.devui-pagination .devui-pagination__size:hover {
border-color: var(--devui-line, #d7d8da);
}
/* 数字输入框 去掉hover效果*/
.devui-input-number:hover .devui-input-number__control-buttons:not(.disabled) {
border-color: var(--devui-line, #d7d8da);
}
.devui-input-number:hover .devui-input-number__input-box:not(.disabled) {
border: 1px solid var(--devui-line, #9b9fa8);
}
/* 下拉框 去掉hover效果*/
.devui-select__selection:hover {
border-color: var(--devui-line, #d7d8da);
}
/* 时间范围选择 去掉hover效果 */
.devui-range-date-picker-pro .devui-range-date-picker-pro__range-picker:not(.devui-range-date-picker-pro--error):not(.devui-range-date-picker-pro--disabled):hover {
border-color: var(--devui-line, #d7d8da);
}
.g-add-border {
border-color: var(--devui-line, #d7d8da);
}
.g-z-index-9 {
z-index: 9 !important;
}
.g-z-index-9999 {
z-index: 9999 !important; // 9的层级低于列表的遮罩层
}
.g-hidden-scrollbar {
scrollbar-width: none;
scrollbar-color: transparent transparent;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
&::-webkit-scrollbar-horizontal {
display: none;
}
}
.g-discussion-item .dp-md-container .dp-md-content-container {
min-height: 150px;
}
// modal相关
.g-modal-footer {
display: flex;
padding: 20px;
gap: 8px;
justify-content: flex-end;
}
.row-reverse {
display: flex;
justify-content: flex-start;
flex-direction: row-reverse;
}
.ellipsis {
white-space: nowrap;
word-break: keep-all;
text-overflow: ellipsis;
overflow: hidden;
}
.ellipsis-pre {
white-space: pre-line;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
}
.ellipsis-two-line {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.ellipsis-three-line {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
.absolute-full {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: auto;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
.inline-center {
display: inline-flex;
align-items: center;
justify-content: center;
}
// 重置a标签的默认和hover色值
.reset-hover {
color: unset;
&:hover {
color: unset;
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.spin {
animation: spin 2s linear infinite;
transform-origin: center center;
}
// 重写RadioGroup样式
.g-radio-group {
&.devui-radio-group {
background-color: var(--color-G100);
padding: 2px;
.devui-radio-button {
border: none;
line-height: 22px;
height: 28px;
color: var(--color-CG600);
&:first-child {
border-left: none !important;
}
&.active {
color: #fff;
box-shadow: 0px 2px 6px 0px rgba(37, 43, 58, 0.12);
border-radius: var(--border-radius);
font-weight: 500;
}
}
}
}
.border-none {
border: none !important;
}
input {
background-color:transparent !important;
// appearance: none;
&:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {
-webkit-text-fill-color: inherit !important;
background-color: transparent !important;
background-image: none;
transition: background-color 36000s ease-in-out 0s; //背景色透明 生效时长 过渡效果 启用时延迟的时间
}
&:-moz-autofill, textarea:-moz-autofill, select:-moz-autofill {
-webkit-text-fill-color: inherit !important;
background-color: transparent !important;
background-image: none;
transition: background-color 36000s ease-in-out 0s; //背景色透明 生效时长 过渡效果 启用时延迟的时间
}
}
@media screen and (max-width: 1536px) {
.g-padding-x {
padding: 0 32px;
}
}
@media screen and (max-width: 768px) {
.g-padding-x {
padding: 0 16px;
}
}
.g-content-card-v2 {
background-color: $devui-global-bg;
border-radius: $devui-border-radius-card;
border: 1px solid var(--gray-border-color);
}
.g-number {
border-radius: 4px;
padding: 0 4px;
background: var(--gray-bg-color);
font-size: 12px;
line-height: 16px;
color: var(--devui-text);
}
.font-color-t1 {
color: $devui-text;
}
.font-color-t2 {
color: $devui-aide-text;
}
.font-color-placeholder {
color: $devui-placeholder;
}
.g-large-title-font {
font-size: 22px;
line-height: 22px;
font-weight: 500;
}
.g-divide-line {
height: 1px;
width: 100%;
background: var(--devui-dividing-line);
margin: 32px 0
}
.g-tip-text {
font-size: var(--devui-font-size);
line-height: 20px;
color: $devui-placeholder;
}
// 新版设计统一设置标题样式 大小颜色行高
.unify-settingTitle-title{
font-weight: 700;
line-height: 34px;
font-size: 24px;
color: var(--devui-text);
}
// 项目设置页面标题
.repo-settings-title {
@apply text-xl mb-[12px] flex items-center justify-between font-semibold;
}
// 下拉框动效
.arrow-down{
transition: transform var(--devui-animation-duration-slow, .3s) var(--devui-animation-ease-in-out-smooth, cubic-bezier(.645, .045, .355, 1));
transform-origin: center;
transform: rotateZ(0deg) !important;
}
.arrow-up{
transition: transform var(--devui-animation-duration-slow, .3s) var(--devui-animation-ease-in-out-smooth, cubic-bezier(.645, .045, .355, 1));
transform-origin: center;
transform: rotateZ(180deg) !important;
}

View File

@@ -0,0 +1,147 @@
// 自定义 按钮额外主题 红绿橙
button.devui-button {
// 实心按钮
&--solid {
//绿色按钮
&--success,
&--operable {
background-color: $v2-color-success;
&:hover {
background-color: $v2-color-success-hover;
}
&:active {
background-color: $v2-color-success-active;
}
&:disabled {
background-color: $v2-color-success-disable;
}
}
// 橙色按钮
&--warning {
background-color: $v2-color-warning;
&:hover {
background-color: $v2-color-warning-hover;
}
&:active {
background-color: $v2-color-warning-active;
}
&:disabled {
background-color: $v2-color-warning-disable;
}
}
// 暗红按钮
&--error {
background-color: $v2-color-error;
&:hover {
background-color: $v2-color-error-hover;
}
&:active {
background-color: $v2-color-error-active;
}
&:disabled {
background-color: $v2-color-error-disable;
}
}
}
//镂空按钮
&--outline {
&--success,
&--operable {
color: $v2-color-success;
border-color: $v2-color-success;
&:hover {
color: $v2-color-success-hover;
border-color: $v2-color-success-hover;
}
&:active {
color: $v2-color-success-active;
border-color: $v2-color-success-active;
}
&:disabled {
color: $v2-color-success-disable;
border-color: $v2-color-success-disable;
}
}
// 橙色按钮
&--warning {
color: $v2-color-warning;
border-color: $v2-color-warning;
&:hover {
color: $v2-color-warning-hover;
border-color: $v2-color-warning-hover;
}
&:active {
color: $v2-color-warning-active;
border-color: $v2-color-warning-active;
}
&:disabled {
color: $v2-color-warning-disable;
border-color: $v2-color-warning-disable;
}
}
// 暗红按钮
&--error {
color: $v2-color-error;
border-color: $v2-color-error;
&:hover {
color: $v2-color-error-hover;
border-color: $v2-color-error-hover;
}
&:active {
color: $v2-color-error-active;
border-color: $v2-color-error-active;
}
&:disabled {
color: $v2-color-error-disable;
border-color: $v2-color-error-disable;
}
}
}
//文字按钮
&--text {
&--success,
&--operable {
color: $v2-color-success;
&:hover {
color: $v2-color-success-hover;
}
&:active {
color: $v2-color-success-active;
}
&:disabled {
color: $v2-color-success-disable;
}
}
&--warning {
color: $v2-color-warning;
&:hover {
color: $v2-color-warning-hover;
}
&:active {
color: $v2-color-warning-active;
}
&:disabled {
color: $v2-color-warning-disable;
}
}
&--error {
color: $v2-color-success;
&:hover {
color: $v2-color-success-hover;
}
&:active {
color: $v2-color-success-active;
}
&:disabled {
color: $v2-color-success-disable;
}
}
}
}

View File

@@ -0,0 +1,34 @@
@import './variables.scss';
.v2-g-card {
position: relative;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border: 1px solid $card-border-color;
border-radius: $card-border-radius;
color: $card-text-color;
}
.v2-g-card-header:first-child {
border-radius: $card-border-radius $card-border-radius 0 0;
}
.v2-g-card-header {
margin-bottom: 0;
padding: $card-padding;
background-color: $card-border-header-bg;
border-bottom: 1px solid $card-border-color;
border-top-left-radius: $card-border-radius;
border-top-right-radius: $card-border-radius;
}
.v2-g-card-body {
padding: $card-padding;
}
.v2-g-card-header:only-child {
border-bottom-left-radius: $card-border-radius;
border-bottom-right-radius: $card-border-radius;
margin-bottom: -1px;
}

View File

@@ -0,0 +1,2 @@
@import './card.scss';
@import './button.scss';

View File

@@ -0,0 +1,21 @@
// 按钮 scss 变量
$v2-color-success: #10a35c;
$v2-color-success-hover: #31a26c;
$v2-color-success-active: #31a26c;
$v2-color-success-disable: #d6ece2;
$v2-color-warning: #ed5f22;
$v2-color-warning-hover: #f07a47;
$v2-color-warning-active: #f07a47;
$v2-color-warning-disable: #fce4da;
$v2-color-error: #da203e;
$v2-color-error-hover: #da203e;
$v2-color-error-active: hsla(350, 74%, 44%, 1);
$v2-color-error-disable: #fce4da;
$card-border-color: #e3e3ee;
$card-padding: 16px;
$card-border-radius: 8px;
$card-border-header-bg: #f9f9fb;
$card-text-color: #3b3e55;

16
src/assets/css/theme.scss Normal file
View File

@@ -0,0 +1,16 @@
/**
* 网站主题(暂定前端控制)
*/
// 亮色
.g-theme-light {
.dp-editor-md-preview-container.dp-md-view [src$="#gh-dark-mode-only"] {
display: none;
}
}
// 暗色
.g-theme-dark {
.dp-editor-md-preview-container.dp-md-view [src$="#gh-light-mode-only"] {
display: none;
}
}

View File

@@ -0,0 +1,78 @@
:root {
--color-G100: #FBFBFB;
--color-G150: #F6F6F8;
--color-G200: #F0F1F2;
--color-G300: #E6E6E8;
--color-G400: #D1D2D4;
--color-G500: #B3B4B5;
--color-G600: #9A9B9C;
--color-G700: #7E7E80;
--color-G800: #5B5B5C;
--color-G900: #2D2D2E;
--color-G1000: #000000;
--color-CG100: #F8F9FB;
--color-CG200: #F4F7F9;
--color-CG300: #E4E9F0;
--color-CG400: #CAD0D9;
--color-CG500: #9FA7B3;
--color-CG600: #707A87;
--color-CG700: #505A69;
--color-CG800: #3B4655;
--color-CG900: #252D3B;
--color-CG950: #151A26;
--color-DP100: #FDF4F6;
--color-DP200: #FAE5EC;
--color-DP300: #F4C7D5;
--color-DP400: #EA92AD;
--color-DP500: #E05E86;
--color-DP600: #B64C6D;
--color-DP700: #963F59;
--color-DP800: #652A3C;
--color-DP900: #3E1A25;
--color-DP950: #261017;
--color-B300: #AECCFC;
--color-B400: #6FA3F7;
--color-B500: #3B82F6;
--color-B600: #2562C4;
--color-R500: #F2050D;
--color-O500: #FF6C17;
--color-Y100: #FEF6E5;
--color-Y200: #FCE7BB;
--color-Y500: #F5AB0B;
--color-GN500: #0EB07B;
--color-linear100: linear-gradient(180deg, #FCFCFC 0%, #F8F9FB 100%);
--color-linear200: linear-gradient(180deg, #F8F9FA 0%, #F0F1F2 100%);
--color-primary: var(--color-B500);
--color-primary-hover: var(--color-B400);
--color-primary-active: var(--color-B600);
--color-primary-disable: var(--color-B300);
--color-danger: var(--color-R500);
--color-success: var(--color-GN500);
--color-tip: var(--color-Y500);
--color-warning: var(--color-O500);
--color-link: var(--color-B600);
--color-font: var(--color-G900);
--color-light: var(--color-CG600);
--color-lighter: var(--color-CG500);
--color-disabled: var(--color-CG500);
--color-border: var(--color-G300);
--color-border-light: var(--color-G200);
--color-button-border: var(--color-G400);
--color-button-border-hover: var(--color-B500);
--w-normal: 1440px;
--w-sm: 1100px;
--w-xs: 720px;
--spacing-normal: 32px;
--text-xs: 12px;
--text-sm: 14px;
--text-base: 16px;
--text-lg: 18px;
--text-xl: 20px;
--text-2xl: 22px;
--border-radius: 3px;
--gray-border-color: #E3E3EE;
--gray-bg-color: #e3e3ed;
--tab-active-bg: #F1F1F8;
--checkbox-border-color: #D1D1E0;
}

View File

@@ -0,0 +1,54 @@
{
"devui-text": "#000000",
"devui-aide-text": "#3B3E55",
"devui-placeholder": "#9C9DB4",
"devui-disabled-text": "#BCBCD0",
"devui-light-text": "#FFFFFF",
"devui-icon-fill": "#000000",
"devui-icon-fill-weak": "#3B3E55",
"devui-icon-fill-hover": "#3B3E55",
"devui-icon-disabled-color": "#F1F1F8",
"devui-icon-bg": "#FFFFFF",
"devui-brand": "#DA203E",
"devui-shape-icon-fill": "#BCBCD0",
"devui-shape-icon-fill-hover": "#8B8CA7",
"devui-shape-icon-fill-disabled": "#D1D1E0",
"devui-dividing-line": "#F1F1F8",
"devui-line": "#F9F9FB",
"devui-disabled-line": "#F1F1F8",
"devui-form-control-line-hover": "#8B8CA7",
"devui-form-control-line-active": "#F1F1F8",
"devui-primary": "#000000",
"devui-primary-hover": "#323232",
"devui-primary-active": "#000000",
"devui-primary-disabled": "#E3E3EE",
"devui-btn-common-bg": "#FFFFFF",
"devui-btn-common-bg-hover": "#F9F9FB",
"devui-disabled-bg": "#F9F9FB",
"devui-btn-common-border-color": "#E3E3EE",
"devui-btn-common-border-color-hover": "#8B8CA7",
"devui-btn-common-border-disabled": "#E3E3EE",
"devui-gray-form-control-bg": "#F9F9FB",
"devui-gray-form-control-hover-bg": "#F1F1F8",
"devui-link": "#2951E0",
"devui-link-light": "#000000",
"devui-link-disabled": "#F1F1F8",
"devui-icon-hover-bg": "#F1F1F8",
"devui-icon-active-bg": "#E3E3EE",
"devui-list-item-active-bg": "#F1F1F8",
"devui-global-bg": "#F9F9FB",
"devui-connected-overlay-b": "#FFFFFF",
"devui-list-item-hover-bg": "#FFFFFF",
"devui-feedback-overlay-bg": "#3F425A",
"devui-danger-bg": "#FFECE8",
"devui-danger": "#DA203E",
"devui-contrast-hover": "#CB272D",
"devui-contrast-active": "#841527",
"devui-danger-text": "#A1151E",
"devui-warning-bg": "#FFF7E8",
"devui-warning": "#FF7D00",
"devui-warning-text": "#CC5120",
"devui-success-bg": "#E8FFEA",
"devui-success": "#10A35C",
"devui-success-text": "#006622"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

BIN
src/assets/imgs/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 519 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

Some files were not shown because too many files have changed in this diff Show More