diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 791367a3..9c4ebc20 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -9,7 +9,7 @@ body:
value: |
感谢您花时间填写此 Bug 报告!
- - **提交错误报告前**:请检查 [已有 Issues](https://github.com/linux-do/pay/issues)列表,了解是否有类似问题被报告。如果不确定,请进行搜索,这有助于我们高效地专注于改进项目。
+ - **提交错误报告前**:请检查 [已有 Issues](https://github.com/linux-do/credit/issues)列表,了解是否有类似问题被报告。如果不确定,请进行搜索,这有助于我们高效地专注于改进项目。
- type: checkboxes
id: issue-check
attributes:
@@ -18,7 +18,7 @@ body:
options:
- label: 我已经搜索了现有问题和讨论。
required: true
- - label: 我正在使用最新版本或 cdk.linux.do 上的此应用。
+ - label: 我正在使用最新版本或 credit.linux.do 上的此应用。
required: true
- type: textarea
id: what-happened
@@ -68,7 +68,7 @@ body:
options:
- label: 我已阅读并遵循了 `README.md` 中的所有说明。
required: true
- - label: 我正在使用 linux-do/cdk 的最新版本。
+ - label: 我正在使用 linux-do/credit 的最新版本。
required: true
- label: 我已提供我能够提供的尽可能多的相关日志,屏幕截图等。
required: true
@@ -87,4 +87,4 @@ body:
value: |
## 注意
如果 Bug 报告不完整或不遵循说明,则可能不会得到处理。请确保您已遵循所有 **README.md** 指南,并提供所有必要信息以便我们重现该问题。
- 感谢您为 linux-do/cdk 做出贡献!
+ 感谢您为 linux-do/credit 做出贡献!
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index f52668e6..7faa5ea3 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -9,7 +9,7 @@ body:
value: |
感谢您花时间填写此功能请求!
- - **提交功能请求前**:请检查 [已有 Issues](https://github.com/linux-do/pay/issues) 列表和讨论区,了解是否有类似功能已被讨论或请求。这有助于我们避免重复工作,并高效地专注于改进项目。
+ - **提交功能请求前**:请检查 [已有 Issues](https://github.com/linux-do/credit/issues) 列表和讨论区,了解是否有类似功能已被讨论或请求。这有助于我们避免重复工作,并高效地专注于改进项目。
- type: checkboxes
id: check-existing
attributes:
@@ -18,7 +18,7 @@ body:
options:
- label: 我已经搜索了现有问题和讨论。
required: true
- - label: 我正在使用最新版本或 cdk.linux.do 上的此应用。
+ - label: 我正在使用最新版本或 credit.linux.do 上的此应用。
required: true
- type: textarea
id: feature-description
@@ -65,7 +65,7 @@ body:
options:
- label: 我已阅读并遵循了 `README.md` 中的所有说明。
required: true
- - label: 我正在使用 linux-do/cdk 的最新版本。
+ - label: 我正在使用 linux-do/credit 的最新版本。
required: true
- label: 我已提供我能够提供的尽可能多的相关信息,包括用例和场景。
required: true
@@ -76,4 +76,4 @@ body:
value: |
## 注意
如果功能请求不完整或不遵循说明,则可能不会得到处理。请确保您已提供所有必要信息以便我们理解您的建议。
- 感谢您为 linux-do/cdk 做出贡献!
+ 感谢您为 linux-do/credit 做出贡献!
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index e74543f0..efad130f 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -2,9 +2,9 @@
-- [ ] 我已阅读并理解 [贡献者公约](https://github.com/linux-do/pay/blob/master/CODE_OF_CONDUCT.md),
-- [ ] 我已阅读并同意 [贡献者许可协议 (CLA)](https://github.com/linux-do/pay/blob/master/CLA.md),确认我的贡献将根据项目的 MIT 许可证进行许可,
-- [ ] 我知晓如果此 PR 并不做出实质性更改,或可被认为是*为了PR被合并而提交PR*的,则可能不会被合并,
+- [ ] 我已阅读并理解 [贡献者公约](https://github.com/linux-do/credit/blob/master/CODE_OF_CONDUCT.md)
+- [ ] 我已阅读并同意 [贡献者许可协议 (CLA)](https://github.com/linux-do/credit/blob/master/CLA.md),确认我的贡献将根据项目的 Apache2.0 许可证进行许可
+- [ ] 我知晓如果此 PR 并不做出实质性更改,或可被认为是*为了PR被合并而提交PR*的,则可能不会被合并
**关联信息**
diff --git a/.github/workflows/build_backend.yml b/.github/workflows/build_backend.yml
index dd718b8f..5d88d96d 100644
--- a/.github/workflows/build_backend.yml
+++ b/.github/workflows/build_backend.yml
@@ -10,7 +10,7 @@ on:
jobs:
go_build:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -18,12 +18,13 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
- go-version: "1.25.4"
+ go-version: "1.26"
+ check-latest: true
- name: Install dependencies
run: |
go mod download
- go install github.com/swaggo/swag/cmd/swag@latest
+ go install github.com/swaggo/swag/cmd/swag@v1.16.6
- name: Make Swagger
run: make swagger
diff --git a/.github/workflows/build_frontend.yml b/.github/workflows/build_frontend.yml
index eac227bb..22e8d969 100644
--- a/.github/workflows/build_frontend.yml
+++ b/.github/workflows/build_frontend.yml
@@ -10,27 +10,27 @@ on:
jobs:
nextjs_build:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v4
-
+
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10.10.0
-
+
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: 'pnpm'
cache-dependency-path: frontend/pnpm-lock.yaml
-
+
- name: Install dependencies
working-directory: frontend
run: pnpm install --frozen-lockfile
-
+
- name: Build
working-directory: frontend
run: pnpm build
diff --git a/.github/workflows/build_image.yml b/.github/workflows/build_image.yml
index 2ceeb4dd..29ad9cb6 100644
--- a/.github/workflows/build_image.yml
+++ b/.github/workflows/build_image.yml
@@ -10,6 +10,7 @@ on:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
+ FRONTEND_IMAGE_NAME: ${{ github.repository }}-web
# add permission for package publishing
permissions:
@@ -18,12 +19,19 @@ permissions:
jobs:
build_image:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
# checkout code
- name: Checkout repository
uses: actions/checkout@v4
+ # set up go
+ - name: Set up Go
+ uses: actions/setup-go@v5
+ with:
+ go-version: "1.26"
+ check-latest: true
+
# download Go modules
- name: Download Go modules
run: go mod download
@@ -32,13 +40,13 @@ jobs:
- name: Build Go Binary (multi-arch)
run: |
# build amd64 binary
- GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o pay-server-amd64 main.go
+ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o credit-server-amd64 main.go
# build arm64 binary
- GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o pay-server-arm64 main.go
+ GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o credit-server-arm64 main.go
# show binaries
- ls -alh pay-server-*
+ ls -alh credit-server-*
# set up docker buildx
- name: Set up Docker Buildx
@@ -74,3 +82,119 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64
+
+ build_frontend_image:
+ runs-on: ubuntu-24.04
+ steps:
+ # checkout code
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ # set up docker buildx
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ # login to registry
+ - name: Log into registry
+ uses: docker/login-action@v3
+ with:
+ registry: ${{ env.REGISTRY }}
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ # extract metadata for docker (frontend)
+ - name: Extract Docker metadata (frontend)
+ id: meta
+ uses: docker/metadata-action@v5
+ with:
+ images: ${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}
+ tags: |
+ type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
+ type=semver,pattern={{version}}
+ type=semver,pattern={{major}}.{{minor}}
+ type=ref,event=tag
+ type=sha,format=short,prefix=
+
+ # generate frontend build date in utc
+ - name: Generate frontend build date
+ id: frontend_build_meta
+ run: echo "build_date=$(date -u +'%Y/%m/%d UTC')" >> "$GITHUB_OUTPUT"
+
+ # build and push frontend docker image with version argument
+ - name: Build Frontend Docker image
+ uses: docker/build-push-action@v5
+ with:
+ context: ./frontend
+ push: ${{ github.ref_type == 'tag' || (github.ref == 'refs/heads/master' && github.event_name == 'push') }}
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ platforms: linux/amd64
+ build-args: |
+ VERSION=${{ github.ref_type == 'tag' && github.ref_name || '' }}
+ BUILD_DATE=${{ steps.frontend_build_meta.outputs.build_date }}
+
+ update_helm_values:
+ runs-on: ubuntu-24.04
+ needs: [build_image, build_frontend_image]
+ if: github.ref_type == 'tag'
+ steps:
+ # configure SSH agent with deploy key
+ - name: Setup SSH agent
+ uses: webfactory/ssh-agent@v0.9.0
+ with:
+ ssh-private-key: ${{ secrets.DEPLOY_KEY }}
+
+ # add github.com to known_hosts to avoid host verification prompt
+ - name: Add GitHub to known_hosts
+ run: ssh-keyscan github.com >> ~/.ssh/known_hosts
+
+ # clone the helm charts repository
+ - name: Clone Helm Charts repository
+ run: git clone ${{ vars.HELM_CHARTS_REPO }} helm-charts
+
+ # install yq for yaml editing
+ - name: Install yq
+ run: |
+ sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
+ sudo chmod +x /usr/local/bin/yq
+
+ # determine helm values file based on tag type (production or test)
+ - name: Determine Helm values file
+ id: helm_config
+ run: |
+ TAG="${{ github.ref_name }}"
+ if [[ $TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+ echo "values_file=values/credit/credit.yaml" >> "$GITHUB_OUTPUT"
+ echo "branch_prefix=update/credit" >> "$GITHUB_OUTPUT"
+ else
+ echo "values_file=values/credit_test/credit.yaml" >> "$GITHUB_OUTPUT"
+ echo "branch_prefix=update/credit_test" >> "$GITHUB_OUTPUT"
+ fi
+
+ # update image tags in helm values file
+ - name: Update image tags in helm values file
+ run: |
+ cd helm-charts
+ yq -i '.image.tag = "${{ github.ref_name }}"' ${{ steps.helm_config.outputs.values_file }}
+ yq -i '.image.webTag = "${{ github.ref_name }}"' ${{ steps.helm_config.outputs.values_file }}
+
+ # commit and push to a new branch, then open a PR for review
+ - name: Commit, push and create PR
+ env:
+ GH_TOKEN: ${{ secrets.GH_TOKEN }}
+ run: |
+ cd helm-charts
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ BRANCH_NAME="${{ steps.helm_config.outputs.branch_prefix }}-${{ github.ref_name }}"
+ git checkout -b "$BRANCH_NAME"
+ git add ${{ steps.helm_config.outputs.values_file }}
+ git commit -m "chore: update credit image tag to ${{ github.ref_name }}"
+ git push origin "$BRANCH_NAME"
+ HELM_REPO=$(echo "${{ vars.HELM_CHARTS_REPO }}" | sed 's/git@github.com://;s/\.git$//')
+ gh pr create \
+ --repo "${HELM_REPO}" \
+ --title "chore: update credit image tag to ${{ github.ref_name }}" \
+ --body "Automated PR: update \`${{ steps.helm_config.outputs.values_file }}\` image tags to \`${{ github.ref_name }}\` after Docker image build." \
+ --base main \
+ --head "$BRANCH_NAME"
diff --git a/.github/workflows/check_license.yml b/.github/workflows/check_license.yml
index 25c0cc5e..b625d9a6 100644
--- a/.github/workflows/check_license.yml
+++ b/.github/workflows/check_license.yml
@@ -9,7 +9,7 @@ on:
jobs:
check_license:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- name: checkout code
uses: actions/checkout@v4
diff --git a/.github/workflows/close_ticket.yml b/.github/workflows/close_ticket.yml
index fcacf28b..4ebf1f4a 100644
--- a/.github/workflows/close_ticket.yml
+++ b/.github/workflows/close_ticket.yml
@@ -6,7 +6,7 @@ on:
jobs:
close_ticket:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
permissions:
issues: write
pull-requests: write
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 16edd5ec..7d76f9c8 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -11,7 +11,7 @@ on:
jobs:
analyze:
name: Analyze (${{ matrix.language }})
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
permissions:
security-events: write
packages: read
diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml
index 69b36659..4aec2afc 100644
--- a/.github/workflows/copilot-setup-steps.yml
+++ b/.github/workflows/copilot-setup-steps.yml
@@ -11,7 +11,7 @@ on:
jobs:
copilot-setup-steps:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
permissions:
contents: read
@@ -39,9 +39,10 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
- go-version: "1.24"
+ go-version: "1.26"
+ check-latest: true
- name: Install dependencies
run: |
go mod download
- go install github.com/swaggo/swag/cmd/swag@latest
+ go install github.com/swaggo/swag/cmd/swag@v1.16.6
diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml
index 9f959cbe..f8865db9 100644
--- a/.github/workflows/eslint.yml
+++ b/.github/workflows/eslint.yml
@@ -10,7 +10,7 @@ on:
jobs:
lint:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/pr-template-check.yml b/.github/workflows/pr-template-check.yml
index 16ea9467..e61365de 100644
--- a/.github/workflows/pr-template-check.yml
+++ b/.github/workflows/pr-template-check.yml
@@ -6,7 +6,7 @@ on:
jobs:
check-pr-template:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- name: check all checklist items are checked
uses: actions/github-script@v7
diff --git a/.gitignore b/.gitignore
index 0c019aef..b2cd718b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,9 @@
# IDE
.idea/*
+.idea
!.idea/icon.png
.vscode
+.pnpm-store/
# logs
logs
@@ -34,5 +36,12 @@ Thumbs.db
# go workspace
go.work
go.work.sum
-cdk
+/credit
main
+
+# upload
+uploads/*
+
+s3_cache
+
+.gocache
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 4635e05f..32ed842f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,10 @@
-FROM alpine:latest
+FROM alpine:3.23
# set the time zone to Beijing Time in the Eastern 8th Time Zone
+ARG TZ=Asia/Shanghai
RUN apk add --no-cache tzdata && \
- cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
- echo "Asia/Shanghai" > /etc/timezone
+ cp /usr/share/zoneinfo/${TZ} /etc/localtime && \
+ echo "${TZ}" > /etc/timezone
WORKDIR /app
@@ -11,7 +12,7 @@ WORKDIR /app
ARG TARGETPLATFORM
# copy the appropriate binary based on platform
-COPY pay-server-${TARGETPLATFORM#linux/} ./pay-server
+COPY credit-server-${TARGETPLATFORM#linux/} ./credit-server
# copy docs
COPY docs ./docs
@@ -19,4 +20,4 @@ COPY docs ./docs
EXPOSE 8000
# set entrypoint
-ENTRYPOINT ["./pay-server"]
+ENTRYPOINT ["./credit-server"]
diff --git a/README.md b/README.md
index b95f998f..18fdbff1 100644
--- a/README.md
+++ b/README.md
@@ -1,37 +1,40 @@
# LINUX DO Credit
-🚀 Linux Do 社区 Credit (Content Distribution Kit) 快速分享平台
+🚀 Linux Do Community Credit Service Platform
-[](https://opensource.org/licenses/MIT)
-[](https://golang.org/)
+[中文](./README_zh.md)
+
+[](https://opensource.org/licenses/Apache-2.0)
+[](https://golang.org/)
[](https://nextjs.org/)
[](https://reactjs.org/)
-[](https://github.com/linux-do/pay/releases)
-[](https://github.com/linux-do/pay/stargazers)
-[](https://github.com/linux-do/pay/network)
-[](https://github.com/linux-do/pay/issues)
-[](https://github.com/linux-do/pay/pulls)
-[](https://github.com/linux-do/pay/graphs/contributors)
+[](https://github.com/linux-do/credit/releases)
+[](https://github.com/linux-do/credit/stargazers)
+[](https://github.com/linux-do/credit/network)
+[](https://github.com/linux-do/credit/issues)
+[](https://github.com/linux-do/credit/pulls)
+[](https://github.com/linux-do/credit/graphs/contributors)
+
+[](https://github.com/linux-do/credit/actions/workflows/build_backend.yml)
+[](https://github.com/linux-do/credit/actions/workflows/build_frontend.yml)
+[](https://github.com/linux-do/credit/actions/workflows/build_image.yml)
+[](https://github.com/linux-do/credit/actions/workflows/codeql.yml)
+[](https://github.com/linux-do/credit/actions/workflows/eslint.yml)
-[](https://github.com/linux-do/pay/actions/workflows/build_backend.yml)
-[](https://github.com/linux-do/pay/actions/workflows/build_frontend.yml)
-[](https://github.com/linux-do/pay/actions/workflows/build_image.yml)
-[](https://github.com/linux-do/pay/actions/workflows/codeql.yml)
-[](https://github.com/linux-do/pay/actions/workflows/eslint.yml)
+## 📖 Introduction
-## 📖 项目简介
+LINUX DO Credit is a credit service platform built for the Linux Do community, aimed at providing a series of credit-related services and offering a foundational framework for credit circulation for community developers.
-LINUX DO Credit 是一个为 Linux Do 社区打造的积分服务平台,旨在提供一系列积分相关服务,为社区开发者提供积分流转基础框架。
-### ✨ 主要特性
+### ✨ Key Features
-- 🔐 **OAuth2 认证** - 集成 Linux Do 社区账号系统
-- 🛡️ **风险控制** - 完善的信任等级和风险评估系统
-- 📊 **实时监控** - 详细的分发统计和用户行为分析
-- 🎨 **现代化界面** - 基于 Next.js 16 和 React 19 的响应式设计
-- ⚡ **高性能** - Go 后端 + Redis 缓存 + PostgreSQL 数据库
+- 🔐 **OAuth2 Authentication** - Integrated with Linux Do community account system
+- 🛡️ **Risk Control** - Comprehensive trust level and risk assessment system
+- 📊 **Real-time Monitoring** - Detailed distribution statistics and user behavior analysis
+- 🎨 **Modern Interface** - Responsive design based on Next.js 16 and React 19
+- ⚡ **High Performance** - Go Backend + Redis Cache + PostgreSQL Database
-## 🏗️ 架构概览
+## 🏗️ Architecture Overview
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
@@ -40,34 +43,245 @@ LINUX DO Credit 是一个为 Linux Do 社区打造的积分服务平台,旨在
│ │ │ │ │ │
│ • React 19 │ │ • Gin Framework │ │ • PostgreSQL │
│ • TypeScript │ │ • OAuth2 │ │ • Redis Cache │
-│ • Tailwind CSS │ │ • OpenTelemetry │ │ • Session Store │
-│ • Shadcn UI │ │ • Swagger API │ │ │
+│ • Tailwind CSS │ │ • Session Store │ │ │
+│ • Shadcn UI │ │ • OpenTelemetry │ │ │
+│ │ │ • Swagger API │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```
-## 🛠️ 技术栈
+## 🛠️ Tech Stack
-### 后端
-- **Go 1.25.4** - 主要开发语言
-- **Gin** - Web 框架
-- **GORM** - ORM 框架
-- **Redis** - 缓存和会话存储
-- **PostgreSQL** - 主数据库
-- **OpenTelemetry** - 可观测性
-- **Swagger** - API 文档
+### Backend
+- **[Go 1.26](https://go.dev/doc)** - Primary development language
+- **[GIN](https://github.com/gin-gonic/gin)** - Web Framework
+- **[GORM](https://github.com/go-gorm/gorm)** - ORM Framework
+- **[Redis](https://github.com/redis/redis)** - Cache and session store
+- **[PostgreSQL](https://www.postgresql.org)** - Primary Database
+- **[OpenTelemetry](https://opentelemetry.io)** - Observability
+- **[Swagger](https://github.com/swaggo/swag)** - API Documentation
-### 前端
-- **Next.js 16** - React 框架
-- **React 19** - UI 库
-- **TypeScript** - 类型安全
-- **Tailwind CSS 4** - 样式框架
-- **Shadcn UI** - 组件库
-- **Lucide Icons** - 图标库
+### Frontend
+- **[Next.js 16](https://github.com/vercel/next.js)** - React Framework
+- **[React 19](https://github.com/facebook/react)** - UI Library
+- **[TypeScript](https://github.com/microsoft/TypeScript)** - Type Safety
+- **[Tailwind CSS 4](https://github.com/tailwindlabs/tailwindcss)** - Styling Framework
+- **[Shadcn UI](https://github.com/shadcn-ui/ui)** - Component Library
+- **[Lucide Icons](https://github.com/lucide-icons/lucide)** - Icon Library
-## 📋 环境要求
+## 📋 Requirements
-- **Go** >= 1.25.4
+- **Go** >= 1.26
- **Node.js** >= 18.0
- **PostgreSQL** >= 18
- **Redis** >= 6.0
-- **pnpm** >= 8.0 (推荐)
\ No newline at end of file
+- **pnpm** >= 8.0 (Recommended)
+
+## 🚀 Quick Start
+
+### 1. Clone the Project
+
+```bash
+git clone https://github.com/linux-do/credit.git
+cd credit
+```
+
+### 2. Configure Environment
+
+Copy the configuration file and edit it:
+
+```bash
+cp config.example.yaml config.yaml
+```
+
+Edit `config.yaml` to configure database connections, Redis, OAuth2, etc.
+
+### 3. Initialize Database
+
+```bash
+# Create database
+createdb -h -p 5432 -U postgres linux_do_credit
+
+# If you need to specify encoding, use:
+# psql -h -p 5432 -U postgres -c "CREATE DATABASE linux_do_credit WITH ENCODING 'UTF8' LC_COLLATE='zh_CN.UTF-8' LC_CTYPE='zh_CN.UTF-8' TEMPLATE template0;"
+
+# Run migrations (automatically executed when starting the backend)
+```
+
+### 4. Start Backend
+
+```bash
+# Install Go dependencies
+go mod tidy
+
+# Generate API documentation
+make swagger
+
+# Start backend service
+go run main.go api
+```
+
+### 5. Start Frontend
+
+```bash
+cd frontend
+
+# Install dependencies
+pnpm install
+
+# Start development server
+pnpm dev
+```
+
+### 6. Access Application
+
+- **Frontend Interface**: http://localhost:3000
+- **API Documentation**: http://localhost:8000/swagger/index.html
+- **Health Check**: http://localhost:8000/api/v1/health
+- **Readiness Check**: http://localhost:8000/api/v1/ready
+
+## ⚙️ Configuration
+
+### Main Configuration Options
+
+| Option | Description | Example |
+|--------|-------------|---------|
+| `app.addr` | Backend service listening address | `:8000` |
+| `worker.port` | Worker probe port | `8001` |
+| `scheduler.port` | Scheduler probe port | `8002` |
+| `oauth2.client_id` | OAuth2 Client ID | `your_client_id` |
+| `database.host` | PostgreSQL database host | `127.0.0.1` |
+| `database.port` | PostgreSQL database port | `5432` |
+| `database.username` | PostgreSQL database username | `postgres` |
+| `database.password` | PostgreSQL database password | `password` |
+| `database.database` | PostgreSQL database name | `linux_do_credit` |
+| `database.ssl_mode` | PostgreSQL SSL mode | `disable` |
+| `database.application_name` | PostgreSQL application name | `credit-server` |
+| `database.search_path` | PostgreSQL search path | `public` |
+| `database.default_query_exec_mode` | SQL cache mode | `cache_statement` |
+| `redis.host` | Redis server address | `127.0.0.1` |
+
+For detailed configuration instructions, please refer to the `config.example.yaml` file.
+
+## 🔧 Development Guide
+
+### Backend Development
+
+```bash
+# Run API server
+go run main.go api
+
+# Run task scheduler
+go run main.go scheduler
+
+# Run worker queue
+go run main.go worker
+
+# Generate Swagger documentation
+make swagger
+
+# Format and check code
+make tidy
+```
+
+### Frontend Development
+
+```bash
+cd frontend
+
+# Development mode (using Turbopack)
+pnpm dev
+
+# Build production version
+pnpm build
+
+# Start production service
+pnpm start
+
+# Lint and format code
+pnpm lint
+pnpm format
+```
+
+## 📚 API Documentation
+
+API documentation is automatically generated by Swagger and can be accessed after starting the backend service:
+
+```
+http://localhost:8000/swagger/index.html
+```
+
+## 🧪 Testing
+
+```bash
+# Backend testing
+go test ./...
+
+# Frontend testing
+cd frontend
+pnpm test
+```
+
+## 🚀 Deployment
+
+### Docker Deployment
+
+```bash
+# Build image
+docker build -t linux-do-credit .
+
+# Run container
+docker run -d -p 8000:8000 linux-do-credit
+```
+
+### Production Environment Deployment
+
+1. Build frontend resources:
+ ```bash
+ cd frontend && pnpm build
+ ```
+
+2. Compile backend program:
+ ```bash
+ go build -o credit main.go
+ ```
+
+3. Configure `config.yaml` for production
+
+4. Start service:
+ ```bash
+ ./credit api
+ ```
+
+## 🤝 Contribution Guidelines
+
+We welcome community contributions! Please read the following before submitting code:
+
+- [Contribution Guidelines](CONTRIBUTING.md)
+- [Code of Conduct](CODE_OF_CONDUCT.md)
+- [Contributor License Agreement](CLA.md)
+
+### Submission Process
+
+1. Fork this repository
+2. Create a feature branch (`git checkout -b feature/your-feature`)
+3. Commit changes (`git commit -am 'Add your feature'`)
+4. Push to branch (`git push origin feature/your-feature`)
+5. Create Pull Request
+
+## 📄 License
+
+This project is open source under the [Apache2.0 License](LICENSE).
+
+## 🔗 Related Links
+
+- [Linux Do Community](https://linux.do)
+- [Issue Reporting](https://github.com/linux-do/credit/issues)
+- [Feature Request](https://github.com/linux-do/credit/issues/new?template=feature_request.md)
+
+## ❤️ Acknowledgements
+
+Thanks to all developers who contributed to this project and the support of the Linux Do Community!
+
+## 📈 Star History
+
+[](https://star-history.com/#linux-do/credit&Date)
diff --git a/README_zh.md b/README_zh.md
new file mode 100644
index 00000000..e5a98768
--- /dev/null
+++ b/README_zh.md
@@ -0,0 +1,287 @@
+# LINUX DO Credit
+
+🚀 Linux Do 社区 Credit 积分服务平台
+
+[English](./README.md)
+
+[](https://opensource.org/licenses/Apache-2.0)
+[](https://golang.org/)
+[](https://nextjs.org/)
+[](https://reactjs.org/)
+
+[](https://github.com/linux-do/credit/releases)
+[](https://github.com/linux-do/credit/stargazers)
+[](https://github.com/linux-do/credit/network)
+[](https://github.com/linux-do/credit/issues)
+[](https://github.com/linux-do/credit/pulls)
+[](https://github.com/linux-do/credit/graphs/contributors)
+
+[](https://github.com/linux-do/credit/actions/workflows/build_backend.yml)
+[](https://github.com/linux-do/credit/actions/workflows/build_frontend.yml)
+[](https://github.com/linux-do/credit/actions/workflows/build_image.yml)
+[](https://github.com/linux-do/credit/actions/workflows/codeql.yml)
+[](https://github.com/linux-do/credit/actions/workflows/eslint.yml)
+
+## 📖 项目简介
+
+LINUX DO Credit 是一个为 Linux Do 社区打造的积分服务平台,旨在提供一系列积分相关服务,为社区开发者提供积分流转基础框架。
+
+### ✨ 主要特性
+
+- 🔐 **OAuth2 认证** - 集成 Linux Do 社区账号系统
+- 🛡️ **风险控制** - 完善的信任等级和风险评估系统
+- 📊 **实时监控** - 详细的分发统计和用户行为分析
+- 🎨 **现代化界面** - 基于 Next.js 16 和 React 19 的响应式设计
+- ⚡ **高性能** - Go 后端 + Redis 缓存 + PostgreSQL 数据库
+
+## 🏗️ 架构概览
+
+```
+┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
+│ Frontend │ │ Backend │ │ Database │
+│ (Next.js) │◄──►│ (Go) │◄──►│ (PostgreSQL) │
+│ │ │ │ │ │
+│ • React 19 │ │ • Gin Framework │ │ • PostgreSQL │
+│ • TypeScript │ │ • OAuth2 │ │ • Redis Cache │
+│ • Tailwind CSS │ │ • Session Store │ │ │
+│ • Shadcn UI │ │ • OpenTelemetry │ │ │
+│ │ │ • Swagger API │ │ │
+└─────────────────┘ └─────────────────┘ └─────────────────┘
+```
+
+## 🛠️ 技术栈
+
+### 后端
+- **[Go 1.26](https://go.dev/doc)** - 主要开发语言
+- **[GIN](https://github.com/gin-gonic/gin)** - Web 框架
+- **[GORM](https://github.com/go-gorm/gorm)** - ORM 框架
+- **[Redis](https://github.com/redis/redis)** - 缓存和会话存储
+- **[PostgreSQL](https://www.postgresql.org)** - 主数据库
+- **[OpenTelemetry](https://opentelemetry.io)** - 可观测性
+- **[Swagger](https://github.com/swaggo/swag)** - API 文档
+
+### 前端
+- **[Next.js 16](https://github.com/vercel/next.js)** - React 框架
+- **[React 19](https://github.com/facebook/react)** - UI 库
+- **[TypeScript](https://github.com/microsoft/TypeScript)** - 类型安全
+- **[Tailwind CSS 4](https://github.com/tailwindlabs/tailwindcss)** - 样式框架
+- **[Shadcn UI](https://github.com/shadcn-ui/ui)** - 组件库
+- **[Lucide Icons](https://github.com/lucide-icons/lucide)** - 图标库
+
+## 📋 环境要求
+
+- **Go** >= 1.26
+- **Node.js** >= 18.0
+- **PostgreSQL** >= 18
+- **Redis** >= 6.0
+- **pnpm** >= 8.0 (推荐)
+
+## 🚀 快速开始
+
+### 1. 克隆项目
+
+```bash
+git clone https://github.com/linux-do/credit.git
+cd credit
+```
+
+### 2. 配置环境
+
+复制配置文件并编辑:
+
+```bash
+cp config.example.yaml config.yaml
+```
+
+编辑 `config.yaml` 文件,配置数据库连接、Redis、OAuth2 等信息。
+
+### 3. 初始化数据库
+
+```bash
+# 创建数据库
+createdb -h <主机> -p 5432 -U postgres linux_do_credit
+
+# 如果需要指定字符集,可使用
+# psql -h <主机> -p 5432 -U postgres -c "CREATE DATABASE linux_do_credit WITH ENCODING 'UTF8' LC_COLLATE='zh_CN.UTF-8' LC_CTYPE='zh_CN.UTF-8' TEMPLATE template0;"
+
+# 运行迁移(启动后端时会自动执行)
+```
+
+### 4. 启动后端
+
+```bash
+# 安装 Go 依赖
+go mod tidy
+
+# 生成 API 文档
+make swagger
+
+# 启动后端服务
+go run main.go api
+```
+
+### 5. 启动前端
+
+```bash
+cd frontend
+
+# 安装依赖
+pnpm install
+
+# 启动开发服务器
+pnpm dev
+```
+
+### 6. 访问应用
+
+- **前端界面**: http://localhost:3000
+- **API 文档**: http://localhost:8000/swagger/index.html
+- **健康检查**: http://localhost:8000/api/v1/health
+- **就绪检查**: http://localhost:8000/api/v1/ready
+
+## ⚙️ 配置说明
+
+### 主要配置项
+
+| 配置项 | 说明 | 示例 |
+|--------|------|------|
+| `app.addr` | 后端服务监听地址 | `:8000` |
+| `worker.port` | Worker 探针端口 | `8001` |
+| `scheduler.port` | Scheduler 探针端口 | `8002` |
+| `oauth2.client_id` | OAuth2 客户端 ID | `your_client_id` |
+| `database.host` | PostgreSQL 数据库地址 | `127.0.0.1` |
+| `database.port` | PostgreSQL 数据库端口 | `5432` |
+| `database.username` | PostgreSQL 数据库用户名 | `postgres` |
+| `database.password` | PostgreSQL 数据库密码 | `password` |
+| `database.database` | PostgreSQL 数据库名称 | `linux_do_credit` |
+| `database.ssl_mode` | PostgreSQL SSL 模式 | `disable` |
+| `database.application_name` | PostgreSQL 应用标识 | `credit-server` |
+| `database.search_path` | PostgreSQL 搜索路径 | `public` |
+| `database.default_query_exec_mode` | SQL 缓存模式 | `cache_statement` |
+| `redis.host` | Redis 服务器地址 | `127.0.0.1` |
+
+详细配置说明请参考 `config.example.yaml` 文件。
+
+## 🔧 开发指南
+
+### 后端开发
+
+```bash
+# 运行 API 服务器
+go run main.go api
+
+# 运行任务调度器
+go run main.go scheduler
+
+# 运行工作队列
+go run main.go worker
+
+# 生成 Swagger 文档
+make swagger
+
+# 代码格式化和检查
+make tidy
+```
+
+### 前端开发
+
+```bash
+cd frontend
+
+# 开发模式(使用 Turbopack)
+pnpm dev
+
+# 构建生产版本
+pnpm build
+
+# 启动生产服务
+pnpm start
+
+# 代码检查和格式化
+pnpm lint
+pnpm format
+```
+
+## 📚 API 文档
+
+API 文档通过 Swagger 自动生成,启动后端服务后可访问:
+
+```
+http://localhost:8000/swagger/index.html
+```
+
+## 🧪 测试
+
+```bash
+# 后端测试
+go test ./...
+
+# 前端测试
+cd frontend
+pnpm test
+```
+
+## 🚀 部署
+
+### Docker 部署
+
+```bash
+# 构建镜像
+docker build -t linux-do-credit .
+
+# 运行容器
+docker run -d -p 8000:8000 linux-do-credit
+```
+
+### 生产环境部署
+
+1. 构建前端资源:
+ ```bash
+ cd frontend && pnpm build
+ ```
+
+2. 编译后端程序:
+ ```bash
+ go build -o credit main.go
+ ```
+
+3. 配置生产环境的 `config.yaml`
+
+4. 启动服务:
+ ```bash
+ ./credit api
+ ```
+
+## 🤝 贡献指南
+
+我们欢迎社区贡献!请在提交代码前阅读:
+
+- [贡献指南](CONTRIBUTING.md)
+- [行为准则](CODE_OF_CONDUCT.md)
+- [贡献者许可协议](CLA.md)
+
+### 提交流程
+
+1. Fork 本仓库
+2. 创建特性分支 (`git checkout -b feature/your-feature`)
+3. 提交更改 (`git commit -am 'Add your feature'`)
+4. 推送到分支 (`git push origin feature/your-feature`)
+5. 创建 Pull Request
+
+## 📄 许可证
+
+本项目基于 [Apache2.0 许可证](LICENSE) 开源。
+
+## 🔗 相关链接
+
+- [Linux Do 社区](https://linux.do)
+- [问题反馈](https://github.com/linux-do/credit/issues)
+- [功能请求](https://github.com/linux-do/credit/issues/new?template=feature_request.md)
+
+## ❤️ 致谢
+
+感谢所有为本项目做出贡献的开发者和 Linux Do 社区的支持!
+
+## 📈 项目趋势
+
+[](https://star-history.com/#linux-do/credit&Date)
diff --git a/config.example.yaml b/config.example.yaml
index eade8fc0..945c4139 100644
--- a/config.example.yaml
+++ b/config.example.yaml
@@ -6,6 +6,7 @@ app:
app_name: "linux-do-credit"
env: "development" # development, testing, production
addr: ":8000"
+ node_id: 1 # 分布式节点 ID (0-1023),不同实例必须不同
graceful_shutdown_timeout: 30
session_cookie_name: "linux_do_credit_session_id" # change this in local dev env
session_secret: "" # you can't change this after first time start
@@ -14,13 +15,15 @@ app:
session_secure: false
session_http_only: false
api_prefix: "/api"
+ frontend_url: "http://localhost:3000"
frontend_pay_url: "http://localhost:3000/paying"
-# OAuth2
+# OAuth2/OIDC(优先)
oauth2:
client_id: ""
client_secret: ""
redirect_uri: ""
+ issuer: "https://connect.linux.do/" # OIDC Issuer URL,用于自动发现端点
authorization_endpoint: "https://connect.linux.do/oauth2/authorize"
token_endpoint: "https://connect.linux.do/oauth2/token"
user_endpoint: "https://connect.linux.do/api/user"
@@ -47,12 +50,27 @@ database:
search_path: "public"
statement_cache_capacity: 256
default_query_exec_mode: "cache_statement"
+ slow_threshold: 200ms
# replicas:
# - host: "replica1.db.local"
# port: 5432
# - host: "replica2.db.local"
# port: 5432
+# clickhouse
+clickhouse:
+ enabled: false
+ hosts:
+ - "127.0.0.1:9000"
+ username: "default"
+ password: ""
+ database: "linux_do_credit"
+ max_idle_conn: 10
+ max_open_conn: 100
+ conn_max_lifetime: 3600
+ dial_timeout: 5
+ block_buffer_size: 10
+
# Redis
# 支持三种模式:Standalone(单节点)、Sentinel(高可用)、Cluster(水平扩展)
redis:
@@ -85,15 +103,20 @@ log:
max_backups: 10
compress: true
-# Schedule
-schedule:
- user_gamification_score_dispatch_interval_seconds: 3
+# Scheduler
+scheduler:
+ port: 8002 # scheduler probe port
update_user_gamification_scores_task_cron: "0 2 * * *"
dispute_auto_refund_dispatch_interval_seconds: 3
auto_refund_expired_disputes_task_cron: "0 0 * * *"
+ sync_orders_to_clickhouse_task_cron: "10 0 * * *"
+ refund_expired_red_envelopes_task_cron: "0 1 * * *"
+ cleanup_unused_uploads_task_cron: "0 */2 * * *"
+ settle_pending_payments_task_cron: "0 * * * *"
# Worker
worker:
+ port: 8001 # worker probe port
concurrency: 20
strict_priority: false
queues:
@@ -103,11 +126,41 @@ worker:
priority: 5
- name: default
priority: 3
+ # 积分更新速率限制:rate 次/period 秒
+ gamification_score_rate_limit:
+ rate: 1 # 允许的请求次数
+ period: 3 # 时间周期(秒)
# linuxDo
linuxDo:
api_key: ""
+# OpenAPI Risk
+openapi_risk:
+ enabled: false
+ base_url: "https://audit.example.com"
+ username: ""
+ password: ""
+ cache_ttl_seconds: 3600
+ prompt_risk_levels: []
+ block_risk_levels: []
+
# OpenTelemetry
otel:
sampling_rate: 0.1 # 采样率 0.0-1.0
+
+# S3 Compatible Storage
+# 支持 AWS S3、MinIO、Cloudflare R2、腾讯 COS 等 S3 兼容存储
+s3:
+ enabled: true
+ endpoint: "https://.r2.cloudflarestorage.com"
+ region: "auto"
+ bucket: ""
+ access_key_id: ""
+ secret_access_key: ""
+ path_style: false # MinIO 等自托管服务设为 true
+ key_prefix: "" # 对象 key 前缀,如 "uploads/",可用于分目录存储
+ cdn_url: "" # CDN 域名(如 https://cdn.example.com),为空则直接读 S3
+ local_cache:
+ enabled: false
+ cache_dir: "./s3_cache"
diff --git a/docs/docs.go b/docs/docs.go
index 466e3a03..cbb8e673 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -39,19 +39,16 @@ const docTemplate = `{
"required": true
},
{
+ "maxLength": 64,
+ "minLength": 1,
"type": "string",
"name": "out_trade_no",
- "in": "query"
- },
- {
- "type": "string",
- "name": "pid",
"in": "query",
"required": true
},
{
- "type": "integer",
- "name": "trade_no",
+ "type": "string",
+ "name": "pid",
"in": "query",
"required": true
}
@@ -96,23 +93,7 @@ const docTemplate = `{
}
}
},
- "/api/v1/admin/system-configs": {
- "get": {
- "produces": [
- "application/json"
- ],
- "tags": [
- "admin"
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/util.ResponseAny"
- }
- }
- }
- },
+ "/api/v1/admin/orders": {
"post": {
"consumes": [
"application/json"
@@ -130,7 +111,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/system_config.CreateSystemConfigRequest"
+ "$ref": "#/definitions/order.listOrdersRequest"
}
}
],
@@ -144,33 +125,8 @@ const docTemplate = `{
}
}
},
- "/api/v1/admin/system-configs/{key}": {
- "get": {
- "produces": [
- "application/json"
- ],
- "tags": [
- "admin"
- ],
- "parameters": [
- {
- "type": "string",
- "description": "配置键",
- "name": "key",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/util.ResponseAny"
- }
- }
- }
- },
- "put": {
+ "/api/v1/admin/orders/{id}/refund": {
+ "post": {
"consumes": [
"application/json"
],
@@ -182,9 +138,9 @@ const docTemplate = `{
],
"parameters": [
{
- "type": "string",
- "description": "配置键",
- "name": "key",
+ "type": "integer",
+ "description": "订单ID",
+ "name": "id",
"in": "path",
"required": true
},
@@ -192,36 +148,10 @@ const docTemplate = `{
"description": "request body",
"name": "request",
"in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/system_config.UpdateSystemConfigRequest"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
"schema": {
- "$ref": "#/definitions/util.ResponseAny"
+ "$ref": "#/definitions/order.refundOrderRequest"
}
}
- }
- },
- "delete": {
- "produces": [
- "application/json"
- ],
- "tags": [
- "admin"
- ],
- "parameters": [
- {
- "type": "string",
- "description": "配置键",
- "name": "key",
- "in": "path",
- "required": true
- }
],
"responses": {
"200": {
@@ -233,7 +163,7 @@ const docTemplate = `{
}
}
},
- "/api/v1/admin/user-pay-configs": {
+ "/api/v1/admin/system-configs": {
"get": {
"produces": [
"application/json"
@@ -267,7 +197,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/user_pay_config.CreateUserPayConfigRequest"
+ "$ref": "#/definitions/system_config.CreateSystemConfigRequest"
}
}
],
@@ -281,7 +211,7 @@ const docTemplate = `{
}
}
},
- "/api/v1/admin/user-pay-configs/{id}": {
+ "/api/v1/admin/system-configs/{key}": {
"get": {
"produces": [
"application/json"
@@ -292,8 +222,8 @@ const docTemplate = `{
"parameters": [
{
"type": "string",
- "description": "配置ID",
- "name": "id",
+ "description": "配置键",
+ "name": "key",
"in": "path",
"required": true
}
@@ -320,8 +250,8 @@ const docTemplate = `{
"parameters": [
{
"type": "string",
- "description": "配置ID",
- "name": "id",
+ "description": "配置键",
+ "name": "key",
"in": "path",
"required": true
},
@@ -331,7 +261,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/user_pay_config.UpdateUserPayConfigRequest"
+ "$ref": "#/definitions/system_config.UpdateSystemConfigRequest"
}
}
],
@@ -354,8 +284,8 @@ const docTemplate = `{
"parameters": [
{
"type": "string",
- "description": "配置ID",
- "name": "id",
+ "description": "配置键",
+ "name": "key",
"in": "path",
"required": true
}
@@ -370,8 +300,8 @@ const docTemplate = `{
}
}
},
- "/api/v1/config/public": {
- "get": {
+ "/api/v1/admin/tasks/dispatch": {
+ "post": {
"consumes": [
"application/json"
],
@@ -379,7 +309,18 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "config"
+ "admin"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/task.DispatchTaskRequest"
+ }
+ }
],
"responses": {
"200": {
@@ -391,13 +332,13 @@ const docTemplate = `{
}
}
},
- "/api/v1/health": {
+ "/api/v1/admin/tasks/types": {
"get": {
"produces": [
"application/json"
],
"tags": [
- "health"
+ "admin"
],
"responses": {
"200": {
@@ -409,13 +350,13 @@ const docTemplate = `{
}
}
},
- "/api/v1/merchant/api-keys": {
+ "/api/v1/admin/user-pay-configs": {
"get": {
"produces": [
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"responses": {
"200": {
@@ -434,7 +375,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
@@ -443,7 +384,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/api_key.CreateAPIKeyRequest"
+ "$ref": "#/definitions/user_pay_config.CreateUserPayConfigRequest"
}
}
],
@@ -457,19 +398,18 @@ const docTemplate = `{
}
}
},
- "/api/v1/merchant/api-keys/{id}": {
+ "/api/v1/admin/user-pay-configs/{id}": {
"get": {
"produces": [
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
- "type": "integer",
- "format": "int64",
- "description": "API Key ID",
+ "type": "string",
+ "description": "配置ID",
"name": "id",
"in": "path",
"required": true
@@ -492,13 +432,12 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
- "type": "integer",
- "format": "int64",
- "description": "API Key ID",
+ "type": "string",
+ "description": "配置ID",
"name": "id",
"in": "path",
"required": true
@@ -509,7 +448,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/api_key.UpdateAPIKeyRequest"
+ "$ref": "#/definitions/user_pay_config.UpdateUserPayConfigRequest"
}
}
],
@@ -527,13 +466,12 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
- "type": "integer",
- "format": "int64",
- "description": "API Key ID",
+ "type": "string",
+ "description": "配置ID",
"name": "id",
"in": "path",
"required": true
@@ -549,22 +487,37 @@ const docTemplate = `{
}
}
},
- "/api/v1/merchant/api-keys/{id}/payment-links": {
+ "/api/v1/admin/users": {
"get": {
"produces": [
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
+ "minimum": 1,
"type": "integer",
- "format": "int64",
- "description": "API Key ID",
- "name": "id",
- "in": "path",
- "required": true
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "maximum": 100,
+ "minimum": 1,
+ "type": "integer",
+ "name": "page_size",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "name": "user_id",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "name": "username",
+ "in": "query"
}
],
"responses": {
@@ -575,33 +528,31 @@ const docTemplate = `{
}
}
}
- },
- "post": {
- "consumes": [
- "application/json"
- ],
+ }
+ },
+ "/api/v1/admin/users/{id}/status": {
+ "put": {
"produces": [
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
"type": "integer",
- "format": "int64",
- "description": "API Key ID",
+ "description": "用户ID",
"name": "id",
"in": "path",
"required": true
},
{
- "description": "创建支付链接请求",
+ "description": "状态",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/link.CreatePaymentLinkRequest"
+ "$ref": "#/definitions/user.updateUserStatusRequest"
}
}
],
@@ -615,31 +566,16 @@ const docTemplate = `{
}
}
},
- "/api/v1/merchant/api-keys/{id}/payment-links/{linkId}": {
- "delete": {
+ "/api/v1/config/public": {
+ "get": {
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "merchant"
- ],
- "parameters": [
- {
- "type": "integer",
- "format": "int64",
- "description": "API Key ID",
- "name": "id",
- "in": "path",
- "required": true
- },
- {
- "type": "integer",
- "format": "int64",
- "description": "Payment Link ID",
- "name": "linkId",
- "in": "path",
- "required": true
- }
+ "config"
],
"responses": {
"200": {
@@ -651,8 +587,8 @@ const docTemplate = `{
}
}
},
- "/api/v1/merchant/payment": {
- "post": {
+ "/api/v1/dashboard/stats/daily": {
+ "get": {
"consumes": [
"application/json"
],
@@ -660,17 +596,16 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "payment"
+ "dashboard"
],
+ "summary": "获取每日收支统计",
"parameters": [
{
- "description": "支付订单请求",
- "name": "request",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/payment.PayOrderRequest"
- }
+ "type": "integer",
+ "description": "查询天数,最大7天",
+ "name": "days",
+ "in": "query",
+ "required": true
}
],
"responses": {
@@ -683,8 +618,8 @@ const docTemplate = `{
}
}
},
- "/api/v1/merchant/payment-links/pay": {
- "post": {
+ "/api/v1/dashboard/stats/top-customers": {
+ "get": {
"consumes": [
"application/json"
],
@@ -692,17 +627,23 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "merchant"
+ "dashboard"
],
+ "summary": "获取Top客户",
"parameters": [
{
- "description": "支付请求",
- "name": "request",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/link.PayByLinkRequest"
- }
+ "type": "integer",
+ "description": "查询天数,最大7天",
+ "name": "days",
+ "in": "query",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "返回数量,最大10",
+ "name": "limit",
+ "in": "query",
+ "required": true
}
],
"responses": {
@@ -715,21 +656,725 @@ const docTemplate = `{
}
}
},
- "/api/v1/merchant/payment-links/{token}": {
+ "/api/v1/dashboard/stats/user-balance": {
"get": {
+ "description": "统计所有用户的AvailableBalance字段",
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "merchant"
+ "dashboard"
+ ],
+ "summary": "获取用户余额统计",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/util.ResponseAny"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/definitions/dashboard.UserBalanceStatsResponse"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/health": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "health"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/leaderboard": {
+ "get": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "leaderboard"
+ ],
+ "summary": "获取排行榜列表",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "页码",
+ "name": "page",
+ "in": "query",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "每页数量",
+ "name": "page_size",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/leaderboard/me": {
+ "get": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "leaderboard"
+ ],
+ "summary": "获取当前用户排名",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/leaderboard/users/{id}": {
+ "get": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "leaderboard"
+ ],
+ "summary": "获取指定用户排名",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "用户ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/api-keys": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ },
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/api_key.CreateAPIKeyRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/api-keys/{id}": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ },
+ "put": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/api_key.UpdateAPIKeyRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ },
+ "delete": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/api-keys/{id}/payment-links": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ },
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "创建支付链接请求",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/link.PaymentLinkRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/api-keys/{id}/payment-links/{linkId}": {
+ "put": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "Payment Link ID",
+ "name": "linkId",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "更新支付链接请求",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/link.PaymentLinkRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ },
+ "delete": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "Payment Link ID",
+ "name": "linkId",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/payment": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "payment"
+ ],
+ "parameters": [
+ {
+ "description": "支付订单请求",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/payment.PayOrderRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/payment-links/pay": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "description": "支付请求",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/link.PayByLinkRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/payment-links/{token}": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "string",
+ "description": "支付链接 Token",
+ "name": "token",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/payment/order": {
+ "get": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "payment"
+ ],
+ "parameters": [
+ {
+ "type": "string",
+ "description": "订单号",
+ "name": "order_no",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/oauth/callback": {
+ "post": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "oauth"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/oauth.CallbackRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/oauth/login": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "oauth"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/oauth/logout": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "oauth"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/oauth/user-info": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "oauth"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/order/dispute": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "order"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dispute.CreateDisputeRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/order/dispute/close": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "order"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dispute.CloseDisputeRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/order/disputes": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "order"
],
"parameters": [
{
- "type": "string",
- "description": "支付链接 Token",
- "name": "token",
- "in": "path",
- "required": true
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "schema": {
+ "$ref": "#/definitions/dispute.ListDisputesRequest"
+ }
}
],
"responses": {
@@ -742,8 +1387,8 @@ const docTemplate = `{
}
}
},
- "/api/v1/merchant/payment/order": {
- "get": {
+ "/api/v1/order/disputes/merchant": {
+ "post": {
"consumes": [
"application/json"
],
@@ -751,15 +1396,16 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "payment"
+ "order"
],
"parameters": [
{
- "type": "string",
- "description": "订单号",
- "name": "order_no",
- "in": "query",
- "required": true
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "schema": {
+ "$ref": "#/definitions/dispute.ListDisputesRequest"
+ }
}
],
"responses": {
@@ -772,13 +1418,16 @@ const docTemplate = `{
}
}
},
- "/api/v1/oauth/callback": {
+ "/api/v1/order/refund-review": {
"post": {
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "oauth"
+ "order"
],
"parameters": [
{
@@ -787,7 +1436,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/oauth.CallbackRequest"
+ "$ref": "#/definitions/dispute.RefundReviewRequest"
}
}
],
@@ -801,13 +1450,26 @@ const docTemplate = `{
}
}
},
- "/api/v1/oauth/login": {
- "get": {
+ "/api/v1/order/transactions": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "oauth"
+ "order"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "schema": {
+ "$ref": "#/definitions/order.TransactionListRequest"
+ }
+ }
],
"responses": {
"200": {
@@ -819,13 +1481,27 @@ const docTemplate = `{
}
}
},
- "/api/v1/oauth/logout": {
- "get": {
+ "/api/v1/payment/transfer": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "oauth"
+ "payment"
+ ],
+ "parameters": [
+ {
+ "description": "转账请求",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/payment.TransferRequest"
+ }
+ }
],
"responses": {
"200": {
@@ -837,13 +1513,13 @@ const docTemplate = `{
}
}
},
- "/api/v1/oauth/user-info": {
+ "/api/v1/ready": {
"get": {
"produces": [
"application/json"
],
"tags": [
- "oauth"
+ "health"
],
"responses": {
"200": {
@@ -851,11 +1527,17 @@ const docTemplate = `{
"schema": {
"$ref": "#/definitions/util.ResponseAny"
}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
}
}
}
},
- "/api/v1/order/dispute": {
+ "/api/v1/redenvelope/claim": {
"post": {
"consumes": [
"application/json"
@@ -864,16 +1546,16 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "order"
+ "redenvelope"
],
"parameters": [
{
- "description": "request body",
+ "description": "领取红包请求",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/dispute.CreateDisputeRequest"
+ "$ref": "#/definitions/redenvelope.ClaimRequest"
}
}
],
@@ -887,7 +1569,34 @@ const docTemplate = `{
}
}
},
- "/api/v1/order/dispute/close": {
+ "/api/v1/redenvelope/covers": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "redenvelope"
+ ],
+ "parameters": [
+ {
+ "type": "string",
+ "description": "封面类型 (cover/heterotypic)",
+ "name": "type",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/redenvelope/create": {
"post": {
"consumes": [
"application/json"
@@ -896,16 +1605,16 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "order"
+ "redenvelope"
],
"parameters": [
{
- "description": "request body",
+ "description": "创建红包请求",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/dispute.CloseDisputeRequest"
+ "$ref": "#/definitions/redenvelope.CreateRequest"
}
}
],
@@ -919,7 +1628,7 @@ const docTemplate = `{
}
}
},
- "/api/v1/order/disputes": {
+ "/api/v1/redenvelope/list": {
"post": {
"consumes": [
"application/json"
@@ -928,15 +1637,16 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "order"
+ "redenvelope"
],
"parameters": [
{
- "description": "request body",
+ "description": "列表请求",
"name": "request",
"in": "body",
+ "required": true,
"schema": {
- "$ref": "#/definitions/dispute.ListDisputesRequest"
+ "$ref": "#/definitions/redenvelope.ListRequest"
}
}
],
@@ -950,25 +1660,21 @@ const docTemplate = `{
}
}
},
- "/api/v1/order/disputes/merchant": {
- "post": {
- "consumes": [
- "application/json"
- ],
+ "/api/v1/redenvelope/{id}": {
+ "get": {
"produces": [
"application/json"
],
"tags": [
- "order"
+ "redenvelope"
],
"parameters": [
{
- "description": "request body",
- "name": "request",
- "in": "body",
- "schema": {
- "$ref": "#/definitions/dispute.ListDisputesRequest"
- }
+ "type": "string",
+ "description": "红包ID",
+ "name": "id",
+ "in": "path",
+ "required": true
}
],
"responses": {
@@ -981,26 +1687,31 @@ const docTemplate = `{
}
}
},
- "/api/v1/order/refund-review": {
+ "/api/v1/upload/redenvelope/cover": {
"post": {
"consumes": [
- "application/json"
+ "multipart/form-data"
],
"produces": [
"application/json"
],
"tags": [
- "order"
+ "upload"
],
"parameters": [
{
- "description": "request body",
- "name": "request",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/dispute.RefundReviewRequest"
- }
+ "type": "file",
+ "description": "图片文件",
+ "name": "file",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "封面类型 (cover/heterotypic)",
+ "name": "type",
+ "in": "formData",
+ "required": true
}
],
"responses": {
@@ -1013,8 +1724,8 @@ const docTemplate = `{
}
}
},
- "/api/v1/order/transactions": {
- "post": {
+ "/api/v1/user/pay-key": {
+ "put": {
"consumes": [
"application/json"
],
@@ -1022,15 +1733,16 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "order"
+ "user"
],
"parameters": [
{
"description": "request body",
"name": "request",
"in": "body",
+ "required": true,
"schema": {
- "$ref": "#/definitions/order.TransactionListRequest"
+ "$ref": "#/definitions/user.UpdatePayKeyRequest"
}
}
],
@@ -1044,7 +1756,31 @@ const docTemplate = `{
}
}
},
- "/api/v1/payment/transfer": {
+ "/f/{id}": {
+ "get": {
+ "produces": [
+ "application/octet-stream"
+ ],
+ "tags": [
+ "upload"
+ ],
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Upload ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK"
+ }
+ }
+ }
+ },
+ "/pay/distribute": {
"post": {
"consumes": [
"application/json"
@@ -1057,12 +1793,19 @@ const docTemplate = `{
],
"parameters": [
{
- "description": "转账请求",
+ "type": "string",
+ "description": "Basic Auth (base64(client_id:client_secret))",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "description": "分发请求",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/payment.TransferRequest"
+ "$ref": "#/definitions/payment.MerchantDistributeRequest"
}
}
],
@@ -1076,16 +1819,16 @@ const docTemplate = `{
}
}
},
- "/api/v1/user/pay-key": {
- "put": {
+ "/pay/submit.php": {
+ "get": {
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
],
"tags": [
- "user"
+ "payment"
],
"parameters": [
{
@@ -1094,7 +1837,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/user.UpdatePayKeyRequest"
+ "$ref": "#/definitions/payment.CreateOrderRequest"
}
}
],
@@ -1106,9 +1849,7 @@ const docTemplate = `{
}
}
}
- }
- },
- "/pay/submit.php": {
+ },
"post": {
"consumes": [
"application/x-www-form-urlencoded"
@@ -1166,9 +1907,16 @@ const docTemplate = `{
"type": "string",
"maxLength": 100
},
+ "public_key": {
+ "type": "string",
+ "maxLength": 100
+ },
"redirect_uri": {
"type": "string",
"maxLength": 100
+ },
+ "test_mode": {
+ "type": "boolean"
}
}
},
@@ -1179,21 +1927,54 @@ const docTemplate = `{
"type": "string",
"maxLength": 100
},
- "app_homepage_url": {
- "type": "string",
- "maxLength": 100
+ "app_homepage_url": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "app_name": {
+ "type": "string",
+ "maxLength": 20
+ },
+ "notify_url": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "public_key": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "redirect_uri": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "test_mode": {
+ "type": "boolean"
+ }
+ }
+ },
+ "dashboard.UserBalanceStatsResponse": {
+ "type": "object",
+ "properties": {
+ "avg_amount": {
+ "type": "number"
+ },
+ "max_amount": {
+ "type": "number"
+ },
+ "median_amount": {
+ "type": "number"
},
- "app_name": {
- "type": "string",
- "maxLength": 20
+ "min_amount": {
+ "type": "number"
},
- "notify_url": {
- "type": "string",
- "maxLength": 100
+ "std_dev": {
+ "type": "number"
},
- "redirect_uri": {
- "type": "string",
- "maxLength": 100
+ "total_amount": {
+ "type": "number"
+ },
+ "total_count": {
+ "type": "integer"
}
}
},
@@ -1204,7 +1985,8 @@ const docTemplate = `{
],
"properties": {
"dispute_id": {
- "type": "integer"
+ "type": "string",
+ "example": "0"
}
}
},
@@ -1216,7 +1998,8 @@ const docTemplate = `{
],
"properties": {
"order_id": {
- "type": "integer"
+ "type": "string",
+ "example": "0"
},
"reason": {
"type": "string",
@@ -1228,7 +2011,8 @@ const docTemplate = `{
"type": "object",
"properties": {
"dispute_id": {
- "type": "integer"
+ "type": "string",
+ "example": "0"
},
"page": {
"type": "integer",
@@ -1257,7 +2041,8 @@ const docTemplate = `{
],
"properties": {
"dispute_id": {
- "type": "integer"
+ "type": "string",
+ "example": "0"
},
"reason": {
"type": "string",
@@ -1272,46 +2057,65 @@ const docTemplate = `{
}
}
},
- "link.CreatePaymentLinkRequest": {
+ "link.PayByLinkRequest": {
"type": "object",
"required": [
- "amount",
- "product_name"
+ "pay_key",
+ "token"
],
"properties": {
- "amount": {
- "type": "number"
- },
- "product_name": {
+ "pay_key": {
"type": "string",
- "maxLength": 30
+ "maxLength": 6
},
"remark": {
"type": "string",
"maxLength": 100
+ },
+ "token": {
+ "type": "string"
}
}
},
- "link.PayByLinkRequest": {
+ "link.PaymentLinkRequest": {
"type": "object",
"required": [
- "pay_key",
- "token"
+ "amount",
+ "product_name"
],
"properties": {
- "pay_key": {
+ "amount": {
+ "type": "number"
+ },
+ "product_name": {
"type": "string",
- "maxLength": 6
+ "maxLength": 30
},
"remark": {
"type": "string",
"maxLength": 100
},
- "token": {
- "type": "string"
+ "total_limit": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "user_limit": {
+ "type": "integer",
+ "minimum": 1
}
}
},
+ "model.OrderTransferStatus": {
+ "type": "string",
+ "enum": [
+ "pending",
+ "completed"
+ ],
+ "x-enum-varnames": [
+ "OrderTransferStatusPending",
+ "OrderTransferStatusCompleted"
+ ]
+ },
"model.PayLevel": {
"type": "integer",
"format": "int32",
@@ -1328,6 +2132,17 @@ const docTemplate = `{
"PayLevelPremium"
]
},
+ "model.RedEnvelopeType": {
+ "type": "string",
+ "enum": [
+ "fixed",
+ "random"
+ ],
+ "x-enum-varnames": [
+ "RedEnvelopeTypeFixed",
+ "RedEnvelopeTypeRandom"
+ ]
+ },
"oauth.CallbackRequest": {
"type": "object",
"properties": {
@@ -1348,6 +2163,13 @@ const docTemplate = `{
"endTime": {
"type": "string"
},
+ "id": {
+ "type": "string",
+ "example": "0"
+ },
+ "order_name": {
+ "type": "string"
+ },
"page": {
"type": "integer",
"minimum": 1
@@ -1357,30 +2179,102 @@ const docTemplate = `{
"maximum": 100,
"minimum": 1
},
+ "payee_transfer_status": {
+ "enum": [
+ "pending",
+ "completed"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/model.OrderTransferStatus"
+ }
+ ]
+ },
+ "payee_username": {
+ "type": "string"
+ },
+ "payer_username": {
+ "type": "string"
+ },
"startTime": {
"type": "string"
},
- "status": {
+ "statuses": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "types": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "order.listOrdersRequest": {
+ "type": "object",
+ "properties": {
+ "client_id": {
"type": "string",
- "enum": [
- "success",
- "pending",
- "failed",
- "expired",
- "disputing",
- "refund",
- "refused"
- ]
+ "maxLength": 64
},
- "type": {
+ "end_time": {
+ "type": "string"
+ },
+ "id": {
"type": "string",
- "enum": [
- "receive",
- "payment",
- "transfer",
- "community",
- "online"
- ]
+ "example": "0"
+ },
+ "merchant_order_no": {
+ "type": "string",
+ "maxLength": 64
+ },
+ "order_name": {
+ "type": "string",
+ "maxLength": 64
+ },
+ "page": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "page_size": {
+ "type": "integer",
+ "maximum": 100,
+ "minimum": 1
+ },
+ "payee_username": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "payer_username": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "start_time": {
+ "type": "string"
+ },
+ "statuses": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "types": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "order.refundOrderRequest": {
+ "type": "object",
+ "properties": {
+ "remark": {
+ "type": "string",
+ "maxLength": 100
}
}
},
@@ -1395,7 +2289,13 @@ const docTemplate = `{
"type": "number"
},
"merchant_order_no": {
- "type": "string"
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1
+ },
+ "notify_url": {
+ "type": "string",
+ "maxLength": 100
},
"order_name": {
"type": "string",
@@ -1407,6 +2307,38 @@ const docTemplate = `{
"remark": {
"type": "string",
"maxLength": 100
+ },
+ "return_url": {
+ "type": "string",
+ "maxLength": 100
+ }
+ }
+ },
+ "payment.MerchantDistributeRequest": {
+ "type": "object",
+ "required": [
+ "amount",
+ "user_id",
+ "username"
+ ],
+ "properties": {
+ "amount": {
+ "type": "number"
+ },
+ "out_trade_no": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1
+ },
+ "remark": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "user_id": {
+ "type": "integer"
+ },
+ "username": {
+ "type": "string"
}
}
},
@@ -1531,7 +2463,8 @@ const docTemplate = `{
"maxLength": 6
},
"recipient_id": {
- "type": "integer"
+ "type": "string",
+ "example": "0"
},
"recipient_username": {
"type": "string"
@@ -1542,6 +2475,88 @@ const docTemplate = `{
}
}
},
+ "redenvelope.ClaimRequest": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "0"
+ }
+ }
+ },
+ "redenvelope.CreateRequest": {
+ "type": "object",
+ "required": [
+ "pay_key",
+ "total_amount",
+ "total_count",
+ "type"
+ ],
+ "properties": {
+ "cover_upload_id": {
+ "type": "string",
+ "example": "0"
+ },
+ "greeting": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "heterotypic_upload_id": {
+ "type": "string",
+ "example": "0"
+ },
+ "pay_key": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "total_amount": {
+ "type": "number"
+ },
+ "total_count": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "type": {
+ "enum": [
+ "fixed",
+ "random"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/model.RedEnvelopeType"
+ }
+ ]
+ }
+ }
+ },
+ "redenvelope.ListRequest": {
+ "type": "object",
+ "required": [
+ "page",
+ "page_size"
+ ],
+ "properties": {
+ "page": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "page_size": {
+ "type": "integer",
+ "maximum": 100,
+ "minimum": 1
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "sent",
+ "received"
+ ]
+ }
+ }
+ },
"system_config.CreateSystemConfigRequest": {
"type": "object",
"required": [
@@ -1579,6 +2594,26 @@ const docTemplate = `{
}
}
},
+ "task.DispatchTaskRequest": {
+ "type": "object",
+ "required": [
+ "task_type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string"
+ },
+ "start_time": {
+ "type": "string"
+ },
+ "task_type": {
+ "type": "string"
+ },
+ "user_id": {
+ "type": "integer"
+ }
+ }
+ },
"user.UpdatePayKeyRequest": {
"type": "object",
"required": [
@@ -1591,9 +2626,18 @@ const docTemplate = `{
}
}
},
+ "user.updateUserStatusRequest": {
+ "type": "object",
+ "properties": {
+ "is_active": {
+ "type": "boolean"
+ }
+ }
+ },
"user_pay_config.CreateUserPayConfigRequest": {
"type": "object",
"required": [
+ "distribute_rate",
"fee_rate",
"score_rate"
],
@@ -1601,6 +2645,9 @@ const docTemplate = `{
"daily_limit": {
"type": "integer"
},
+ "distribute_rate": {
+ "type": "number"
+ },
"fee_rate": {
"type": "number"
},
@@ -1611,8 +2658,7 @@ const docTemplate = `{
"type": "integer"
},
"min_score": {
- "type": "integer",
- "minimum": 0
+ "type": "integer"
},
"score_rate": {
"type": "number"
@@ -1622,6 +2668,7 @@ const docTemplate = `{
"user_pay_config.UpdateUserPayConfigRequest": {
"type": "object",
"required": [
+ "distribute_rate",
"fee_rate",
"score_rate"
],
@@ -1629,6 +2676,9 @@ const docTemplate = `{
"daily_limit": {
"type": "integer"
},
+ "distribute_rate": {
+ "type": "number"
+ },
"fee_rate": {
"type": "number"
},
@@ -1636,8 +2686,7 @@ const docTemplate = `{
"type": "integer"
},
"min_score": {
- "type": "integer",
- "minimum": 0
+ "type": "integer"
},
"score_rate": {
"type": "number"
@@ -1659,7 +2708,7 @@ const docTemplate = `{
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
- Version: "0.1.0",
+ Version: "1.0.0",
Host: "",
BasePath: "",
Schemes: []string{},
diff --git a/docs/swagger.json b/docs/swagger.json
index 6d6c93c0..003dc0fb 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -3,7 +3,7 @@
"info": {
"title": "LINUX DO Credit",
"contact": {},
- "version": "0.1.0"
+ "version": "1.0.0"
},
"paths": {
"/api.php": {
@@ -30,19 +30,16 @@
"required": true
},
{
+ "maxLength": 64,
+ "minLength": 1,
"type": "string",
"name": "out_trade_no",
- "in": "query"
- },
- {
- "type": "string",
- "name": "pid",
"in": "query",
"required": true
},
{
- "type": "integer",
- "name": "trade_no",
+ "type": "string",
+ "name": "pid",
"in": "query",
"required": true
}
@@ -87,23 +84,7 @@
}
}
},
- "/api/v1/admin/system-configs": {
- "get": {
- "produces": [
- "application/json"
- ],
- "tags": [
- "admin"
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/util.ResponseAny"
- }
- }
- }
- },
+ "/api/v1/admin/orders": {
"post": {
"consumes": [
"application/json"
@@ -121,7 +102,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/system_config.CreateSystemConfigRequest"
+ "$ref": "#/definitions/order.listOrdersRequest"
}
}
],
@@ -135,33 +116,8 @@
}
}
},
- "/api/v1/admin/system-configs/{key}": {
- "get": {
- "produces": [
- "application/json"
- ],
- "tags": [
- "admin"
- ],
- "parameters": [
- {
- "type": "string",
- "description": "配置键",
- "name": "key",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/util.ResponseAny"
- }
- }
- }
- },
- "put": {
+ "/api/v1/admin/orders/{id}/refund": {
+ "post": {
"consumes": [
"application/json"
],
@@ -173,9 +129,9 @@
],
"parameters": [
{
- "type": "string",
- "description": "配置键",
- "name": "key",
+ "type": "integer",
+ "description": "订单ID",
+ "name": "id",
"in": "path",
"required": true
},
@@ -183,36 +139,10 @@
"description": "request body",
"name": "request",
"in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/system_config.UpdateSystemConfigRequest"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
"schema": {
- "$ref": "#/definitions/util.ResponseAny"
+ "$ref": "#/definitions/order.refundOrderRequest"
}
}
- }
- },
- "delete": {
- "produces": [
- "application/json"
- ],
- "tags": [
- "admin"
- ],
- "parameters": [
- {
- "type": "string",
- "description": "配置键",
- "name": "key",
- "in": "path",
- "required": true
- }
],
"responses": {
"200": {
@@ -224,7 +154,7 @@
}
}
},
- "/api/v1/admin/user-pay-configs": {
+ "/api/v1/admin/system-configs": {
"get": {
"produces": [
"application/json"
@@ -258,7 +188,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/user_pay_config.CreateUserPayConfigRequest"
+ "$ref": "#/definitions/system_config.CreateSystemConfigRequest"
}
}
],
@@ -272,7 +202,7 @@
}
}
},
- "/api/v1/admin/user-pay-configs/{id}": {
+ "/api/v1/admin/system-configs/{key}": {
"get": {
"produces": [
"application/json"
@@ -283,8 +213,8 @@
"parameters": [
{
"type": "string",
- "description": "配置ID",
- "name": "id",
+ "description": "配置键",
+ "name": "key",
"in": "path",
"required": true
}
@@ -311,8 +241,8 @@
"parameters": [
{
"type": "string",
- "description": "配置ID",
- "name": "id",
+ "description": "配置键",
+ "name": "key",
"in": "path",
"required": true
},
@@ -322,7 +252,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/user_pay_config.UpdateUserPayConfigRequest"
+ "$ref": "#/definitions/system_config.UpdateSystemConfigRequest"
}
}
],
@@ -345,8 +275,8 @@
"parameters": [
{
"type": "string",
- "description": "配置ID",
- "name": "id",
+ "description": "配置键",
+ "name": "key",
"in": "path",
"required": true
}
@@ -361,8 +291,8 @@
}
}
},
- "/api/v1/config/public": {
- "get": {
+ "/api/v1/admin/tasks/dispatch": {
+ "post": {
"consumes": [
"application/json"
],
@@ -370,7 +300,18 @@
"application/json"
],
"tags": [
- "config"
+ "admin"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/task.DispatchTaskRequest"
+ }
+ }
],
"responses": {
"200": {
@@ -382,13 +323,13 @@
}
}
},
- "/api/v1/health": {
+ "/api/v1/admin/tasks/types": {
"get": {
"produces": [
"application/json"
],
"tags": [
- "health"
+ "admin"
],
"responses": {
"200": {
@@ -400,13 +341,13 @@
}
}
},
- "/api/v1/merchant/api-keys": {
+ "/api/v1/admin/user-pay-configs": {
"get": {
"produces": [
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"responses": {
"200": {
@@ -425,7 +366,7 @@
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
@@ -434,7 +375,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/api_key.CreateAPIKeyRequest"
+ "$ref": "#/definitions/user_pay_config.CreateUserPayConfigRequest"
}
}
],
@@ -448,19 +389,18 @@
}
}
},
- "/api/v1/merchant/api-keys/{id}": {
+ "/api/v1/admin/user-pay-configs/{id}": {
"get": {
"produces": [
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
- "type": "integer",
- "format": "int64",
- "description": "API Key ID",
+ "type": "string",
+ "description": "配置ID",
"name": "id",
"in": "path",
"required": true
@@ -483,13 +423,12 @@
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
- "type": "integer",
- "format": "int64",
- "description": "API Key ID",
+ "type": "string",
+ "description": "配置ID",
"name": "id",
"in": "path",
"required": true
@@ -500,7 +439,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/api_key.UpdateAPIKeyRequest"
+ "$ref": "#/definitions/user_pay_config.UpdateUserPayConfigRequest"
}
}
],
@@ -518,13 +457,12 @@
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
- "type": "integer",
- "format": "int64",
- "description": "API Key ID",
+ "type": "string",
+ "description": "配置ID",
"name": "id",
"in": "path",
"required": true
@@ -540,22 +478,37 @@
}
}
},
- "/api/v1/merchant/api-keys/{id}/payment-links": {
+ "/api/v1/admin/users": {
"get": {
"produces": [
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
+ "minimum": 1,
"type": "integer",
- "format": "int64",
- "description": "API Key ID",
- "name": "id",
- "in": "path",
- "required": true
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "maximum": 100,
+ "minimum": 1,
+ "type": "integer",
+ "name": "page_size",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "name": "user_id",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "name": "username",
+ "in": "query"
}
],
"responses": {
@@ -566,33 +519,31 @@
}
}
}
- },
- "post": {
- "consumes": [
- "application/json"
- ],
+ }
+ },
+ "/api/v1/admin/users/{id}/status": {
+ "put": {
"produces": [
"application/json"
],
"tags": [
- "merchant"
+ "admin"
],
"parameters": [
{
"type": "integer",
- "format": "int64",
- "description": "API Key ID",
+ "description": "用户ID",
"name": "id",
"in": "path",
"required": true
},
{
- "description": "创建支付链接请求",
+ "description": "状态",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/link.CreatePaymentLinkRequest"
+ "$ref": "#/definitions/user.updateUserStatusRequest"
}
}
],
@@ -606,31 +557,16 @@
}
}
},
- "/api/v1/merchant/api-keys/{id}/payment-links/{linkId}": {
- "delete": {
+ "/api/v1/config/public": {
+ "get": {
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "merchant"
- ],
- "parameters": [
- {
- "type": "integer",
- "format": "int64",
- "description": "API Key ID",
- "name": "id",
- "in": "path",
- "required": true
- },
- {
- "type": "integer",
- "format": "int64",
- "description": "Payment Link ID",
- "name": "linkId",
- "in": "path",
- "required": true
- }
+ "config"
],
"responses": {
"200": {
@@ -642,8 +578,8 @@
}
}
},
- "/api/v1/merchant/payment": {
- "post": {
+ "/api/v1/dashboard/stats/daily": {
+ "get": {
"consumes": [
"application/json"
],
@@ -651,17 +587,16 @@
"application/json"
],
"tags": [
- "payment"
+ "dashboard"
],
+ "summary": "获取每日收支统计",
"parameters": [
{
- "description": "支付订单请求",
- "name": "request",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/payment.PayOrderRequest"
- }
+ "type": "integer",
+ "description": "查询天数,最大7天",
+ "name": "days",
+ "in": "query",
+ "required": true
}
],
"responses": {
@@ -674,8 +609,8 @@
}
}
},
- "/api/v1/merchant/payment-links/pay": {
- "post": {
+ "/api/v1/dashboard/stats/top-customers": {
+ "get": {
"consumes": [
"application/json"
],
@@ -683,17 +618,23 @@
"application/json"
],
"tags": [
- "merchant"
+ "dashboard"
],
+ "summary": "获取Top客户",
"parameters": [
{
- "description": "支付请求",
- "name": "request",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/link.PayByLinkRequest"
- }
+ "type": "integer",
+ "description": "查询天数,最大7天",
+ "name": "days",
+ "in": "query",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "返回数量,最大10",
+ "name": "limit",
+ "in": "query",
+ "required": true
}
],
"responses": {
@@ -706,21 +647,725 @@
}
}
},
- "/api/v1/merchant/payment-links/{token}": {
+ "/api/v1/dashboard/stats/user-balance": {
"get": {
+ "description": "统计所有用户的AvailableBalance字段",
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "merchant"
+ "dashboard"
+ ],
+ "summary": "获取用户余额统计",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/util.ResponseAny"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/definitions/dashboard.UserBalanceStatsResponse"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/health": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "health"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/leaderboard": {
+ "get": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "leaderboard"
+ ],
+ "summary": "获取排行榜列表",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "页码",
+ "name": "page",
+ "in": "query",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "每页数量",
+ "name": "page_size",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/leaderboard/me": {
+ "get": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "leaderboard"
+ ],
+ "summary": "获取当前用户排名",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/leaderboard/users/{id}": {
+ "get": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "leaderboard"
+ ],
+ "summary": "获取指定用户排名",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "用户ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/api-keys": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ },
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/api_key.CreateAPIKeyRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/api-keys/{id}": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ },
+ "put": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/api_key.UpdateAPIKeyRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ },
+ "delete": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/api-keys/{id}/payment-links": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ },
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "创建支付链接请求",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/link.PaymentLinkRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/api-keys/{id}/payment-links/{linkId}": {
+ "put": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "Payment Link ID",
+ "name": "linkId",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "更新支付链接请求",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/link.PaymentLinkRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ },
+ "delete": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "API Key ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "format": "int64",
+ "description": "Payment Link ID",
+ "name": "linkId",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/payment": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "payment"
+ ],
+ "parameters": [
+ {
+ "description": "支付订单请求",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/payment.PayOrderRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/payment-links/pay": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "description": "支付请求",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/link.PayByLinkRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/payment-links/{token}": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "merchant"
+ ],
+ "parameters": [
+ {
+ "type": "string",
+ "description": "支付链接 Token",
+ "name": "token",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/merchant/payment/order": {
+ "get": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "payment"
+ ],
+ "parameters": [
+ {
+ "type": "string",
+ "description": "订单号",
+ "name": "order_no",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/oauth/callback": {
+ "post": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "oauth"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/oauth.CallbackRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/oauth/login": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "oauth"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/oauth/logout": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "oauth"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/oauth/user-info": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "oauth"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/order/dispute": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "order"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dispute.CreateDisputeRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/order/dispute/close": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "order"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/dispute.CloseDisputeRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/order/disputes": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "order"
],
"parameters": [
{
- "type": "string",
- "description": "支付链接 Token",
- "name": "token",
- "in": "path",
- "required": true
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "schema": {
+ "$ref": "#/definitions/dispute.ListDisputesRequest"
+ }
}
],
"responses": {
@@ -733,8 +1378,8 @@
}
}
},
- "/api/v1/merchant/payment/order": {
- "get": {
+ "/api/v1/order/disputes/merchant": {
+ "post": {
"consumes": [
"application/json"
],
@@ -742,15 +1387,16 @@
"application/json"
],
"tags": [
- "payment"
+ "order"
],
"parameters": [
{
- "type": "string",
- "description": "订单号",
- "name": "order_no",
- "in": "query",
- "required": true
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "schema": {
+ "$ref": "#/definitions/dispute.ListDisputesRequest"
+ }
}
],
"responses": {
@@ -763,13 +1409,16 @@
}
}
},
- "/api/v1/oauth/callback": {
+ "/api/v1/order/refund-review": {
"post": {
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "oauth"
+ "order"
],
"parameters": [
{
@@ -778,7 +1427,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/oauth.CallbackRequest"
+ "$ref": "#/definitions/dispute.RefundReviewRequest"
}
}
],
@@ -792,13 +1441,26 @@
}
}
},
- "/api/v1/oauth/login": {
- "get": {
+ "/api/v1/order/transactions": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "oauth"
+ "order"
+ ],
+ "parameters": [
+ {
+ "description": "request body",
+ "name": "request",
+ "in": "body",
+ "schema": {
+ "$ref": "#/definitions/order.TransactionListRequest"
+ }
+ }
],
"responses": {
"200": {
@@ -810,13 +1472,27 @@
}
}
},
- "/api/v1/oauth/logout": {
- "get": {
+ "/api/v1/payment/transfer": {
+ "post": {
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "oauth"
+ "payment"
+ ],
+ "parameters": [
+ {
+ "description": "转账请求",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/payment.TransferRequest"
+ }
+ }
],
"responses": {
"200": {
@@ -828,13 +1504,13 @@
}
}
},
- "/api/v1/oauth/user-info": {
+ "/api/v1/ready": {
"get": {
"produces": [
"application/json"
],
"tags": [
- "oauth"
+ "health"
],
"responses": {
"200": {
@@ -842,11 +1518,17 @@
"schema": {
"$ref": "#/definitions/util.ResponseAny"
}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
}
}
}
},
- "/api/v1/order/dispute": {
+ "/api/v1/redenvelope/claim": {
"post": {
"consumes": [
"application/json"
@@ -855,16 +1537,16 @@
"application/json"
],
"tags": [
- "order"
+ "redenvelope"
],
"parameters": [
{
- "description": "request body",
+ "description": "领取红包请求",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/dispute.CreateDisputeRequest"
+ "$ref": "#/definitions/redenvelope.ClaimRequest"
}
}
],
@@ -878,7 +1560,34 @@
}
}
},
- "/api/v1/order/dispute/close": {
+ "/api/v1/redenvelope/covers": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "redenvelope"
+ ],
+ "parameters": [
+ {
+ "type": "string",
+ "description": "封面类型 (cover/heterotypic)",
+ "name": "type",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/util.ResponseAny"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/redenvelope/create": {
"post": {
"consumes": [
"application/json"
@@ -887,16 +1596,16 @@
"application/json"
],
"tags": [
- "order"
+ "redenvelope"
],
"parameters": [
{
- "description": "request body",
+ "description": "创建红包请求",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/dispute.CloseDisputeRequest"
+ "$ref": "#/definitions/redenvelope.CreateRequest"
}
}
],
@@ -910,7 +1619,7 @@
}
}
},
- "/api/v1/order/disputes": {
+ "/api/v1/redenvelope/list": {
"post": {
"consumes": [
"application/json"
@@ -919,15 +1628,16 @@
"application/json"
],
"tags": [
- "order"
+ "redenvelope"
],
"parameters": [
{
- "description": "request body",
+ "description": "列表请求",
"name": "request",
"in": "body",
+ "required": true,
"schema": {
- "$ref": "#/definitions/dispute.ListDisputesRequest"
+ "$ref": "#/definitions/redenvelope.ListRequest"
}
}
],
@@ -941,25 +1651,21 @@
}
}
},
- "/api/v1/order/disputes/merchant": {
- "post": {
- "consumes": [
- "application/json"
- ],
+ "/api/v1/redenvelope/{id}": {
+ "get": {
"produces": [
"application/json"
],
"tags": [
- "order"
+ "redenvelope"
],
"parameters": [
{
- "description": "request body",
- "name": "request",
- "in": "body",
- "schema": {
- "$ref": "#/definitions/dispute.ListDisputesRequest"
- }
+ "type": "string",
+ "description": "红包ID",
+ "name": "id",
+ "in": "path",
+ "required": true
}
],
"responses": {
@@ -972,26 +1678,31 @@
}
}
},
- "/api/v1/order/refund-review": {
+ "/api/v1/upload/redenvelope/cover": {
"post": {
"consumes": [
- "application/json"
+ "multipart/form-data"
],
"produces": [
"application/json"
],
"tags": [
- "order"
+ "upload"
],
"parameters": [
{
- "description": "request body",
- "name": "request",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/dispute.RefundReviewRequest"
- }
+ "type": "file",
+ "description": "图片文件",
+ "name": "file",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "封面类型 (cover/heterotypic)",
+ "name": "type",
+ "in": "formData",
+ "required": true
}
],
"responses": {
@@ -1004,8 +1715,8 @@
}
}
},
- "/api/v1/order/transactions": {
- "post": {
+ "/api/v1/user/pay-key": {
+ "put": {
"consumes": [
"application/json"
],
@@ -1013,15 +1724,16 @@
"application/json"
],
"tags": [
- "order"
+ "user"
],
"parameters": [
{
"description": "request body",
"name": "request",
"in": "body",
+ "required": true,
"schema": {
- "$ref": "#/definitions/order.TransactionListRequest"
+ "$ref": "#/definitions/user.UpdatePayKeyRequest"
}
}
],
@@ -1035,7 +1747,31 @@
}
}
},
- "/api/v1/payment/transfer": {
+ "/f/{id}": {
+ "get": {
+ "produces": [
+ "application/octet-stream"
+ ],
+ "tags": [
+ "upload"
+ ],
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Upload ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK"
+ }
+ }
+ }
+ },
+ "/pay/distribute": {
"post": {
"consumes": [
"application/json"
@@ -1048,12 +1784,19 @@
],
"parameters": [
{
- "description": "转账请求",
+ "type": "string",
+ "description": "Basic Auth (base64(client_id:client_secret))",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "description": "分发请求",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/payment.TransferRequest"
+ "$ref": "#/definitions/payment.MerchantDistributeRequest"
}
}
],
@@ -1067,16 +1810,16 @@
}
}
},
- "/api/v1/user/pay-key": {
- "put": {
+ "/pay/submit.php": {
+ "get": {
"consumes": [
- "application/json"
+ "application/x-www-form-urlencoded"
],
"produces": [
"application/json"
],
"tags": [
- "user"
+ "payment"
],
"parameters": [
{
@@ -1085,7 +1828,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/user.UpdatePayKeyRequest"
+ "$ref": "#/definitions/payment.CreateOrderRequest"
}
}
],
@@ -1097,9 +1840,7 @@
}
}
}
- }
- },
- "/pay/submit.php": {
+ },
"post": {
"consumes": [
"application/x-www-form-urlencoded"
@@ -1157,9 +1898,16 @@
"type": "string",
"maxLength": 100
},
+ "public_key": {
+ "type": "string",
+ "maxLength": 100
+ },
"redirect_uri": {
"type": "string",
"maxLength": 100
+ },
+ "test_mode": {
+ "type": "boolean"
}
}
},
@@ -1170,21 +1918,54 @@
"type": "string",
"maxLength": 100
},
- "app_homepage_url": {
- "type": "string",
- "maxLength": 100
+ "app_homepage_url": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "app_name": {
+ "type": "string",
+ "maxLength": 20
+ },
+ "notify_url": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "public_key": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "redirect_uri": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "test_mode": {
+ "type": "boolean"
+ }
+ }
+ },
+ "dashboard.UserBalanceStatsResponse": {
+ "type": "object",
+ "properties": {
+ "avg_amount": {
+ "type": "number"
+ },
+ "max_amount": {
+ "type": "number"
+ },
+ "median_amount": {
+ "type": "number"
},
- "app_name": {
- "type": "string",
- "maxLength": 20
+ "min_amount": {
+ "type": "number"
},
- "notify_url": {
- "type": "string",
- "maxLength": 100
+ "std_dev": {
+ "type": "number"
},
- "redirect_uri": {
- "type": "string",
- "maxLength": 100
+ "total_amount": {
+ "type": "number"
+ },
+ "total_count": {
+ "type": "integer"
}
}
},
@@ -1195,7 +1976,8 @@
],
"properties": {
"dispute_id": {
- "type": "integer"
+ "type": "string",
+ "example": "0"
}
}
},
@@ -1207,7 +1989,8 @@
],
"properties": {
"order_id": {
- "type": "integer"
+ "type": "string",
+ "example": "0"
},
"reason": {
"type": "string",
@@ -1219,7 +2002,8 @@
"type": "object",
"properties": {
"dispute_id": {
- "type": "integer"
+ "type": "string",
+ "example": "0"
},
"page": {
"type": "integer",
@@ -1248,7 +2032,8 @@
],
"properties": {
"dispute_id": {
- "type": "integer"
+ "type": "string",
+ "example": "0"
},
"reason": {
"type": "string",
@@ -1263,46 +2048,65 @@
}
}
},
- "link.CreatePaymentLinkRequest": {
+ "link.PayByLinkRequest": {
"type": "object",
"required": [
- "amount",
- "product_name"
+ "pay_key",
+ "token"
],
"properties": {
- "amount": {
- "type": "number"
- },
- "product_name": {
+ "pay_key": {
"type": "string",
- "maxLength": 30
+ "maxLength": 6
},
"remark": {
"type": "string",
"maxLength": 100
+ },
+ "token": {
+ "type": "string"
}
}
},
- "link.PayByLinkRequest": {
+ "link.PaymentLinkRequest": {
"type": "object",
"required": [
- "pay_key",
- "token"
+ "amount",
+ "product_name"
],
"properties": {
- "pay_key": {
+ "amount": {
+ "type": "number"
+ },
+ "product_name": {
"type": "string",
- "maxLength": 6
+ "maxLength": 30
},
"remark": {
"type": "string",
"maxLength": 100
},
- "token": {
- "type": "string"
+ "total_limit": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "user_limit": {
+ "type": "integer",
+ "minimum": 1
}
}
},
+ "model.OrderTransferStatus": {
+ "type": "string",
+ "enum": [
+ "pending",
+ "completed"
+ ],
+ "x-enum-varnames": [
+ "OrderTransferStatusPending",
+ "OrderTransferStatusCompleted"
+ ]
+ },
"model.PayLevel": {
"type": "integer",
"format": "int32",
@@ -1319,6 +2123,17 @@
"PayLevelPremium"
]
},
+ "model.RedEnvelopeType": {
+ "type": "string",
+ "enum": [
+ "fixed",
+ "random"
+ ],
+ "x-enum-varnames": [
+ "RedEnvelopeTypeFixed",
+ "RedEnvelopeTypeRandom"
+ ]
+ },
"oauth.CallbackRequest": {
"type": "object",
"properties": {
@@ -1339,6 +2154,13 @@
"endTime": {
"type": "string"
},
+ "id": {
+ "type": "string",
+ "example": "0"
+ },
+ "order_name": {
+ "type": "string"
+ },
"page": {
"type": "integer",
"minimum": 1
@@ -1348,30 +2170,102 @@
"maximum": 100,
"minimum": 1
},
+ "payee_transfer_status": {
+ "enum": [
+ "pending",
+ "completed"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/model.OrderTransferStatus"
+ }
+ ]
+ },
+ "payee_username": {
+ "type": "string"
+ },
+ "payer_username": {
+ "type": "string"
+ },
"startTime": {
"type": "string"
},
- "status": {
+ "statuses": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "types": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "order.listOrdersRequest": {
+ "type": "object",
+ "properties": {
+ "client_id": {
"type": "string",
- "enum": [
- "success",
- "pending",
- "failed",
- "expired",
- "disputing",
- "refund",
- "refused"
- ]
+ "maxLength": 64
},
- "type": {
+ "end_time": {
+ "type": "string"
+ },
+ "id": {
"type": "string",
- "enum": [
- "receive",
- "payment",
- "transfer",
- "community",
- "online"
- ]
+ "example": "0"
+ },
+ "merchant_order_no": {
+ "type": "string",
+ "maxLength": 64
+ },
+ "order_name": {
+ "type": "string",
+ "maxLength": 64
+ },
+ "page": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "page_size": {
+ "type": "integer",
+ "maximum": 100,
+ "minimum": 1
+ },
+ "payee_username": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "payer_username": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "start_time": {
+ "type": "string"
+ },
+ "statuses": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "types": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "order.refundOrderRequest": {
+ "type": "object",
+ "properties": {
+ "remark": {
+ "type": "string",
+ "maxLength": 100
}
}
},
@@ -1386,7 +2280,13 @@
"type": "number"
},
"merchant_order_no": {
- "type": "string"
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1
+ },
+ "notify_url": {
+ "type": "string",
+ "maxLength": 100
},
"order_name": {
"type": "string",
@@ -1398,6 +2298,38 @@
"remark": {
"type": "string",
"maxLength": 100
+ },
+ "return_url": {
+ "type": "string",
+ "maxLength": 100
+ }
+ }
+ },
+ "payment.MerchantDistributeRequest": {
+ "type": "object",
+ "required": [
+ "amount",
+ "user_id",
+ "username"
+ ],
+ "properties": {
+ "amount": {
+ "type": "number"
+ },
+ "out_trade_no": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1
+ },
+ "remark": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "user_id": {
+ "type": "integer"
+ },
+ "username": {
+ "type": "string"
}
}
},
@@ -1522,7 +2454,8 @@
"maxLength": 6
},
"recipient_id": {
- "type": "integer"
+ "type": "string",
+ "example": "0"
},
"recipient_username": {
"type": "string"
@@ -1533,6 +2466,88 @@
}
}
},
+ "redenvelope.ClaimRequest": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "0"
+ }
+ }
+ },
+ "redenvelope.CreateRequest": {
+ "type": "object",
+ "required": [
+ "pay_key",
+ "total_amount",
+ "total_count",
+ "type"
+ ],
+ "properties": {
+ "cover_upload_id": {
+ "type": "string",
+ "example": "0"
+ },
+ "greeting": {
+ "type": "string",
+ "maxLength": 100
+ },
+ "heterotypic_upload_id": {
+ "type": "string",
+ "example": "0"
+ },
+ "pay_key": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "total_amount": {
+ "type": "number"
+ },
+ "total_count": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "type": {
+ "enum": [
+ "fixed",
+ "random"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/model.RedEnvelopeType"
+ }
+ ]
+ }
+ }
+ },
+ "redenvelope.ListRequest": {
+ "type": "object",
+ "required": [
+ "page",
+ "page_size"
+ ],
+ "properties": {
+ "page": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "page_size": {
+ "type": "integer",
+ "maximum": 100,
+ "minimum": 1
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "sent",
+ "received"
+ ]
+ }
+ }
+ },
"system_config.CreateSystemConfigRequest": {
"type": "object",
"required": [
@@ -1570,6 +2585,26 @@
}
}
},
+ "task.DispatchTaskRequest": {
+ "type": "object",
+ "required": [
+ "task_type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string"
+ },
+ "start_time": {
+ "type": "string"
+ },
+ "task_type": {
+ "type": "string"
+ },
+ "user_id": {
+ "type": "integer"
+ }
+ }
+ },
"user.UpdatePayKeyRequest": {
"type": "object",
"required": [
@@ -1582,9 +2617,18 @@
}
}
},
+ "user.updateUserStatusRequest": {
+ "type": "object",
+ "properties": {
+ "is_active": {
+ "type": "boolean"
+ }
+ }
+ },
"user_pay_config.CreateUserPayConfigRequest": {
"type": "object",
"required": [
+ "distribute_rate",
"fee_rate",
"score_rate"
],
@@ -1592,6 +2636,9 @@
"daily_limit": {
"type": "integer"
},
+ "distribute_rate": {
+ "type": "number"
+ },
"fee_rate": {
"type": "number"
},
@@ -1602,8 +2649,7 @@
"type": "integer"
},
"min_score": {
- "type": "integer",
- "minimum": 0
+ "type": "integer"
},
"score_rate": {
"type": "number"
@@ -1613,6 +2659,7 @@
"user_pay_config.UpdateUserPayConfigRequest": {
"type": "object",
"required": [
+ "distribute_rate",
"fee_rate",
"score_rate"
],
@@ -1620,6 +2667,9 @@
"daily_limit": {
"type": "integer"
},
+ "distribute_rate": {
+ "type": "number"
+ },
"fee_rate": {
"type": "number"
},
@@ -1627,8 +2677,7 @@
"type": "integer"
},
"min_score": {
- "type": "integer",
- "minimum": 0
+ "type": "integer"
},
"score_rate": {
"type": "number"
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index dd7284bf..f42a3d17 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -13,9 +13,14 @@ definitions:
notify_url:
maxLength: 100
type: string
+ public_key:
+ maxLength: 100
+ type: string
redirect_uri:
maxLength: 100
type: string
+ test_mode:
+ type: boolean
required:
- app_homepage_url
- app_name
@@ -35,21 +40,45 @@ definitions:
notify_url:
maxLength: 100
type: string
+ public_key:
+ maxLength: 100
+ type: string
redirect_uri:
maxLength: 100
type: string
+ test_mode:
+ type: boolean
+ type: object
+ dashboard.UserBalanceStatsResponse:
+ properties:
+ avg_amount:
+ type: number
+ max_amount:
+ type: number
+ median_amount:
+ type: number
+ min_amount:
+ type: number
+ std_dev:
+ type: number
+ total_amount:
+ type: number
+ total_count:
+ type: integer
type: object
dispute.CloseDisputeRequest:
properties:
dispute_id:
- type: integer
+ example: "0"
+ type: string
required:
- dispute_id
type: object
dispute.CreateDisputeRequest:
properties:
order_id:
- type: integer
+ example: "0"
+ type: string
reason:
maxLength: 100
type: string
@@ -60,7 +89,8 @@ definitions:
dispute.ListDisputesRequest:
properties:
dispute_id:
- type: integer
+ example: "0"
+ type: string
page:
minimum: 1
type: integer
@@ -78,7 +108,8 @@ definitions:
dispute.RefundReviewRequest:
properties:
dispute_id:
- type: integer
+ example: "0"
+ type: string
reason:
maxLength: 100
type: string
@@ -91,20 +122,6 @@ definitions:
- dispute_id
- status
type: object
- link.CreatePaymentLinkRequest:
- properties:
- amount:
- type: number
- product_name:
- maxLength: 30
- type: string
- remark:
- maxLength: 100
- type: string
- required:
- - amount
- - product_name
- type: object
link.PayByLinkRequest:
properties:
pay_key:
@@ -119,6 +136,34 @@ definitions:
- pay_key
- token
type: object
+ link.PaymentLinkRequest:
+ properties:
+ amount:
+ type: number
+ product_name:
+ maxLength: 30
+ type: string
+ remark:
+ maxLength: 100
+ type: string
+ total_limit:
+ minimum: 1
+ type: integer
+ user_limit:
+ minimum: 1
+ type: integer
+ required:
+ - amount
+ - product_name
+ type: object
+ model.OrderTransferStatus:
+ enum:
+ - pending
+ - completed
+ type: string
+ x-enum-varnames:
+ - OrderTransferStatusPending
+ - OrderTransferStatusCompleted
model.PayLevel:
enum:
- 0
@@ -132,6 +177,14 @@ definitions:
- PayLevelBasic
- PayLevelStandard
- PayLevelPremium
+ model.RedEnvelopeType:
+ enum:
+ - fixed
+ - random
+ type: string
+ x-enum-varnames:
+ - RedEnvelopeTypeFixed
+ - RedEnvelopeTypeRandom
oauth.CallbackRequest:
properties:
code:
@@ -145,6 +198,11 @@ definitions:
type: string
endTime:
type: string
+ id:
+ example: "0"
+ type: string
+ order_name:
+ type: string
page:
minimum: 1
type: integer
@@ -152,25 +210,71 @@ definitions:
maximum: 100
minimum: 1
type: integer
- startTime:
- type: string
- status:
+ payee_transfer_status:
+ allOf:
+ - $ref: '#/definitions/model.OrderTransferStatus'
enum:
- - success
- pending
- - failed
- - expired
- - disputing
- - refund
- - refused
+ - completed
+ payee_username:
type: string
- type:
- enum:
- - receive
- - payment
- - transfer
- - community
- - online
+ payer_username:
+ type: string
+ startTime:
+ type: string
+ statuses:
+ items:
+ type: string
+ type: array
+ types:
+ items:
+ type: string
+ type: array
+ type: object
+ order.listOrdersRequest:
+ properties:
+ client_id:
+ maxLength: 64
+ type: string
+ end_time:
+ type: string
+ id:
+ example: "0"
+ type: string
+ merchant_order_no:
+ maxLength: 64
+ type: string
+ order_name:
+ maxLength: 64
+ type: string
+ page:
+ minimum: 1
+ type: integer
+ page_size:
+ maximum: 100
+ minimum: 1
+ type: integer
+ payee_username:
+ maxLength: 255
+ type: string
+ payer_username:
+ maxLength: 255
+ type: string
+ start_time:
+ type: string
+ statuses:
+ items:
+ type: string
+ type: array
+ types:
+ items:
+ type: string
+ type: array
+ type: object
+ order.refundOrderRequest:
+ properties:
+ remark:
+ maxLength: 100
type: string
type: object
payment.CreateOrderRequest:
@@ -178,6 +282,11 @@ definitions:
amount:
type: number
merchant_order_no:
+ maxLength: 64
+ minLength: 1
+ type: string
+ notify_url:
+ maxLength: 100
type: string
order_name:
maxLength: 64
@@ -187,10 +296,33 @@ definitions:
remark:
maxLength: 100
type: string
+ return_url:
+ maxLength: 100
+ type: string
required:
- amount
- order_name
type: object
+ payment.MerchantDistributeRequest:
+ properties:
+ amount:
+ type: number
+ out_trade_no:
+ maxLength: 64
+ minLength: 1
+ type: string
+ remark:
+ maxLength: 100
+ type: string
+ user_id:
+ type: integer
+ username:
+ type: string
+ required:
+ - amount
+ - user_id
+ - username
+ type: object
payment.PayOrderRequest:
properties:
order_no:
@@ -273,7 +405,8 @@ definitions:
maxLength: 6
type: string
recipient_id:
- type: integer
+ example: "0"
+ type: string
recipient_username:
type: string
remark:
@@ -285,6 +418,63 @@ definitions:
- recipient_id
- recipient_username
type: object
+ redenvelope.ClaimRequest:
+ properties:
+ id:
+ example: "0"
+ type: string
+ required:
+ - id
+ type: object
+ redenvelope.CreateRequest:
+ properties:
+ cover_upload_id:
+ example: "0"
+ type: string
+ greeting:
+ maxLength: 100
+ type: string
+ heterotypic_upload_id:
+ example: "0"
+ type: string
+ pay_key:
+ maxLength: 10
+ type: string
+ total_amount:
+ type: number
+ total_count:
+ minimum: 1
+ type: integer
+ type:
+ allOf:
+ - $ref: '#/definitions/model.RedEnvelopeType'
+ enum:
+ - fixed
+ - random
+ required:
+ - pay_key
+ - total_amount
+ - total_count
+ - type
+ type: object
+ redenvelope.ListRequest:
+ properties:
+ page:
+ minimum: 1
+ type: integer
+ page_size:
+ maximum: 100
+ minimum: 1
+ type: integer
+ type:
+ enum:
+ - sent
+ - received
+ type: string
+ required:
+ - page
+ - page_size
+ type: object
system_config.CreateSystemConfigRequest:
properties:
description:
@@ -311,6 +501,19 @@ definitions:
required:
- value
type: object
+ task.DispatchTaskRequest:
+ properties:
+ end_time:
+ type: string
+ start_time:
+ type: string
+ task_type:
+ type: string
+ user_id:
+ type: integer
+ required:
+ - task_type
+ type: object
user.UpdatePayKeyRequest:
properties:
pay_key:
@@ -319,10 +522,17 @@ definitions:
required:
- pay_key
type: object
+ user.updateUserStatusRequest:
+ properties:
+ is_active:
+ type: boolean
+ type: object
user_pay_config.CreateUserPayConfigRequest:
properties:
daily_limit:
type: integer
+ distribute_rate:
+ type: number
fee_rate:
type: number
level:
@@ -330,11 +540,11 @@ definitions:
max_score:
type: integer
min_score:
- minimum: 0
type: integer
score_rate:
type: number
required:
+ - distribute_rate
- fee_rate
- score_rate
type: object
@@ -342,16 +552,18 @@ definitions:
properties:
daily_limit:
type: integer
+ distribute_rate:
+ type: number
fee_rate:
type: number
max_score:
type: integer
min_score:
- minimum: 0
type: integer
score_rate:
type: number
required:
+ - distribute_rate
- fee_rate
- score_rate
type: object
@@ -365,7 +577,7 @@ definitions:
info:
contact: {}
title: LINUX DO Credit
- version: 0.1.0
+ version: 1.0.0
paths:
/api.php:
get:
@@ -380,16 +592,15 @@ paths:
required: true
type: string
- in: query
+ maxLength: 64
+ minLength: 1
name: out_trade_no
+ required: true
type: string
- in: query
name: pid
required: true
type: string
- - in: query
- name: trade_no
- required: true
- type: integer
produces:
- application/json
responses:
@@ -418,6 +629,50 @@ paths:
$ref: '#/definitions/payment.RefundMerchantOrderResponse'
tags:
- payment
+ /api/v1/admin/orders:
+ post:
+ consumes:
+ - application/json
+ parameters:
+ - description: request body
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/order.listOrdersRequest'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - admin
+ /api/v1/admin/orders/{id}/refund:
+ post:
+ consumes:
+ - application/json
+ parameters:
+ - description: 订单ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ - description: request body
+ in: body
+ name: request
+ schema:
+ $ref: '#/definitions/order.refundOrderRequest'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - admin
/api/v1/admin/system-configs:
get:
produces:
@@ -505,6 +760,37 @@ paths:
$ref: '#/definitions/util.ResponseAny'
tags:
- admin
+ /api/v1/admin/tasks/dispatch:
+ post:
+ consumes:
+ - application/json
+ parameters:
+ - description: request body
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/task.DispatchTaskRequest'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - admin
+ /api/v1/admin/tasks/types:
+ get:
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - admin
/api/v1/admin/user-pay-configs:
get:
produces:
@@ -592,10 +878,24 @@ paths:
$ref: '#/definitions/util.ResponseAny'
tags:
- admin
- /api/v1/config/public:
+ /api/v1/admin/users:
get:
- consumes:
- - application/json
+ parameters:
+ - in: query
+ minimum: 1
+ name: page
+ type: integer
+ - in: query
+ maximum: 100
+ minimum: 1
+ name: page_size
+ type: integer
+ - in: query
+ name: user_id
+ type: integer
+ - in: query
+ name: username
+ type: string
produces:
- application/json
responses:
@@ -604,18 +904,178 @@ paths:
schema:
$ref: '#/definitions/util.ResponseAny'
tags:
- - config
- /api/v1/health:
- get:
- produces:
- - application/json
- responses:
- "200":
+ - admin
+ /api/v1/admin/users/{id}/status:
+ put:
+ parameters:
+ - description: 用户ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ - description: 状态
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/user.updateUserStatusRequest'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - admin
+ /api/v1/config/public:
+ get:
+ consumes:
+ - application/json
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - config
+ /api/v1/dashboard/stats/daily:
+ get:
+ consumes:
+ - application/json
+ parameters:
+ - description: 查询天数,最大7天
+ in: query
+ name: days
+ required: true
+ type: integer
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ summary: 获取每日收支统计
+ tags:
+ - dashboard
+ /api/v1/dashboard/stats/top-customers:
+ get:
+ consumes:
+ - application/json
+ parameters:
+ - description: 查询天数,最大7天
+ in: query
+ name: days
+ required: true
+ type: integer
+ - description: 返回数量,最大10
+ in: query
+ name: limit
+ required: true
+ type: integer
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ summary: 获取Top客户
+ tags:
+ - dashboard
+ /api/v1/dashboard/stats/user-balance:
+ get:
+ consumes:
+ - application/json
+ description: 统计所有用户的AvailableBalance字段
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ allOf:
+ - $ref: '#/definitions/util.ResponseAny'
+ - properties:
+ data:
+ $ref: '#/definitions/dashboard.UserBalanceStatsResponse'
+ type: object
+ summary: 获取用户余额统计
+ tags:
+ - dashboard
+ /api/v1/health:
+ get:
+ produces:
+ - application/json
+ responses:
+ "200":
description: OK
schema:
$ref: '#/definitions/util.ResponseAny'
tags:
- health
+ /api/v1/leaderboard:
+ get:
+ consumes:
+ - application/json
+ parameters:
+ - description: 页码
+ in: query
+ name: page
+ required: true
+ type: integer
+ - description: 每页数量
+ in: query
+ name: page_size
+ required: true
+ type: integer
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ summary: 获取排行榜列表
+ tags:
+ - leaderboard
+ /api/v1/leaderboard/me:
+ get:
+ consumes:
+ - application/json
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ summary: 获取当前用户排名
+ tags:
+ - leaderboard
+ /api/v1/leaderboard/users/{id}:
+ get:
+ consumes:
+ - application/json
+ parameters:
+ - description: 用户ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ summary: 获取指定用户排名
+ tags:
+ - leaderboard
/api/v1/merchant/api-keys:
get:
produces:
@@ -739,7 +1199,7 @@ paths:
name: request
required: true
schema:
- $ref: '#/definitions/link.CreatePaymentLinkRequest'
+ $ref: '#/definitions/link.PaymentLinkRequest'
produces:
- application/json
responses:
@@ -773,6 +1233,37 @@ paths:
$ref: '#/definitions/util.ResponseAny'
tags:
- merchant
+ put:
+ consumes:
+ - application/json
+ parameters:
+ - description: API Key ID
+ format: int64
+ in: path
+ name: id
+ required: true
+ type: integer
+ - description: Payment Link ID
+ format: int64
+ in: path
+ name: linkId
+ required: true
+ type: integer
+ - description: 更新支付链接请求
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/link.PaymentLinkRequest'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - merchant
/api/v1/merchant/payment:
post:
consumes:
@@ -1037,6 +1528,139 @@ paths:
$ref: '#/definitions/util.ResponseAny'
tags:
- payment
+ /api/v1/ready:
+ get:
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - health
+ /api/v1/redenvelope/{id}:
+ get:
+ parameters:
+ - description: 红包ID
+ in: path
+ name: id
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - redenvelope
+ /api/v1/redenvelope/claim:
+ post:
+ consumes:
+ - application/json
+ parameters:
+ - description: 领取红包请求
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/redenvelope.ClaimRequest'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - redenvelope
+ /api/v1/redenvelope/covers:
+ get:
+ parameters:
+ - description: 封面类型 (cover/heterotypic)
+ in: query
+ name: type
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - redenvelope
+ /api/v1/redenvelope/create:
+ post:
+ consumes:
+ - application/json
+ parameters:
+ - description: 创建红包请求
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/redenvelope.CreateRequest'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - redenvelope
+ /api/v1/redenvelope/list:
+ post:
+ consumes:
+ - application/json
+ parameters:
+ - description: 列表请求
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/redenvelope.ListRequest'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - redenvelope
+ /api/v1/upload/redenvelope/cover:
+ post:
+ consumes:
+ - multipart/form-data
+ parameters:
+ - description: 图片文件
+ in: formData
+ name: file
+ required: true
+ type: file
+ - description: 封面类型 (cover/heterotypic)
+ in: formData
+ name: type
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - upload
/api/v1/user/pay-key:
put:
consumes:
@@ -1057,7 +1681,66 @@ paths:
$ref: '#/definitions/util.ResponseAny'
tags:
- user
+ /f/{id}:
+ get:
+ parameters:
+ - description: Upload ID
+ in: path
+ name: id
+ required: true
+ type: string
+ produces:
+ - application/octet-stream
+ responses:
+ "200":
+ description: OK
+ tags:
+ - upload
+ /pay/distribute:
+ post:
+ consumes:
+ - application/json
+ parameters:
+ - description: Basic Auth (base64(client_id:client_secret))
+ in: header
+ name: Authorization
+ required: true
+ type: string
+ - description: 分发请求
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/payment.MerchantDistributeRequest'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - payment
/pay/submit.php:
+ get:
+ consumes:
+ - application/x-www-form-urlencoded
+ parameters:
+ - description: request body
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/payment.CreateOrderRequest'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/util.ResponseAny'
+ tags:
+ - payment
post:
consumes:
- application/x-www-form-urlencoded
diff --git a/frontend/.env.example b/frontend/.env.example
index 81dd197b..a855cd4f 100644
--- a/frontend/.env.example
+++ b/frontend/.env.example
@@ -1,3 +1,11 @@
-LINUX_DO_PAY_BACKEND_URL=http://localhost:8010
-LINUX_DO_PAY_FRONTEND_URL=http://localhost:3010
+# 前端 URL
+LINUX_DO_CREDIT_FRONTEND_URL=http://localhost:3000
+
+# 后端 URL
+LINUX_DO_CREDIT_BACKEND_URL=http://localhost:8000
+
+# Session Cookie
+LINUX_DO_CREDIT_SESSION_COOKIE_NAME=linux_do_credit_session_id
+
+# 环境
NODE_ENV=production
\ No newline at end of file
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
new file mode 100644
index 00000000..a411c7b6
--- /dev/null
+++ b/frontend/Dockerfile
@@ -0,0 +1,52 @@
+# ---- base stage ----
+FROM node:22-alpine AS base
+
+ENV PNPM_HOME="/pnpm"
+ENV PATH="$PNPM_HOME:$PATH"
+
+RUN corepack enable && corepack prepare pnpm@10.10.0 --activate
+
+# ---- build stage ----
+FROM base AS builder
+
+ENV NODE_ENV=production
+ENV NEXT_PUBLIC_LINUX_DO_CREDIT_BACKEND_URL=https://build-placeholder.invalid
+ENV LINUX_DO_CREDIT_SESSION_COOKIE_NAME=__LINUX_DO_CREDIT_SESSION_COOKIE_NAME__
+ENV LINUX_DO_CREDIT_RATE_LIMIT_ENABLED=__LINUX_DO_CREDIT_RATE_LIMIT_ENABLED__
+ENV LINUX_DO_CREDIT_BACKEND_URL=https://build-placeholder-2.invalid
+
+ARG VERSION=""
+ARG BUILD_DATE=""
+
+WORKDIR /app
+
+COPY package.json pnpm-lock.yaml ./
+
+RUN pnpm install --frozen-lockfile
+
+COPY . .
+
+RUN if [ -n "$VERSION" ] || [ -n "$BUILD_DATE" ]; then \
+ VERSION="$VERSION" BUILD_DATE="$BUILD_DATE" node -e "const fs = require('fs'); const pkg = require('./package.json'); const version = process.env.VERSION; const buildDate = process.env.BUILD_DATE; if (version) pkg.version = version; if (buildDate) pkg.buildDate = buildDate; fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\\n')"; \
+fi
+
+RUN pnpm build
+
+RUN grep -rl \
+ -e "https://build-placeholder.invalid" \
+ -e "https://build-placeholder-2.invalid" \
+ -e "__LINUX_DO_CREDIT_SESSION_COOKIE_NAME__" \
+ -e "__LINUX_DO_CREDIT_RATE_LIMIT_ENABLED__" \
+ /app/.next > /app/.replace.files
+
+# ---- runner stage ----
+FROM base AS runner
+
+WORKDIR /app
+
+COPY --from=builder /app .
+
+EXPOSE 3000
+
+ENTRYPOINT ["./entrypoint.sh"]
+CMD ["pnpm", "start"]
diff --git a/frontend/README.md b/frontend/README.md
index e215bc4c..412a6b4b 100644
--- a/frontend/README.md
+++ b/frontend/README.md
@@ -1,36 +1,50 @@
-This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+# Linux Do Credit Frontend
-## Getting Started
+Modern frontend application for the Linux Do Credit system.
+
+[中文](./README_zh.md) | English
-First, run the development server:
+## Tech Stack
-```bash
-npm run dev
-# or
-yarn dev
-# or
-pnpm dev
-# or
-bun dev
-```
+- **Framework**: [Next.js 16](https://nextjs.org/)
+- **Styling**: [Tailwind CSS 4](https://tailwindcss.com/)
+- **UI Components**: [Radix UI](https://www.radix-ui.com/)
+- **Icons**: [Lucide React](https://lucide.dev/)
+- **Package Manager**: [pnpm](https://pnpm.io/)
+
+## Getting Started
-Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+### Prerequisites
-You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+- Node.js (Latest LTS recommended)
+- pnpm
-This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+### Installation
-## Learn More
+1. Install dependencies:
+ ```bash
+ pnpm install
+ ```
-To learn more about Next.js, take a look at the following resources:
+2. Run the development server:
+ ```bash
+ pnpm dev
+ ```
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+ Open [http://localhost:3000](http://localhost:3000) (or the port shown in your terminal) with your browser to see the result.
-You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+## Project Structure
-## Deploy on Vercel
+- `app/`: Next.js App Router pages and layouts
+- `components/`: Reusable UI components
+ - `ui/`: Base UI components (buttons, inputs, etc.)
+ - `common/`: Shared business components
+- `lib/`: Utility functions and service definitions
+- `public/`: Static assets
-The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+## Scripts
-Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
+- `pnpm dev`: Start development server with Turbopack
+- `pnpm build`: Build the application for production
+- `pnpm start`: Start production server
+- `pnpm lint`: Run ESLint
diff --git a/frontend/README_zh.md b/frontend/README_zh.md
new file mode 100644
index 00000000..33b0b12c
--- /dev/null
+++ b/frontend/README_zh.md
@@ -0,0 +1,50 @@
+# Linux Do Credit Frontend
+
+Linux Do Credit 系统的现代化前端应用。
+
+[English](./README.md) | 中文
+
+## 技术栈
+
+- **框架**: [Next.js 16](https://nextjs.org/)
+- **样式**: [Tailwind CSS 4](https://tailwindcss.com/)
+- **UI 组件**: [Radix UI](https://www.radix-ui.com/)
+- **图标**: [Lucide React](https://lucide.dev/)
+- **包管理器**: [pnpm](https://pnpm.io/)
+
+## 快速开始
+
+### 前置要求
+
+- Node.js (建议使用最新的 LTS 版本)
+- pnpm
+
+### 安装
+
+1. 安装依赖:
+ ```bash
+ pnpm install
+ ```
+
+2. 运行开发服务器:
+ ```bash
+ pnpm dev
+ ```
+
+ 在浏览器中打开 [http://localhost:3000](http://localhost:3000) (或终端中显示的端口) 查看结果。
+
+## 项目结构
+
+- `app/`: Next.js App Router 页面和布局
+- `components/`: 可复用 UI 组件
+ - `ui/`: 基础 UI 组件 (按钮, 输入框等)
+ - `common/`: 共享业务组件
+- `lib/`: 工具函数和服务定义
+- `public/`: 静态资源
+
+## 脚本
+
+- `pnpm dev`: 启动开发服务器 (使用 Turbopack)
+- `pnpm build`: 构建生产版本
+- `pnpm start`: 启动生产服务器
+- `pnpm lint`: 运行 ESLint
diff --git a/frontend/app/(auth)/privacy-policy/page.tsx b/frontend/app/(auth)/privacy-policy/page.tsx
deleted file mode 100644
index 52d50d73..00000000
--- a/frontend/app/(auth)/privacy-policy/page.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { LegalPageLayout } from "@/components/auth/legal-page-layout";
-import { privacySections, LAST_UPDATED } from "@/components/auth/login-policies";
-
-export default function PrivacyPolicyPage() {
- return (
-
- 感谢您使用 LINUX DO Credit。我们深知个人信息对您的重要性,并会尽全力保护您的个人信息安全可靠。我们致力于维持您对我们的信任,恪守以下原则,保护您的个人信息:权责一致原则、目的明确原则、选择同意原则、最少够用原则、确保安全原则、主体参与原则、公开透明原则等。
-
- }
- />
- );
-}
diff --git a/frontend/app/(auth)/terms-of-service/page.tsx b/frontend/app/(auth)/terms-of-service/page.tsx
deleted file mode 100644
index 20763008..00000000
--- a/frontend/app/(auth)/terms-of-service/page.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { LegalPageLayout } from "@/components/auth/legal-page-layout";
-import { termsSections, LAST_UPDATED } from "@/components/auth/login-policies";
-
-export default function TermsOfServicePage() {
- return (
-
- 欢迎使用 LINUX DO Credit。请仔细阅读以下条款,它们规定了您对我们服务的访问和使用。通过使用我们的服务,即表示您同意受这些条款的约束。如果您不同意这些条款,请立即停止使用此平台。
-
- }
- />
- );
-}
diff --git a/frontend/app/(docs)/docs/api/page.tsx b/frontend/app/(docs)/docs/api/page.tsx
new file mode 100644
index 00000000..8ba38086
--- /dev/null
+++ b/frontend/app/(docs)/docs/api/page.tsx
@@ -0,0 +1,18 @@
+
+import { LegalPageLayout } from "@/components/common/docs/legal-page-layout";
+import { apiSections, DOCS_LAST_UPDATED } from "@/components/common/docs/api";
+
+export default function ApiDocPage() {
+ return (
+
+ LINUX DO Credit 提供简单、强大的 API 接口,支持多种编程语言和开发环境。通过标准化的 HTTP 接口,您可以轻松将积分服务集成到您的应用中。
+
+ }
+ />
+ );
+}
diff --git a/frontend/app/(docs)/docs/how-to-use/page.tsx b/frontend/app/(docs)/docs/how-to-use/page.tsx
new file mode 100644
index 00000000..0724d257
--- /dev/null
+++ b/frontend/app/(docs)/docs/how-to-use/page.tsx
@@ -0,0 +1,19 @@
+
+import { LegalPageLayout } from "@/components/common/docs/legal-page-layout";
+import { howToUseSections } from "@/components/common/docs/how-to-use";
+import { DOCS_LAST_UPDATED } from "@/components/common/docs/api";
+
+export default function HowToUsePage() {
+ return (
+
+ 欢迎使用 LINUX DO Credit。本文档将引导您快速了解平台的核心功能、角色定义及使用流程,帮助您更好地使用我们的服务。
+
+ }
+ />
+ );
+}
diff --git a/frontend/app/(docs)/docs/privacy-policy/page.tsx b/frontend/app/(docs)/docs/privacy-policy/page.tsx
new file mode 100644
index 00000000..50902494
--- /dev/null
+++ b/frontend/app/(docs)/docs/privacy-policy/page.tsx
@@ -0,0 +1,20 @@
+import { LegalPageLayout } from "@/components/common/docs/legal-page-layout"
+import { privacySections } from "@/components/common/docs/privacy"
+import { TERMS_LAST_UPDATED } from "@/components/common/docs/terms"
+
+export default function PrivacyPolicyPage() {
+ return (
+
+ 我们非常重视您的隐私保护。本政策将向您透明地展示我们如何收集、使用、存储您的个人信息,
+
+ 以及您享有的相关权利。
+
+ }
+ />
+ )
+}
diff --git a/frontend/app/(docs)/docs/terms-of-service/page.tsx b/frontend/app/(docs)/docs/terms-of-service/page.tsx
new file mode 100644
index 00000000..8725147d
--- /dev/null
+++ b/frontend/app/(docs)/docs/terms-of-service/page.tsx
@@ -0,0 +1,19 @@
+import { LegalPageLayout } from "@/components/common/docs/legal-page-layout"
+import { termsSections, TERMS_LAST_UPDATED } from "@/components/common/docs/terms"
+
+export default function TermsOfServicePage() {
+ return (
+
+ 欢迎使用 LINUX DO Credit。本协议详述了您在使用本平台服务时的权利与义务。
+
+ 为了保障您的合法权益,请您仔细阅读以下条款。
+
+ }
+ />
+ )
+}
diff --git a/frontend/app/(main)/admin/credit/page.tsx b/frontend/app/(main)/admin/credit/page.tsx
new file mode 100644
index 00000000..20b4075d
--- /dev/null
+++ b/frontend/app/(main)/admin/credit/page.tsx
@@ -0,0 +1,29 @@
+"use client"
+
+import { useEffect } from "react"
+import { UserPayConfigs } from "@/components/common/admin/credit"
+import { useUser } from "@/contexts/user-context"
+import { AdminProvider, useAdmin } from "@/contexts/admin-context"
+
+/* 用户积分配置页面 */
+export default function UserPayConfigPage() {
+ return (
+
+
+
+ )
+}
+
+/* 用户积分配置页面内容 */
+function UserPayConfigPageContent() {
+ const { user } = useUser()
+ const { refetchUserPayConfigs } = useAdmin()
+
+ useEffect(() => {
+ if (user?.is_admin) {
+ refetchUserPayConfigs()
+ }
+ }, [user?.is_admin, refetchUserPayConfigs])
+
+ return
+}
diff --git a/frontend/app/(main)/admin/layout.tsx b/frontend/app/(main)/admin/layout.tsx
new file mode 100644
index 00000000..2cc9a5f4
--- /dev/null
+++ b/frontend/app/(main)/admin/layout.tsx
@@ -0,0 +1,35 @@
+"use client"
+
+import { AdminUsersProvider } from "@/contexts/admin-users-context"
+import { useUser } from "@/contexts/user-context"
+import { LoadingPage } from "@/components/layout/loading"
+import { ErrorPage } from "@/components/layout/error"
+
+export default function AdminLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ const { user, loading } = useUser()
+
+ /* 等待用户信息加载完成 */
+ if (loading) {
+ return
+ }
+
+ /* 权限检查:只有管理员才能访问 */
+ if (!user?.is_admin) {
+ return (
+
+ )
+ }
+
+ return (
+
+ {children}
+
+ )
+}
diff --git a/frontend/app/(main)/admin/orders/page.tsx b/frontend/app/(main)/admin/orders/page.tsx
new file mode 100644
index 00000000..c5ef16a4
--- /dev/null
+++ b/frontend/app/(main)/admin/orders/page.tsx
@@ -0,0 +1,7 @@
+"use client"
+
+import { OrdersManager } from "@/components/common/admin/orders"
+
+export default function OrdersPage() {
+ return
+}
diff --git a/frontend/app/(main)/admin/system/page.tsx b/frontend/app/(main)/admin/system/page.tsx
index 9b65ebfc..93c1690e 100644
--- a/frontend/app/(main)/admin/system/page.tsx
+++ b/frontend/app/(main)/admin/system/page.tsx
@@ -1,14 +1,10 @@
"use client"
import { useEffect } from "react"
-import { SystemConfigs } from "@/components/common/admin/system-configs"
-import { ErrorPage } from "@/components/layout/error"
-import { LoadingPage } from "@/components/layout/loading"
-
+import { SystemConfigs } from "@/components/common/admin/system"
import { useUser } from "@/contexts/user-context"
import { AdminProvider, useAdmin } from "@/contexts/admin-context"
-
/* 系统配置页面 */
export default function SystemConfigPage() {
return (
@@ -20,7 +16,7 @@ export default function SystemConfigPage() {
/* 系统配置页面内容 */
function SystemConfigPageContent() {
- const { user, loading } = useUser()
+ const { user } = useUser()
const { refetchSystemConfigs } = useAdmin()
useEffect(() => {
@@ -29,21 +25,6 @@ function SystemConfigPageContent() {
}
}, [user?.is_admin, refetchSystemConfigs])
- /* 等待用户信息加载完成 */
- if (loading) {
- return
- }
-
- /* 权限检查:只有管理员才能访问 */
- if (!user?.is_admin) {
- return (
-
- )
- }
-
return
}
diff --git a/frontend/app/(main)/admin/tasks/page.tsx b/frontend/app/(main)/admin/tasks/page.tsx
new file mode 100644
index 00000000..39e329a5
--- /dev/null
+++ b/frontend/app/(main)/admin/tasks/page.tsx
@@ -0,0 +1,8 @@
+"use client"
+
+import { TaskManager } from "@/components/common/admin/tasks"
+
+/* 任务管理页面 */
+export default function TasksPage() {
+ return
+}
diff --git a/frontend/app/(main)/admin/user_pay/page.tsx b/frontend/app/(main)/admin/user_pay/page.tsx
deleted file mode 100644
index 38a4eb32..00000000
--- a/frontend/app/(main)/admin/user_pay/page.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-"use client"
-
-import { useEffect } from "react"
-import { UserPayConfigs } from "@/components/common/admin/user-pay-configs"
-import { ErrorPage } from "@/components/layout/error"
-import { LoadingPage } from "@/components/layout/loading"
-
-import { useUser } from "@/contexts/user-context"
-import { AdminProvider, useAdmin } from "@/contexts/admin-context"
-
-
-/* 用户支付配置页面 */
-export default function UserPayConfigPage() {
- return (
-
-
-
- )
-}
-
-/* 用户支付配置页面内容 */
-function UserPayConfigPageContent() {
- const { user, loading } = useUser()
- const { refetchUserPayConfigs } = useAdmin()
-
- useEffect(() => {
- if (user?.is_admin) {
- refetchUserPayConfigs()
- }
- }, [user?.is_admin, refetchUserPayConfigs])
-
- /* 等待用户信息加载完成 */
- if (loading) {
- return
- }
-
- /* 权限检查:只有管理员才能访问 */
- if (!user?.is_admin) {
- return (
-
- )
- }
-
- return
-}
diff --git a/frontend/app/(main)/admin/users/page.tsx b/frontend/app/(main)/admin/users/page.tsx
new file mode 100644
index 00000000..6e20d868
--- /dev/null
+++ b/frontend/app/(main)/admin/users/page.tsx
@@ -0,0 +1,8 @@
+"use client"
+
+import { UsersManager } from "@/components/common/admin/users"
+
+/* 用户管理页面 */
+export default function UsersPage() {
+ return
+}
diff --git a/frontend/app/(main)/docs/api/page.tsx b/frontend/app/(main)/docs/api/page.tsx
deleted file mode 100644
index 4c20b145..00000000
--- a/frontend/app/(main)/docs/api/page.tsx
+++ /dev/null
@@ -1,172 +0,0 @@
-
-import { MarkdownRenderer } from "@/components/common/docs/markdown-renderer";
-import { TableOfContents } from "@/components/common/docs/toc";
-
-const API_DOC = `
-## 1. 官方服务接口
-> 官方服务接口暂未上限,敬请期待
-
----
-
-
-## 2. 易支付兼容接口
-> 兼容易支付、CodePay、VPay 等支付协议
-
-### 2.1 概览
-- 协议:EasyPay / CodePay / VPay 兼容协议
-- 服务类型:仅支持 \`type=epay\`
-- 网关基址:\`https://pay.linux.do/epay\`
-- 订单有效期:取系统配置 \`merchant_order_expire_minutes\`(平台端设置)
-
-### 2.2 常见错误
-- \`不支持的请求类型\`:\`type\` 仅允许 \`epay\`
-- \`签名验证失败\`:参与签名字段与请求体需一致,密钥直接拼接
-- \`金额必须大于0\` / \`积分小数位数不能超过2位\`
-- \`订单已过期\`:超出系统配置有效期
-- \`订单不存在或已完成\`:订单号错误、已退回或已完成
-- \`余额不足\`:余额退回时用户积分不足
-
-### 2.3 对接流程
-1) 控制台创建 API Key,记录 \`pid\`、\`key\`,配置回调地址
-2) 按“签名算法”生成 \`sign\`,调用 \`/pay/submit.php\` 创建积分流转服务并跳转认证界面
-3) 可通过 \`/api.php\` 轮询结果,或等待异步回调
-4) 退回服务时,携带同一 \`trade_no\` 和原积分数量,调用积分退回接口
-5) 回调验签通过后返回 \`success\` 完成闭环
-
-### 2.4 鉴权与签名
-#### 2.4.1 API Key
-- \`pid\`:Client ID
-- \`key\`:Client Secret(妥善保管)
-- \`notify_url\`:回调地址, 使用创建应用时设置的 \`notify_url\`;请求体中的 notify_url 仅参与签名,不会覆盖创建应用时设置的 notify_url。
-
-#### 2.4.2 签名算法
-1) 取所有非空字段(排除 \`sign\`、\`sign_type\` 字段)
-2) 将上述字段按 ASCII 升序,依次拼成 \`k1=v1&k2=v2\`
-3) 在末尾追加应用密钥:\`k1=v1&k2=v2${ "{secret}" }\`
-4) 整体进行 MD5,取小写十六进制作为 \`sign\`
-
-示例:
-\`\`\`bash
-payload="money=10&name=Test&out_trade_no=M20250101&pid=001&type=epay"
-sign=$(echo -n "\${payload}\${SECRET}" | md5) # 输出小写
-\`\`\`
-
-### 2.5 积分流转服务
-- 方法:POST \`/pay/submit.php\`
-- 编码:\`application/x-www-form-urlencoded\`
-- 成功:验签通过后,平台自动创建积分流转服务,并跳转到认证界面(Location=\`https://credit.linux.do/paying?order_no=...\`)
-- 失败:返回 JSON \`{"error_msg":"...", "data":null}\`
-
-| 参数 | 必填 | 说明 |
-| :-- | :-- | :-- |
-| \`pid\` | 是 | Client ID |
-| \`type\` | 是 | 固定 \`epay\` |
-| \`out_trade_no\` | 否 | 业务单号,建议全局唯一 |
-| \`name\` | 是 | 标题,最多 64 字符 |
-| \`money\` | 是 | 积分数量,最多 2 位小数 |
-| \`notify_url\` | 否 | 仅参与签名,不会覆盖创建应用时设置的 notify_url |
-| \`return_url\` | 否 | 仅参与签名,不会覆盖创建应用时设置的 return_url |
-| \`device\` | 否 | 终端标识,可选 |
-| \`sign\` | 是 | 按“签名算法”生成 |
-| \`sign_type\` | 否 | 固定 \`MD5\` |
-
-请求示例:
-\`\`\`bash
-curl -X POST https://credit.linux.do/epay/pay/submit.php \\
- -H "Content-Type: application/x-www-form-urlencoded" \\
- -d "pid=001" \\
- -d "type=epay" \\
- -d "out_trade_no=M20250101" \\
- -d "name=Test" \\
- -d "money=10" \\
- -d "sign=\${SIGN}" \\
- -d "sign_type=MD5"
-\`\`\`
-
-### 2.6 订单查询
-- 方法:GET \`/api.php\`
-- 认证:\`pid\` + \`key\`
-- 说明:\`trade_no\` 必填;\`out_trade_no\` 可选;\`act\` 可传 \`order\`,后端不强校验。
-
-| 参数 | 必填 | 说明 |
-| :-- | :-- | :-- |
-| \`act\` | 否 | 可选字段,建议 \`order\` |
-| \`pid\` | 是 | Client ID |
-| \`key\` | 是 | Client Secret |
-| \`trade_no\` | 是 | 编号 |
-| \`out_trade_no\` | 否 | 业务单号 |
-
-成功响应:
-\`\`\`json
-{
- "code": 1,
- "msg": "查询订单号成功!",
- "trade_no": "M20250101",
- "out_trade_no": "M20250101",
- "type": "epay",
- "pid": "001",
- "addtime": "2025-01-01 12:00:00",
- "endtime": "2025-01-01 12:01:30",
- "name": "Test",
- "money": "10",
- "status": 1
-}
-\`\`\`
-
-补充:\`status\` 1=成功,0=失败/处理中;不存在会返回 HTTP 404 且 \`{"code":-1,"msg":"服务不存在或已完成"}\`。
-
-### 2.7 订单退款
-- 方法:POST \`/api.php\`
-- 编码:\`application/json\` 或 \`application/x-www-form-urlencoded\`
-- 限制:仅支持对已成功的积分流转服务进行积分的全额退回
-
-| 参数 | 必填 | 说明 |
-| :-- | :-- | :-- |
-| \`pid\` | 是 | Client ID |
-| \`key\` | 是 | Client Secret |
-| \`trade_no\` | 是 | 编号 |
-| \`money\` | 是 | 必须等于原积分流转服务的积分数量 |
-| \`out_trade_no\` | 否 | 业务单号(兼容) |
-
-响应:
-\`\`\`json
-{ "code": 1, "msg": "退款成功" }
-\`\`\`
-常见失败:服务不存在/未认证、金额不合法(<=0 或小数超过 2 位)。
-
-### 2.8 异步通知(认证成功)
-- 触发:认证成功后;失败自动重试,最多 5 次(单次 30s 超时)
-- 目标:创建应用时设置的 notify_url
-- 方式:HTTP GET
-
-| 参数 | 说明 |
-| :-- | :-- |
-| \`pid\` | Client ID |
-| \`trade_no\` | 编号 |
-| \`out_trade_no\` | 业务单号 |
-| \`type\` | 固定 \`epay\` |
-| \`name\` | 标题 |
-| \`money\` | 积分数量,最多 2 位小数 |
-| \`trade_status\` | 固定 \`TRADE_SUCCESS\` |
-| \`sign_type\` | \`MD5\` |
-| \`sign\` | 按“签名算法”生成 |
-
-应用需返回 HTTP 200 且响应体为 \`success\`(大小写不敏感),否则视为失败并继续重试。
-`;
-
-export default function ApiDocPage() {
- return (
-
- );
-}
diff --git a/frontend/app/(main)/docs/how-to-use/page.tsx b/frontend/app/(main)/docs/how-to-use/page.tsx
deleted file mode 100644
index 9b1d06ff..00000000
--- a/frontend/app/(main)/docs/how-to-use/page.tsx
+++ /dev/null
@@ -1,168 +0,0 @@
-"use client"
-
-import { MarkdownRenderer } from "@/components/common/docs/markdown-renderer"
-import { TableOfContents } from "@/components/common/docs/toc"
-
-const CONTENT = `
-> 为社区开发者与用户提供完整的平台使用说明
-
-## 1. 快速开始
-- 身份认证:基于 LINUX DO Connect (OAuth)
-- 认证方式:账户积分消耗认证
-- 手续费:动态费率,由服务方承担
-- 争议处理:支持服务方与消费方的双方争议处理
-
-## 2. 角色说明
-- **服务方**:最终积分流转的转入方
-- **消费方**:最终积分流转的转出方
-- **认证平台**:LINUX DO Credit 系统本身
-
-## 3. 接入积分服务
-### 3.1 使用 API 接口
-
-1. 创建应用
-
- - 前往 [集市中心](/merchant)
- - 点击顶部右侧 **创建应用** 按钮
- - 填写必要信息:应用名称、应用主页、回调地址、通知地址
-
-2. 获取 API 凭证
- - 在集市中心顶部右侧选择器中选择您的应用
- - 在 **API 配置** 面板中获取:
- - \`Client ID\`:客户端ID,用于标识您的身份
- - \`Client Secret\`:客户端密钥,用于签名验证(**请妥善保管,切勿泄露**)
-
-3. 使用 API 接口
- - 使用 API 接口创建积分流转服务
- - 参考文档:[API 接口文档](/docs/api)
-
-### 3.2 使用在线服务
-- 适用场景:无代码开发基础,或只用于简单的积分服务。
-- 操作步骤:
- 1. 前往 [集市中心](/merchant) 创建应用,获取 API 凭证
- 2. 选择应用,点击 **在线收款** 功能
- 3. 创建在线积分服务
- 4. 获取唯一积分服务链接
- 5. 发送给您所服务的客户使用
-
-### 3.3 快速集成 New API
-- 适用场景:New API 站点,LINUX DO Credit 兼容 EasyPay 协议,公益站站长可直接集成。
-- 操作步骤:
- 1. 前往 [集市中心](/merchant),点击 **创建应用**,填写 New API 站点信息:
- | 字段 | 值 |
- | :-- | :-- |
- | 应用名称 | \`您的应用名称\` |
- | 应用主页 | \`https://{您的 New API 域名}\` |
- | 回调地址 | \`https://{您的 New API 域名}/console/log\` |
- | 通知地址 | \`https://{您的 New API 域名}/api/user/epay/notify\` |
-
- 2. 前往 New API 站点的系统设置,找到 **支付设置**。
-
- 3. 配置 LINUX DO Credit 平台参数:
- | 参数 | 值 |
- | :-- | :-- |
- | 支付地址 | \`http://credit.linux.do/epay/pay\` |
- | 易支付商户ID | 您的 \`Client ID\` |
- | 易支付商户密钥 | 您的 \`Client Secret\` |
- | 回调地址 | \`https://{您的 New API 域名}\` |
-
- 4. 配置充值方式(JSON 格式):
- \`\`\`json
- [
- {"color":"rgba(var(--semi-blue-5), 1)","name":"支付宝","type":"alipay"},
- {"color":"rgba(var(--semi-green-5), 1)","name":"微信","type":"wxpay"},
- {"color":"black","name":"Linux Do Credit","type":"epay"}
- ]
- \`\`\`
-
-## 4. 使用 LINUX DO Credit 积分
-
-您可以在任意支持 LINUX DO Credit 的平台下使用积分。在其他平台点击使用 LINUX DO Credit 积分时,会自动跳转到 LINUX DO Credit 的积分流转服务页面,您只需要确认积分流转信息无误,并选择使用 LINUX DO Credit 进行账户认证,即可完成整个交易服务。
-
-
-## 5. 服务(手续)费
-### 5.1 规则说明
-
-为了更好的维持 LINUX DO Credit 平台的积分服务机制,保证社区积分的生态可持续发展,我们会按照规范进行不同程度的服务(手续)费用收取。
-
-- **承担方**:服务(手续)费默认**由服务方承担**
-- **消费方使用**:不会产生额外费用
-- **服务方实收**:订单金额 - 服务(手续)费
-
-计算公式:
-\`\`\`
-手续费 = 订单金额 × 当前费率
-商家实际到账 = 订单金额 - 手续费
-\`\`\`
-
-### 5.2 动态费率
-费率并非固定不变,会根据以下因素动态调整:
-- 服务方平台等级
-- 服务方平台积分
-- LINUX DO Credit 平台活动
-
-## 6. 争议处理
-
-为了保障服务方与消费方的合法权益,当积分服务出现纠纷时,可使用争议功能。
-
-- 作为服务方,您需要及时响应消费方的争议请求:
- 1. 在集市中心或通知中查看到 **待处理的争议**
- 2. 查看消费方理由,选择操作:
- - **同意**:认可消费方诉求,积分原路退回给消费方
- - **拒绝**:如果您认为已履约,请提交相关证据
-
-> **重要**:建议服务方与消费方优先通过沟通解决。长时间未处理的争议会由 LINUX DO Credit 平台介入仲裁,这可能会影响您的服务方信誉。
-
-## 7. 积分转移
-
-- 适用场景:向 LINUX DO Credit 平台内的其他用户进行积分转移。
-- 操作步骤
- 1. 进入 **活动** 页面,选择 **积分转移**
- 2. 填写接收方信息:
- - **接收方账户**:对方的用户名
- - **接收方 ID**:对方的用户ID,确保积分去向准确
- - **积分数量**:转移的积分数量
- 3. 验证安全密码后,积分将实时到账
-
-> **重要**:请勿滥用积分转移进行刷号、交易等违规行为,积分审计系统发现此类行为会立即封禁相关账户!
-
-## 8. 社区积分
-
-您的 LINUX DO Credit 平台基础积分主要由 **社区积分 (Community Balance)** 划转而来。
-
-- **基本获取方式**:通过在 LINUX DO 社区的活跃行为获得:
- - 发帖、回复、点赞等社区贡献
- - 详情可见 [LINUX DO 社区](https://linux.do/)
-
-- **划转规则**:
- - 划转时间:社区积分每日凌晨 **00:00** 自动划转至可用余额
- - 限制说明:划转前不可用于任何积分服务
- - 服务费用:目前划转 **服务费**
-
-## 9. 账户设置
-
-您可以在 **设置 (Settings)** 页面管理您的账户信息。
-
-## 功能列表
-- **个人资料**:查看当前的账户信息和会员等级
-- **安全设置**:修改认证密码
-- **通知设置**:暂未上线
-- **外观设置**:切换页面主题、界面外观
-`
-
-export default function HowToUsePage() {
- return (
-
- )
-}
diff --git a/frontend/app/(main)/layout.tsx b/frontend/app/(main)/layout.tsx
index 5af99ddb..d8361612 100644
--- a/frontend/app/(main)/layout.tsx
+++ b/frontend/app/(main)/layout.tsx
@@ -2,6 +2,7 @@
import { motion } from "motion/react"
import { usePathname } from "next/navigation"
+import { useState } from "react"
import { AppSidebar } from "@/components/layout/sidebar"
import { SiteHeader } from "@/components/layout/header"
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"
@@ -16,6 +17,7 @@ export default function MainLayout({
children: React.ReactNode
}) {
const pathname = usePathname()
+ const [isFullWidth, setIsFullWidth] = useState(false)
return (
@@ -30,9 +32,9 @@ export default function MainLayout({
>
-
+
-
+
+}
diff --git a/frontend/app/(main)/settings/notifications/page.tsx b/frontend/app/(main)/settings/notifications/page.tsx
new file mode 100644
index 00000000..f074147d
--- /dev/null
+++ b/frontend/app/(main)/settings/notifications/page.tsx
@@ -0,0 +1,5 @@
+import { NotificationsMain } from "@/components/common/settings/notifications"
+
+export default function NotificationsPage() {
+ return
+}
diff --git a/frontend/app/(redenvelope)/layout.tsx b/frontend/app/(redenvelope)/layout.tsx
new file mode 100644
index 00000000..9ead5ac7
--- /dev/null
+++ b/frontend/app/(redenvelope)/layout.tsx
@@ -0,0 +1,16 @@
+/**
+ * 红包页面布局
+ * 提供简洁的布局,不包含侧边栏和用户上下文
+ * 允许未登录用户访问红包详情
+ */
+export default function RedEnvelopeLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+ {children}
+
+ )
+}
\ No newline at end of file
diff --git a/frontend/app/(redenvelope)/redenvelope/[id]/page.tsx b/frontend/app/(redenvelope)/redenvelope/[id]/page.tsx
new file mode 100644
index 00000000..6ab5510a
--- /dev/null
+++ b/frontend/app/(redenvelope)/redenvelope/[id]/page.tsx
@@ -0,0 +1,32 @@
+import type { Metadata } from "next"
+import { headers } from "next/headers"
+import { RedEnvelopeClaimPage } from "@/components/common/redenvelope/red-envelope-claim"
+
+export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise
{
+ const { id } = await params
+ const requestHeaders = await headers()
+ const protocol = requestHeaders.get("x-forwarded-proto") ?? "https"
+ const host = requestHeaders.get("x-forwarded-host") ?? requestHeaders.get("host") ?? ""
+ const baseUrl = host ? `${protocol}://${host}` : ""
+ const title = "你收到一个LDC红包"
+ const description = "点击打开领取"
+ const url = baseUrl ? `${baseUrl}/redenvelope/${id}` : undefined
+ const image = baseUrl ? `${baseUrl}/red-envelope.svg` : "/red-envelope.svg"
+
+ return {
+ title,
+ description,
+ openGraph: {
+ title,
+ description,
+ url,
+ type: "website",
+ images: [{ url: image, width: 384, height: 512, alt: "红包" }],
+ }
+ }
+}
+
+export default async function RedEnvelopePage({ params }: { params: Promise<{ id: string }> }) {
+ const { id } = await params
+ return
+}
\ No newline at end of file
diff --git a/frontend/app/favicon.ico b/frontend/app/favicon.ico
index 718d6fea..df85a1c1 100644
Binary files a/frontend/app/favicon.ico and b/frontend/app/favicon.ico differ
diff --git a/frontend/app/globals.css b/frontend/app/globals.css
index badcf6e4..33d51423 100644
--- a/frontend/app/globals.css
+++ b/frontend/app/globals.css
@@ -133,7 +133,7 @@
}
@theme inline {
- /*
+ /*
* Aurora 动画配置
*/
--animate-aurora: aurora 120s linear infinite;
@@ -151,4 +151,46 @@
350% 50%;
}
}
+
+ /*
+ * 红包动画配置
+ */
+ --animate-redenvelope-shake: redenvelope-shake 0.5s ease-in-out;
+ --animate-redenvelope-glow: redenvelope-glow 2s ease-in-out infinite;
+ --animate-gold-particle: gold-particle 1s ease-out forwards;
+
+ @keyframes redenvelope-shake {
+ 0%, 100% { transform: rotate(0deg); }
+ 25% { transform: rotate(-5deg); }
+ 75% { transform: rotate(5deg); }
+ }
+
+ @keyframes redenvelope-glow {
+ 0%, 100% { box-shadow: 0 0 20px rgba(255, 215, 0, 0.3); }
+ 50% { box-shadow: 0 0 40px rgba(255, 215, 0, 0.6); }
+ }
+
+ @keyframes gold-particle {
+ 0% { transform: translateY(0) scale(1); opacity: 1; }
+ 100% { transform: translateY(-100px) scale(0); opacity: 0; }
+ }
+
+ /*
+ * 铃铛响铃动画配置
+ * 使用微妙的摆动效果,优雅且不过度
+ */
+ --animate-bell-ring: bell-ring 0.6s cubic-bezier(0.36, 0.07, 0.19, 0.97);
+
+ @keyframes bell-ring {
+ 0% { transform: rotate(0deg); }
+ 10% { transform: rotate(14deg); }
+ 20% { transform: rotate(-12deg); }
+ 30% { transform: rotate(10deg); }
+ 40% { transform: rotate(-8deg); }
+ 50% { transform: rotate(6deg); }
+ 60% { transform: rotate(-4deg); }
+ 70% { transform: rotate(2deg); }
+ 80% { transform: rotate(-1deg); }
+ 100% { transform: rotate(0deg); }
+ }
}
\ No newline at end of file
diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx
index 88a5e337..fb32b7be 100644
--- a/frontend/app/layout.tsx
+++ b/frontend/app/layout.tsx
@@ -3,6 +3,9 @@ import { Inter, Noto_Sans_SC, Geist_Mono } from 'next/font/google';
import { Toaster } from "@/components/ui/sonner";
import { ThemeProvider } from "@/components/layout/theme-provider";
import { CustomThemeProvider } from "@/lib/theme";
+import { BellRingProvider } from "@/contexts/bell-ring-context";
+import { NotificationSettingsProvider } from "@/contexts/notification-settings-context";
+import { RiskBlockDialog } from "@/components/common/risk/risk-block-dialog";
import "./globals.css";
const inter = Inter({
@@ -49,8 +52,13 @@ export default function RootLayout({
disableTransitionOnChange
>
- {children}
-
+
+
+ {children}
+
+
+
+