Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 9 additions & 33 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,38 +1,14 @@
FROM oven/bun:latest AS builder
FROM golang:latest

WORKDIR /build
COPY web/package.json .
COPY web/bun.lock .
RUN bun install
COPY ./web .
COPY ./VERSION .
RUN DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(cat VERSION) bun run build
WORKDIR /app

FROM golang:alpine AS builder2
ENV GO111MODULE=on CGO_ENABLED=0

ARG TARGETOS
ARG TARGETARCH
ENV GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH:-amd64}
ENV GOEXPERIMENT=greenteagc

WORKDIR /build

ADD go.mod go.sum ./
RUN go mod download
ENV GOOS=windows
ENV GOARCH=amd64
ENV CGO_ENABLED=0

# 复制源码(包含我们伪造的 web/dist)
COPY . .
COPY --from=builder /build/dist ./web/dist
RUN go build -ldflags "-s -w -X 'github.com/QuantumNous/new-api/common.Version=$(cat VERSION)'" -o new-api

FROM debian:bookworm-slim

RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates tzdata libasan8 wget \
&& rm -rf /var/lib/apt/lists/* \
&& update-ca-certificates

COPY --from=builder2 /build/new-api /
EXPOSE 3000
WORKDIR /data
ENTRYPOINT ["/new-api"]
# 下载依赖并编译
RUN go mod download
RUN go build -ldflags "-s -w" -o new-api-galaxy.exe
Comment on lines +1 to +14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# First, explore the repo structure
echo "=== Repository structure ==="
ls -la
echo ""

# Look for CI workflows that might reference this Dockerfile
echo "=== CI Workflows ==="
find . -type d -name '.github' -o -name '.gitlab-ci' -o -name '.circleci' | head -20
if [ -d ".github/workflows" ]; then
  echo "GitHub workflows found:"
  ls -la .github/workflows/
  echo ""
fi

# Look for deployment or documentation files
echo "=== Documentation files ==="
fd -e md -e rst | grep -i -E "(deploy|readme|dockerfile|build|docker)" | head -20
echo ""

# Check git history for recent Dockerfile changes
echo "=== Recent Dockerfile history ==="
git log --oneline -n 10 -- Dockerfile 2>/dev/null || echo "Git history not available"
echo ""

# Check for any other Dockerfile variations
echo "=== All Dockerfile variations ==="
fd -type f -name 'Dockerfile*'

Repository: QuantumNous/new-api

Length of output: 3423


🏁 Script executed:

#!/bin/bash

# Check the CI workflows to see if they use this Dockerfile
echo "=== docker-image-alpha.yml ==="
cat .github/workflows/docker-image-alpha.yml
echo ""

echo "=== docker-image-arm64.yml ==="
cat .github/workflows/docker-image-arm64.yml
echo ""

# Check git diff for Dockerfile changes
echo "=== Git diff for Dockerfile (last 5 commits) ==="
git diff HEAD~1 -- Dockerfile 2>/dev/null || echo "Cannot get diff"
echo ""

# Check the git log with patches
echo "=== Git log for Dockerfile ==="
git log --oneline --all -- Dockerfile 2>/dev/null | head -20

# Look at the previous version of Dockerfile
echo ""
echo "=== Previous Dockerfile (HEAD~1) ==="
git show HEAD~1:Dockerfile 2>/dev/null || echo "Cannot retrieve previous version"

Repository: QuantumNous/new-api

Length of output: 10206


🏁 Script executed:

#!/bin/bash

# Read the current Dockerfile
echo "=== Current Dockerfile content ==="
cat -n Dockerfile
echo ""

# Check git history more carefully - find when Dockerfile last changed meaningfully
echo "=== Last few actual Dockerfile changes ==="
git log -p --follow -- Dockerfile 2>/dev/null | head -200
echo ""

# Look at electron directory since it might be related to Windows builds
echo "=== Electron directory structure ==="
ls -la electron/
echo ""

# Check if there's a build-windows script or similar
echo "=== Windows-related files ==="
find . -type f -name "*windows*" -o -name "*exe*" 2>/dev/null | grep -v node_modules | grep -v .git

Repository: QuantumNous/new-api

Length of output: 1514


🏁 Script executed:

#!/bin/bash

# Check what deployment-guide.md says about Docker
echo "=== deployment-guide.md Docker section ==="
grep -A 20 -i "docker" docs/deployment-guide.md | head -40
echo ""

# Check docker-compose.yml to understand expected setup
echo "=== docker-compose.yml ==="
cat docker-compose.yml | head -50
echo ""

# Check if there's a makefile or build script for Windows
echo "=== makefile content ==="
cat makefile
echo ""

# Look at main.go to understand if this is desktop app or server
echo "=== main.go first 50 lines ==="
head -50 main.go

Repository: QuantumNous/new-api

Length of output: 4514


Critical: Dockerfile produces Windows binary, breaking Docker deployments and CI/CD.

This Dockerfile compiles a Windows executable (new-api-galaxy.exe) but the CI/CD workflows (docker-image-alpha.yml, docker-image-arm64.yml) are configured to build for Linux platforms (linux/amd64, linux/arm64) and push to Docker Hub. The docker-compose.yml depends on the Linux image calciumion/new-api:latest. This is a fundamental incompatibility that will break:

  • CI/CD pipelines that build and push to Docker registries
  • Docker Compose deployments using the published images
  • Any container-based deployment

Issues identified:

  1. GOOS=windows produces .exe binary incompatible with linux/amd64 and linux/arm64 targets
  2. No ENTRYPOINT/CMD - the image only compiles, doesn't define how to run
  3. "伪造的 web/dist" comment (fake web/dist) indicates this is temporary/test code
  4. golang:latest - unpinned tag reduces reproducibility

The application is an HTTP server (Gin framework, port 3000 per main.go), not a Windows desktop app. Restore the Linux-compatible Dockerfile or clarify if this is a separate Windows build artifact (not for Docker deployment).

🤖 Prompt for AI Agents
In `@Dockerfile` around lines 1 - 14, The Dockerfile is building a Windows binary
(GOOS=windows producing new-api-galaxy.exe) and lacks a runtime command and
reproducible base image; change GOOS/GOARCH/CGO_ENABLED to produce Linux
binaries matching CI targets (e.g. remove or set GOOS=linux and appropriate
GOARCH), build a non-.exe artifact (e.g. new-api-galaxy or new-api), add a
proper ENTRYPOINT or CMD to run the Gin HTTP server on port 3000, and pin the
base image (replace golang:latest with a specific tag) so CI/CD/docker-compose
images are compatible; update or remove the "伪造的 web/dist" copy step only if
it's temporary test data.

5 changes: 5 additions & 0 deletions controller/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ func AddToken(c *gin.Context) {
AllowIps: token.AllowIps,
Group: token.Group,
CrossGroupRetry: token.CrossGroupRetry,
Duration: token.Duration,
}
if token.Duration > 0 {
cleanToken.ExpiredTime = -1
}
Comment on lines +194 to 198

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Validate Duration to avoid invalid negative values.
Right now any negative duration will flow into the model; consider rejecting it at the API boundary for both create and update.

🔧 Suggested guard
 if len(token.Name) > 50 {
   c.JSON(http.StatusOK, gin.H{
     "success": false,
     "message": "令牌名称过长",
   })
   return
 }
+if token.Duration < 0 {
+  c.JSON(http.StatusOK, gin.H{
+    "success": false,
+    "message": "Duration 不能为负数",
+  })
+  return
+}
🤖 Prompt for AI Agents
In `@controller/token.go` around lines 194 - 198, Reject negative Duration values
at the API boundary by adding validation in the token handlers (e.g.,
CreateToken and UpdateToken) to check token.Duration >= 0 and return a 400 /
validation error when it's negative; do not propagate negative Duration into the
model (cleanToken.Duration) and ensure any logic that sets
cleanToken.ExpiredTime (referencing cleanToken and token.Duration) only runs for
valid, non-negative durations.

err = cleanToken.Insert()
if err != nil {
Expand Down Expand Up @@ -286,6 +290,7 @@ func UpdateToken(c *gin.Context) {
cleanToken.AllowIps = token.AllowIps
cleanToken.Group = token.Group
cleanToken.CrossGroupRetry = token.CrossGroupRetry
cleanToken.Duration = token.Duration
}
err = cleanToken.Update()
if err != nil {
Expand Down
219 changes: 219 additions & 0 deletions docs/deployment-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
# New API 部署指南(避坑记录)

> 记录日期:2026-01-30
> 部署环境:Windows 11 本地开发 → Debian 12 服务器

## 部署方式

本项目采用**本地编译 + 上传可执行文件**的方式部署,而非 Docker 镜像。

### 为什么选择这种方式?

| 方式 | 优点 | 缺点 |
|------|------|------|
| Docker 官方镜像 | 一键部署,简单 | 无法使用自定义修改的代码 |
| **本地编译上传** | 可部署自定义版本 | 需要手动处理依赖 |

## 遇到的问题及解决方案

### 1. SSH 密钥加载失败

**错误信息:**
```
Load key "xxx/id_ed25519": error in libcrypto
```
Comment on lines +22 to +24

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add language identifiers to fenced code blocks.

Several code blocks are missing language specifiers, which triggers MD040 warnings and affects syntax highlighting.

📝 Suggested fixes for code block languages
 **错误信息:**
-```
+```text
 Load key "xxx/id_ed25519": error in libcrypto

```diff
 **错误信息:**
-```
+```text
 /www1/new-api/new-api: cannot execute binary file: Exec format error

```diff
 **错误信息:**
-```
+```text
 ReferenceError: Space is not defined

```diff
 **错误信息:**
-```
+```text
 scp: dest open "/www1/new-api/new-api": Failure

```diff
 ## 目录结构
 
-```
+```text
 /www1/new-api/
 ├── new-api          # 可执行文件

Also applies to: 41-43, 65-67, 93-95, 213-218

🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In `@docs/deployment-guide.md` around lines 22 - 24, The Markdown contains several
fenced code blocks missing language identifiers (triggering MD040); update each
``` block that contains examples like "Load key \"xxx/id_ed25519\": error in
libcrypto", "/www1/new-api/new-api: cannot execute binary file: Exec format
error", "ReferenceError: Space is not defined", "scp: dest open
\"/www1/new-api/new-api\": Failure", and the directory listing to include
appropriate language tags (e.g., ```text or ```bash) so they render with syntax
highlighting and satisfy MD040; search for the bare ``` fences in the document
and add the language specifier to each affected block.


**原因:** Windows 系统的 SSH 密钥文件包含 CRLF 行尾符(`\r\n`),Linux 只认 LF(`\n`)。

**解决方案:**
```bash
# 去除 Windows 行尾符
cat /path/to/id_ed25519 | tr -d '\r' > /tmp/fixed_key
chmod 600 /tmp/fixed_key
ssh -i /tmp/fixed_key user@server
```

---

### 2. 编译成了 Windows 可执行文件

**错误信息:**
```
/www1/new-api/new-api: cannot execute binary file: Exec format error
```

**原因:** 在 Windows 上直接运行 `go build`,默认编译成 Windows PE 格式。

**解决方案:** 必须设置交叉编译环境变量:
```bash
# 正确的 Linux 编译命令
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -o new-api-linux .
```

**验证方法:**
```bash
file new-api-linux
# 应显示:ELF 64-bit LSB executable, x86-64
# 而不是:PE32+ executable (console) x86-64, for MS Windows
```

---

### 3. 前端组件缺少导入导致黑屏

**错误信息:**
```
ReferenceError: Space is not defined
```

**原因:** 某些组件使用了 `<Space>` 但忘记从 `@douyinfe/semi-ui` 导入。

**受影响文件:**
- `web/src/pages/Setting/Payment/SettingsPaymentGatewayCreem.jsx`
- `web/src/pages/Setting/Ratio/UpstreamRatioSync.jsx`

**解决方案:** 在导入语句中添加 `Space`:
```jsx
import {
Button,
// ... 其他组件
Space, // 添加这行
} from '@douyinfe/semi-ui';
```

**预防措施:**
- 使用 ESLint 的 `no-undef` 规则
- 提交前运行 `bun run build` 检查是否有错误

---

### 4. 上传文件时服务正在运行

**错误信息:**
```
scp: dest open "/www1/new-api/new-api": Failure
```

**原因:** Linux 下正在运行的可执行文件无法被覆盖。

**解决方案:** 先停止服务再上传:
```bash
ssh user@server "systemctl stop new-api"
scp new-api-linux user@server:/www1/new-api/new-api
ssh user@server "chmod +x /www1/new-api/new-api && systemctl start new-api"
```

---

## 完整部署流程

### 前置条件

- 本地安装 Go 1.20+
- 本地安装 Bun(用于前端构建)
- 服务器安装 Docker(用于 PostgreSQL 和 Redis)

### 步骤

```bash
# 1. 构建前端
cd web
bun install
bun run build

# 2. 编译后端(Linux 版本)
cd ..
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -o new-api-linux .

# 3. 上传到服务器
ssh user@server "systemctl stop new-api 2>/dev/null; mkdir -p /www1/new-api/logs"
scp new-api-linux user@server:/www1/new-api/new-api
ssh user@server "chmod +x /www1/new-api/new-api"

# 4. 首次部署:启动数据库
ssh user@server << 'EOF'
docker run -d \
--name new-api-postgres \
--restart always \
-e POSTGRES_USER=newapi \
-e POSTGRES_PASSWORD=YOUR_SECURE_PASSWORD \
-e POSTGRES_DB=newapi \
-p 127.0.0.1:5433:5432 \
-v /www1/new-api/pg_data:/var/lib/postgresql/data \
postgres:15

docker run -d \
--name new-api-redis \
--restart always \
-p 127.0.0.1:6380:6379 \
redis:latest
EOF

# 5. 创建启动脚本
ssh user@server << 'EOF'
cat > /www1/new-api/start.sh << 'SCRIPT'
#!/bin/bash
cd /www1/new-api
export SQL_DSN="postgresql://newapi:YOUR_SECURE_PASSWORD@127.0.0.1:5433/newapi"
export REDIS_CONN_STRING="redis://127.0.0.1:6380"
export TZ=Asia/Shanghai
exec ./new-api --port 9527 --log-dir /www1/new-api/logs
SCRIPT
chmod +x /www1/new-api/start.sh
EOF

# 6. 创建 systemd 服务
ssh user@server << 'EOF'
cat > /etc/systemd/system/new-api.service << 'SERVICE'
[Unit]
Description=New API Service
After=network.target docker.service
Requires=docker.service

[Service]
Type=simple
User=root
WorkingDirectory=/www1/new-api
ExecStart=/www1/new-api/start.sh
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
SERVICE
systemctl daemon-reload
systemctl enable new-api
systemctl start new-api
EOF
```

---

## 常用运维命令

```bash
# 查看服务状态
systemctl status new-api

# 查看日志
tail -f /www1/new-api/logs/*.log
journalctl -u new-api -f

# 重启服务
systemctl restart new-api

# 数据库备份
docker exec new-api-postgres pg_dump -U newapi newapi > backup_$(date +%Y%m%d).sql
```

---

## 目录结构

```
/www1/new-api/
├── new-api # 可执行文件
├── start.sh # 启动脚本
├── logs/ # 日志目录
└── pg_data/ # PostgreSQL 数据目录
```
18 changes: 17 additions & 1 deletion model/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type Token struct {
UsedQuota int `json:"used_quota" gorm:"default:0"` // used quota
Group string `json:"group" gorm:"default:''"`
CrossGroupRetry bool `json:"cross_group_retry"` // 跨分组重试,仅auto分组有效
ActivatedTime int64 `json:"activated_time" gorm:"bigint;default:0"`
Duration int64 `json:"duration" gorm:"bigint;default:0"`
DeletedAt gorm.DeletedAt `gorm:"index"`
}

Expand Down Expand Up @@ -87,6 +89,20 @@ func ValidateUserToken(key string) (token *Token, err error) {
if token.Status != common.TokenStatusEnabled {
return token, errors.New("该令牌状态不可用")
}
if token.ExpiredTime == -1 && token.Duration > 0 && token.ActivatedTime == 0 {
token.ActivatedTime = common.GetTimestamp()
token.ExpiredTime = token.ActivatedTime + token.Duration
// Update DB
DB.Model(token).Select("activated_time", "expired_time").Updates(token)
// Update Redis if enabled
if common.RedisEnabled {
gopool.Go(func() {
if err := cacheSetToken(*token); err != nil {
common.SysLog("failed to update token cache: " + err.Error())
}
})
}
}
Comment on lines +92 to +105

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing error handling for DB update during token activation.

The database update on line 96 does not check the returned error. If the update fails, the token's in-memory state will be inconsistent with the database, and the function will continue as if activation succeeded.

Additionally, there's a potential race condition: if two concurrent requests validate the same sleeping token simultaneously, both may attempt activation before either persists. Consider using a transaction with row-level locking or an atomic conditional update (e.g., WHERE activated_time = 0).

Proposed fix for error handling and atomicity
 		if token.ExpiredTime == -1 && token.Duration > 0 && token.ActivatedTime == 0 {
-			token.ActivatedTime = common.GetTimestamp()
-			token.ExpiredTime = token.ActivatedTime + token.Duration
-			// Update DB
-			DB.Model(token).Select("activated_time", "expired_time").Updates(token)
+			now := common.GetTimestamp()
+			// Atomic conditional update to prevent race conditions
+			result := DB.Model(token).
+				Where("activated_time = ?", 0).
+				Select("activated_time", "expired_time").
+				Updates(map[string]interface{}{
+					"activated_time": now,
+					"expired_time":   now + token.Duration,
+				})
+			if result.Error != nil {
+				common.SysLog("failed to activate token: " + result.Error.Error())
+				return token, errors.New("令牌激活失败")
+			}
+			if result.RowsAffected > 0 {
+				token.ActivatedTime = now
+				token.ExpiredTime = now + token.Duration
+			} else {
+				// Another request already activated; reload token
+				token, err = GetTokenByKey(key, true)
+				if err != nil {
+					return nil, err
+				}
+			}
 			// Update Redis if enabled
🤖 Prompt for AI Agents
In `@model/token.go` around lines 92 - 105, The DB update after setting
token.ActivatedTime and token.ExpiredTime (see token.ExpiredTime,
token.Duration, token.ActivatedTime and
DB.Model(token).Select("activated_time","expired_time").Updates(token))
currently ignores errors and can lead to in-memory/db divergence and race
conditions; change this to perform an atomic/conditional update (e.g., within a
transaction or using a WHERE activated_time = 0 conditional update and checking
RowsAffected) and handle the returned error: if the update fails or affects 0
rows, revert the in-memory activation (reset ActivatedTime/ExpiredTime) and
avoid firing cacheSetToken in the gopool.Go block, otherwise proceed to call
cacheSetToken; ensure error is logged via common.SysLog when DB update fails.

if token.ExpiredTime != -1 && token.ExpiredTime < common.GetTimestamp() {
if !common.RedisEnabled {
token.Status = common.TokenStatusExpired
Expand Down Expand Up @@ -190,7 +206,7 @@ func (token *Token) Update() (err error) {
}
}()
err = DB.Model(token).Select("name", "status", "expired_time", "remain_quota", "unlimited_quota",
"model_limits_enabled", "model_limits", "allow_ips", "group", "cross_group_retry").Updates(token).Error
"model_limits_enabled", "model_limits", "allow_ips", "group", "cross_group_retry", "duration", "activated_time").Updates(token).Error
return err
}

Expand Down
1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@visactor/react-vchart": "~1.8.8",
"@visactor/vchart": "~1.8.8",
"@visactor/vchart-semi-theme": "~1.8.8",
"antd": "^6.2.2",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat web/package.json

Repository: QuantumNous/new-api

Length of output: 2745


🌐 Web query:

Ant Design 6.2.2 peer dependencies React 18 Vite compatibility

💡 Result:

  • Peer dependencies (antd 6.2.2): react >= 18.0.0 and react-dom >= 18.0.0. No other peer deps are required by antd itself. [1]
  • React 18: Fully supported (v6 raised the minimum supported React version to 18). [2]
  • Vite compatibility: antd 6.2.2 ships ESM (module: es/index.js) and marks *.css as side effects, which works cleanly with Vite’s dependency pre-bundling and tree-shaking. [1]
    • For styles, you can import the provided CSS entry (commonly antd/dist/reset.css; it exists in 6.2.2). [3]

Sources: [1] [2] [3]


🏁 Script executed:

# Search for existing style/CSS imports in the codebase
rg -i "antd|styles|css|import.*from.*antd" web/src --type js --type jsx --type ts --type tsx -A 2 -B 2 | head -50

Repository: QuantumNous/new-api

Length of output: 90


🏁 Script executed:

# Check if there's a main entry point or setup file
fd -e main.js -e main.jsx -e main.ts -e main.tsx -e app.js -e app.jsx -e app.ts -e app.tsx web/src

Repository: QuantumNous/new-api

Length of output: 396


🏁 Script executed:

# Find main entry point in web/src
fd . web/src --max-depth 1 -e js -e jsx -e ts -e tsx

Repository: QuantumNous/new-api

Length of output: 96


🏁 Script executed:

# Search for any existing antd or CSS imports
rg "import.*antd|import.*\.css|from.*antd" web/src --max-count 20

Repository: QuantumNous/new-api

Length of output: 437


🏁 Script executed:

# Check vite.config file
fd vite.config web

Repository: QuantumNous/new-api

Length of output: 81


🏁 Script executed:

cat -n web/src/index.jsx | head -30

Repository: QuantumNous/new-api

Length of output: 1475


🏁 Script executed:

cat -n web/src/App.jsx | head -50

Repository: QuantumNous/new-api

Length of output: 2610


🏁 Script executed:

cat -n web/vite.config.js

Repository: QuantumNous/new-api

Length of output: 3587


🏁 Script executed:

# Check if any antd components are actually imported/used
rg "from 'antd'|from \"antd\"|Button|Modal|Form|Input|Select" web/src --max-count 15

Repository: QuantumNous/new-api

Length of output: 50376


🏁 Script executed:

rg "from\s+['\"]antd['\"]" web/src

Repository: QuantumNous/new-api

Length of output: 45


🏁 Script executed:

# Check if antd is imported/used anywhere at all
rg "import.*from.*['\"]antd['\"]" web/src

Repository: QuantumNous/new-api

Length of output: 45


🏁 Script executed:

# Verify the full index.jsx to see all imports
wc -l web/src/index.jsx

Repository: QuantumNous/new-api

Length of output: 83


🏁 Script executed:

cat -n web/src/index.jsx | tail -20

Repository: QuantumNous/new-api

Length of output: 664


Add required Ant Design CSS import and clarify intent to use it.

Ant Design v6.2.2 is compatible with React 18.2.0 and Vite 5.2.0, but the integration is incomplete: no CSS is imported in the entry point, so any antd components will render unstyled. Additionally, antd is not imported anywhere in the codebase, yet the project already uses @douyinfe/semi-ui as its complete UI library.

Either add import 'antd/dist/reset.css'; to web/src/index.jsx if antd will be used, or remove the dependency if semi-ui is the intended choice. Using both libraries together will cause style conflicts, increased bundle size, and maintenance burden.

🤖 Prompt for AI Agents
In `@web/package.json` at line 13, The project lists "antd" in package.json but no
stylesheet import or usage is present; either add the Ant Design reset CSS
import or remove the dependency: if you intend to use antd, add the line import
'antd/dist/reset.css'; to the entry file (web/src/index.jsx) before rendering so
Ant components are styled; if you do not intend to use antd (keeping
`@douyinfe/semi-ui` only), remove "antd" from package.json and run your package
manager to update lockfiles to avoid unused dependency and style conflicts.

"axios": "1.12.0",
"clsx": "^2.1.1",
"country-flag-icons": "^1.5.19",
Expand Down
6 changes: 5 additions & 1 deletion web/src/components/common/modals/SecureVerificationModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ const SecureVerificationModal = ({
title={title || t('安全验证')}
visible={visible}
onCancel={onCancel}
footer={<Button onClick={onCancel}>{t('确定')}</Button>}
footer={
<div className='flex justify-end'>
<Button onClick={onCancel}>{t('确定')}</Button>
</div>
}
width={500}
style={{ maxWidth: '90vw' }}
>
Expand Down
6 changes: 3 additions & 3 deletions web/src/components/common/modals/TwoFactorAuthModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ For commercial licensing, please contact support@quantumnous.com

import React from 'react';
import { useTranslation } from 'react-i18next';
import { Modal, Button, Input, Typography } from '@douyinfe/semi-ui';
import { Modal, Button, Input, Typography, Space } from '@douyinfe/semi-ui';

/**
* 可复用的两步验证模态框组件
Expand Down Expand Up @@ -76,7 +76,7 @@ const TwoFactorAuthModal = ({
visible={visible}
onCancel={onCancel}
footer={
<>
<Space>
<Button onClick={onCancel}>{t('取消')}</Button>
<Button
type='primary'
Expand All @@ -86,7 +86,7 @@ const TwoFactorAuthModal = ({
>
{t('验证')}
</Button>
</>
</Space>
}
width={500}
style={{ maxWidth: '90vw' }}
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/layout/NoticeModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ const NoticeModal = ({
visible={visible}
onCancel={onClose}
footer={
<div className='flex justify-end'>
<div className='flex justify-end gap-2'>
<Button type='secondary' onClick={handleCloseTodayNotice}>
{t('今日关闭')}
</Button>
Expand Down
Loading