chore: initial commit
Some checks failed
Synchronize to Gitee / repo-sync (push) Has been cancelled
Typos Checking / Spell Check with Typos (push) Has been cancelled

This commit is contained in:
2026-06-23 11:56:23 +08:00
commit 72e2110987
2883 changed files with 367388 additions and 0 deletions

71
.github/ISSUE_TEMPLATE/bug.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
name: BUG 提交
description: 提交产品缺陷帮助我们更好的改进
title: "[BUG] "
labels: ["bug"]
assignees: ["zrfit"]
body:
- type: markdown
id: contacts_title
attributes:
value: "## 联系方式"
- type: input
id: contacts
validations:
required: false
attributes:
label: "联系方式"
description: "可以快速联系到您进一步沟通的方式:交流群号及昵称、邮箱等"
- type: markdown
id: environment
attributes:
value: "## 环境信息"
- type: input
id: version
validations:
required: true
attributes:
label: "Cordys CRM 版本"
description: "在系统右上角的下拉菜单中选择 `关于` 可查看当前 Cordys CRM 版本。"
- type: dropdown
id: database
validations:
required: true
attributes:
label: "使用外置数据库"
description: "如果使用外置数据库,请确认您的外置数据库版本,目前仅支持 MySQL 8.x 与 MariaDB 11.x。"
options:
-
-
- type: markdown
id: details
attributes:
value: "## 详细信息"
- type: textarea
id: what-happened
attributes:
label: "问题描述"
description: "简要描述您碰到的问题"
validations:
required: true
- type: textarea
id: how-happened
attributes:
label: "重现步骤"
description: "如果操作可以重现该问题"
validations:
required: true
- type: textarea
id: expect
attributes:
label: "期待的正确结果"
- type: textarea
id: logs
attributes:
label: "相关日志输出"
description: "请复制并粘贴任何相关的日志输出。 这将自动格式化为代码,因此无需反引号。"
render: shell
- type: textarea
id: additional-information
attributes:
label: "附加信息"
description: "如果你还有其他需要提供的信息,可以在这里填写(可以提供截图、视频等)。"

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: 对 Cordys CRM 项目有其他问题
url: https://github.com/1Panel-dev/CordysCRM/
about: 如果想要进一步了解 Cordys CRM 项目,欢迎发送邮件到 support@fit2cloud.com 进行提问。
- name: 反馈安全问题 (Report Security Bug)
url: mailto://support@fit2cloud.com
about: 请通过邮箱 support@fit2cloud.com 反馈安全问题 (Please report security vulnerabilities to support@fit2cloud.com)

43
.github/ISSUE_TEMPLATE/feature.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: 需求建议
description: 提出针对本项目的想法和建议
title: "[FEATURE] "
labels: ["需求"]
assignees: ["luty2018", "sakura1412"]
body:
- type: markdown
id: environment
attributes:
value: "## 环境信息"
- type: input
id: version
validations:
required: true
attributes:
label: "Cordys CRM 版本"
description: "在系统右上角的下拉菜单中选择 `关于` 可查看当前 Cordys CRM 版本。"
- type: input
id: contacts
validations:
required: false
attributes:
label: "联系方式"
description: "可以快速联系到您进一步沟通的方式:交流群号及昵称、邮箱等"
- type: markdown
id: details
attributes:
value: "## 详细信息"
- type: textarea
id: description
attributes:
label: "请描述您的需求或者改进建议"
validations:
required: true
- type: textarea
id: solution
attributes:
label: "请描述你建议的实现方案"
- type: textarea
id: additional-information
attributes:
label: "附加信息"
description: "如果你还有其他需要提供的信息,可以在这里填写(可以提供截图、视频等)。"

12
.github/ISSUE_TEMPLATE/question.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
name: 问题咨询
description: 提出针对本项目安装部署、使用及其他方面的相关问题
title: "[QUESTION] "
labels: ["question"]
assignees: ["luty2018", "sakura1412"]
body:
- type: textarea
id: description
attributes:
label: "请描述您的问题"
validations:
required: true

9
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,9 @@
#### What this PR does / why we need it?
#### Summary of your change
#### Please indicate you've done the following:
- [ ] Made sure tests are passing and test coverage is added if needed.
- [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.

38
.github/workflows/add-labels-for-pr.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
on:
workflow_dispatch:
name: Add Labels to PR
jobs:
add_labels:
runs-on: ubuntu-latest
steps:
# Checkout the repository code
- name: Checkout code
uses: actions/checkout@v3
# Extract and format the labels from the comment as "username: label"
- name: Extract reviewer and labels
if: ${{ github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/') }}
id: extract_labels
run: |
comment_body="${{ github.event.comment.body }}"
reviewer="${{ github.event.comment.user.login }}"
# Clean up comment and extract labels
raw_labels=$(echo "$comment_body" | sed 's|^/||')
formatted_labels=$(echo "$raw_labels" | awk -v reviewer="$reviewer" '{split($0, arr, ","); for (i in arr) {gsub(/^ +| +$/, "", arr[i]); print reviewer ": " arr[i]}}')
# Set the formatted labels as an environment variable (new way, not using set-output)
echo "labels=$formatted_labels" >> $GITHUB_ENV
# Output labels for debugging
echo "Formatted labels: $formatted_labels"
# Add the extracted labels to the PR
- name: Add labels via PR comment
if: ${{ github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/') }}
uses: actions-ecosystem/action-add-labels@v1
with:
github_token: ${{ secrets.GH_TOKEN }}
labels: ${{ env.labels }}

View File

@@ -0,0 +1,52 @@
name: build-and-push-base
on:
workflow_dispatch:
inputs:
architecture:
description: 'Architecture'
required: true
default: 'linux/amd64'
type: choice
options:
- linux/amd64
- linux/arm64
- linux/amd64,linux/arm64
jobs:
build-and-push-base-to-ghcr:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: main
- name: Prepare
id: prepare
run: |
DOCKER_IMAGE=ghcr.io/cordys-dev/cordys-base
DOCKER_PLATFORMS=${{ github.event.inputs.architecture }}
TAG_NAME=latest
DOCKER_IMAGE_TAGS="--tag ${DOCKER_IMAGE}:${TAG_NAME} --tag ${DOCKER_IMAGE}:latest"
echo ::set-output name=docker_image::${DOCKER_IMAGE}
echo ::set-output name=version::${TAG_NAME}
echo ::set-output name=buildx_args::--platform ${DOCKER_PLATFORMS} --no-cache \
--build-arg VERSION=${TAG_NAME} \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
--build-arg VCS_REF=${GITHUB_SHA::8} \
${DOCKER_IMAGE_TAGS} .
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GH_TOKEN }}
- name: Docker Buildx (build-and-push)
run: |
docker buildx build --output "type=image,push=true" ${{ steps.prepare.outputs.buildx_args }} -f installer/Dockerfile.base

108
.github/workflows/build-and-push.yml vendored Normal file
View File

@@ -0,0 +1,108 @@
name: build-and-push
run-name: 构建镜像并推送仓库 ${{ github.event.inputs.dockerImageTag }} (${{ github.event.inputs.registry }})
on:
workflow_dispatch:
inputs:
dockerImageTag:
description: 'Docker Image Tag'
default: 'dev'
required: true
architecture:
description: 'Architecture'
required: true
default: 'linux/amd64'
type: choice
options:
- linux/amd64
- linux/arm64
- linux/amd64,linux/arm64
registry:
description: 'Push To Registry'
required: true
default: 'fit2cloud-registry'
type: choice
options:
- fit2cloud-registry
jobs:
build-and-push-to-fit2cloud-registry:
if: ${{ contains(github.event.inputs.registry, 'fit2cloud') }}
runs-on: ubuntu-latest
steps:
- name: Checkout specific repository
uses: actions/checkout@v3
with:
repository: cordys-dev/cordys-crm
token: ${{ secrets.GH_TOKEN }} # 使用 GitHub token
- name: Prepare
id: prepare
run: |
DOCKER_IMAGE=${{ secrets.FIT2CLOUD_REGISTRY_HOST }}/cordys/cordys-crm-ce
DOCKER_PLATFORMS=${{ github.event.inputs.architecture }}
TAG_NAME=${{ github.event.inputs.dockerImageTag }}
SHORT_SHA=$(git rev-parse --short HEAD)
if [[ ${TAG_NAME} == *dev* ]]; then
DOCKER_IMAGE_TAGS="--tag ${DOCKER_IMAGE}:${TAG_NAME}"
else
DOCKER_IMAGE_TAGS="--tag ${DOCKER_IMAGE}:${TAG_NAME} --tag ${DOCKER_IMAGE}:latest"
fi
echo ::set-output name=buildx_args::--platform ${DOCKER_PLATFORMS} \
--build-arg DOCKER_IMAGE_TAG=${{ github.event.inputs.dockerImageTag }} --build-arg BUILD_AT=$(TZ=Asia/Shanghai date +'%Y-%m-%dT%H:%M') --build-arg GITHUB_COMMIT=${GITHUB_SHA::8} --no-cache \
--build-arg FIT2CLOUD_MAVEN_USERNAME=${{ secrets.FIT2CLOUD_MAVEN_USERNAME }} --build-arg FIT2CLOUD_MAVEN_PASSWORD=${{ secrets.FIT2CLOUD_MAVEN_PASSWORD }} \
--build-arg CRM_VERSION=${TAG_NAME}-${SHORT_SHA} \
${DOCKER_IMAGE_TAGS} .
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to FIT2CLOUD Registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.FIT2CLOUD_REGISTRY_HOST }}
username: ${{ secrets.FIT2CLOUD_REGISTRY_USERNAME }}
password: ${{ secrets.FIT2CLOUD_REGISTRY_PASSWORD }}
- name: Docker Buildx (build-and-push)
run: |
docker buildx build --output "type=image,push=true" ${{ steps.prepare.outputs.buildx_args }} -f installer/Dockerfile
# 创建或更新标签
- name: Create or Re-create Tag
if: success()
run: |
git config --global user.name 'fit2-zhao'
git config --global user.email 'yong.zhao@fit2cloud.com'
# 判断是否为dev标签如果是则跳过打tag操作
if [[ "${{ github.event.inputs.dockerImageTag }}" == "dev" ]]; then
echo "当前为dev标签跳过打tag操作"
exit 0
fi
# 获取远程标签信息
git fetch --prune --tags
# 检查标签是否存在(本地或远程)
if git ls-remote --tags origin refs/tags/${{ github.event.inputs.dockerImageTag }} | grep -q "${{ github.event.inputs.dockerImageTag }}" || git tag -l "${{ github.event.inputs.dockerImageTag }}" | grep -q "${{ github.event.inputs.dockerImageTag }}"; then
echo "标签 ${{ github.event.inputs.dockerImageTag }} 已存在,正在删除..."
# 删除本地标签(如果存在)
git tag -d ${{ github.event.inputs.dockerImageTag }} || true
# 删除远程标签并确认结果
git push --delete origin ${{ github.event.inputs.dockerImageTag }} || echo "远程标签可能不存在或已被删除"
# 确认标签已被删除
sleep 2
git fetch --prune --tags
fi
# 创建和推送新标签
git tag -a ${{ github.event.inputs.dockerImageTag }} -m "Release ${{ github.event.inputs.dockerImageTag }}"
git push origin ${{ github.event.inputs.dockerImageTag }}

46
.github/workflows/codecov.yml vendored Normal file
View File

@@ -0,0 +1,46 @@
on:
pull_request:
branches:
- main
paths:
- "backend/**"
- "pom.xml"
name: Code Coverage
permissions:
pull-requests: write
jobs:
generic_handler:
name: Code Coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
token: ${{ secrets.GH_TOKEN }}
# Cache Maven dependencies
- name: Cache Maven dependencies
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('backend/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
check-latest: false
- name: Build with Maven - other
run: mvn -B package -DskipAntRunForJenkins --file pom.xml -pl '!frontend'
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: 1Panel-dev/CordysCRM

View File

@@ -0,0 +1,17 @@
on:
push:
branches:
- 'pr@**'
- 'repr@**'
name: Auto Create PR
jobs:
generic_handler:
name: Auto Create PR
runs-on: ubuntu-latest
steps:
- name: Create pull request
uses: jumpserver/action-generic-handler@master
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

30
.github/workflows/frontend-build.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
on:
pull_request:
branches:
- main
paths:
- "frontend/**"
name: Frontend Code Checking
permissions:
pull-requests: write
jobs:
generic_handler:
name: Frontend Code Checking
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
token: ${{ secrets.GH_TOKEN }}
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
cache: 'maven'
cache-dependency-path: '**/pom.xml' # optional
check-latest: true
- name: Build with Maven - only frontend
run: mvn -T 1C -B package --file pom.xml -pl frontend

16
.github/workflows/issue-close.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: Issue Close Check
on:
issues:
types: [closed]
jobs:
issue-close-remove-labels:
runs-on: ubuntu-latest
steps:
- name: Remove labels
uses: actions-cool/issues-helper@v2
if: ${{ !github.event.issue.pull_request }}
with:
actions: 'remove-labels'
labels: '待处理'

38
.github/workflows/issue-comment.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
on:
issue_comment:
types: [created]
name: Add issues workflow labels
jobs:
add-label-if-is-author:
runs-on: ubuntu-latest
if: ${{ (github.event.issue.user.id == github.event.comment.user.id) && (!github.event.issue.pull_request) }}
steps:
- name: Add require handle label
uses: actions-cool/issues-helper@v2
with:
actions: 'add-labels'
labels: '待处理'
- name: Remove require reply label
uses: actions-cool/issues-helper@v2
with:
actions: 'remove-labels'
labels: '待用户反馈'
add-label-if-not-author:
runs-on: ubuntu-latest
if: ${{ (github.event.issue.user.id != github.event.comment.user.id) && (!github.event.issue.pull_request) && (github.event.issue.state == 'open') }}
steps:
- name: Add require replay label
uses: actions-cool/issues-helper@v2
with:
actions: 'add-labels'
labels: '待用户反馈'
- name: Remove require handle label
uses: actions-cool/issues-helper@v2
with:
actions: 'remove-labels'
labels: '待处理'

16
.github/workflows/issue-open.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: Issue Open Check
on:
issues:
types: [opened]
jobs:
issue-open-add-labels:
runs-on: ubuntu-latest
steps:
- name: Add labels
uses: actions-cool/issues-helper@v2
if: ${{ !github.event.issue.pull_request }}
with:
actions: 'add-labels'
labels: '待处理'

109
.github/workflows/issue-sync-to-tapd.yml vendored Normal file
View File

@@ -0,0 +1,109 @@
name: Sync GitHub Issues to TAPD
on:
issues:
types:
- assigned
- reopened
permissions:
issues: write
jobs:
sync-to-tapd:
runs-on: ubuntu-latest
concurrency:
group: sync-issue-${{ github.event.issue.number }}
cancel-in-progress: false
steps:
- name: Check if sync is needed (assignee + live labels)
id: check
run: |
ASSIGNEE="${{ github.event.issue.assignee.login }}"
# Fetch live labels from GitHub API (not the snapshot in the event)
LABELS=$(gh issue view ${{ github.event.issue.number }} \
--repo ${{ github.repository }} \
--json labels \
--jq '.labels[].name')
if [ -z "$ASSIGNEE" ] || [ "$ASSIGNEE" != "luty2018" ]; then
echo "Issue is not assigned to luty2018 or has no assignee, skipping sync"
echo "should_sync=false" >> $GITHUB_OUTPUT
elif echo "$LABELS" | grep -qx "tapd-synced"; then
echo "Issue already has the tapd-synced label, already synced, skipping"
echo "should_sync=false" >> $GITHUB_OUTPUT
else
echo "Issue is assigned to luty2018 and not yet synced, proceeding to sync"
echo "should_sync=true" >> $GITHUB_OUTPUT
fi
env:
GH_TOKEN: ${{ github.token }}
- name: Sync to TAPD
if: steps.check.outputs.should_sync == 'true'
env:
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_URL: ${{ github.event.issue.html_url }}
ISSUE_BODY: ${{ github.event.issue.body }}
TAPD_WORKSPACE_ID: ${{ secrets.TAPD_WORKSPACE_ID }}
TAPD_PROJECT_ID: ${{ secrets.TAPD_PROJECT_ID }}
TAPD_ITERATION_ID: ${{ secrets.TAPD_ITERATION_ID }}
TAPD_API_USERNAME: ${{ secrets.TAPD_API_USERNAME }}
TAPD_API_PASSWORD: ${{ secrets.TAPD_API_PASSWORD }}
TAPD_API_OWNER: ${{ secrets.TAPD_API_OWNER }}
run: |
# Fallback for empty body
BODY="${ISSUE_BODY:-No description}"
TITLE="[GitHub Issue #${ISSUE_NUMBER}] ${ISSUE_TITLE}"
BODY_HTML="${BODY//$'\n'/<br>}"
DESCRIPTION="GitHub link: ${ISSUE_URL}<br><br>Description: ${BODY_HTML}"
JSON=$(jq -n \
--arg name "$TITLE" \
--arg desc "$DESCRIPTION" \
--arg proj "$TAPD_PROJECT_ID" \
--arg ws "$TAPD_WORKSPACE_ID" \
--arg iteration "$TAPD_ITERATION_ID" \
--arg user "$TAPD_API_USERNAME" \
--arg owner "$TAPD_API_OWNER" \
'{
name: $name,
description: $desc,
project_id: $proj,
workspace_id: $ws,
owner: $owner,
creator: $owner
} + if $iteration != "" then {iteration_id: $iteration} else {} end')
echo "Creating TAPD story..."
echo "Title: $TITLE"
echo "Description: $DESCRIPTION"
HTTP_CODE=$(curl -s -o /dev/stderr -w "%{http_code}" -X POST \
"https://api.tapd.cn/stories?workspace_id=${TAPD_WORKSPACE_ID}" \
-H "Content-Type: application/json" \
-u "${TAPD_API_USERNAME}:${TAPD_API_PASSWORD}" \
-d "$JSON")
if [ "$HTTP_CODE" -ne 200 ] && [ "$HTTP_CODE" -ne 201 ]; then
echo "::error::TAPD API returned HTTP ${HTTP_CODE}, check the response details above"
exit 1
fi
echo "::notice::Sync completed, TAPD story created"
- name: Add synced label
if: steps.check.outputs.should_sync == 'true'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['tapd-synced']
})

41
.github/workflows/llm-code-review.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: LLM Code Review
permissions:
contents: write
pull-requests: write
on:
workflow_dispatch:
jobs:
llm-code-review:
runs-on: ubuntu-latest
steps:
# 1⃣ 拉代码
- name: Checkout code
uses: actions/checkout@v3
# 2⃣ LLM Code Review发表评论
- name: Run LLM Code Review
id: llm-code-review
uses: fit2cloud/LLM-CodeReview-Action@main
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
OPENAI_API_KEY: ${{ secrets.ALIYUN_LLM_API_KEY }}
OPENAI_API_ENDPOINT: https://dashscope.aliyuncs.com/compatible-mode/v1
MODEL: qwen3-coder-plus
LANGUAGE: Chinese
PROMPT: |
你是资深代码审查专家,严格检查以下代码差异。
⚠️【必须遵守】
- 只在代码质量存在问题时发表评论。
- 不要解释、不添加多余文本。
- 审查应专注于以下内容:逻辑错误、代码规范、可读性、性能优化等。
temperature: 0.2
top_p: 1
MAX_PATCH_LENGTH: 50000
IGNORE_PATTERNS: "/node_modules,*.md,/dist,/.github"
FILE_PATTERNS: "*.java"

15
.github/workflows/sync2gitee.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Synchronize to Gitee
on: [push]
jobs:
repo-sync:
runs-on: ubuntu-latest
steps:
- name: Mirror the Github organization repos to Gitee.
uses: Yikun/hub-mirror-action@master
with:
src: 'github/1Panel-dev'
dst: 'gitee/fit2cloud-feizhiyun'
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
dst_token: ${{ secrets.GITEE_TOKEN }}
static_list: "CordysCRM"
force_update: true

23
.github/workflows/typos-check.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: Typos Checking
on:
push:
branches:
- '**'
pull_request:
types: [opened, synchronize, reopened]
permissions:
pull-requests: write
jobs:
run:
name: Spell Check with Typos
runs-on: ubuntu-latest
steps:
- name: Checkout Actions Repository
uses: actions/checkout@v2
- name: Check spelling
uses: crate-ci/typos@master
with:
config: .github/workflows/typos-extend-exclude.toml

View File

@@ -0,0 +1,2 @@
[files]
extend-exclude = ["*.json", "**/*.json", "**/*.js", "**/*.html", "**/*.xml", "**/config.ts", "**/*.sql", "**/*.conf", "**/en-US.ts", "OWNERS", "CODEOWNERS", "LICENSE", "NOTICE"]