Merge branch 'dev' of github.com:engigu/baihu into dev
This commit is contained in:
@@ -6,7 +6,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'Dockerfile.base'
|
||||
- 'docker/Dockerfile.base'
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
@@ -17,9 +17,39 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
base_type: [debian, alpine, debian13]
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
include:
|
||||
- base_type: debian
|
||||
platform: linux/arm/v7
|
||||
dockerfile: docker/Dockerfile.base
|
||||
tag_suffix: ""
|
||||
- base_type: debian
|
||||
platform: linux/amd64
|
||||
dockerfile: docker/Dockerfile.base
|
||||
tag_suffix: ""
|
||||
- base_type: debian
|
||||
platform: linux/arm64
|
||||
dockerfile: docker/Dockerfile.base
|
||||
tag_suffix: ""
|
||||
- base_type: alpine
|
||||
platform: linux/amd64
|
||||
dockerfile: docker/Dockerfile.alpine.base
|
||||
tag_suffix: "-alpine"
|
||||
- base_type: alpine
|
||||
platform: linux/arm64
|
||||
dockerfile: docker/Dockerfile.alpine.base
|
||||
tag_suffix: "-alpine"
|
||||
- base_type: debian13
|
||||
platform: linux/amd64
|
||||
dockerfile: docker/Dockerfile.debian13.base
|
||||
tag_suffix: "-debian13"
|
||||
- base_type: debian13
|
||||
platform: linux/arm64
|
||||
dockerfile: docker/Dockerfile.debian13.base
|
||||
tag_suffix: "-debian13"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -33,7 +63,7 @@ jobs:
|
||||
id: platform
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "pair=${platform//\//-}" >> $GITHUB_OUTPUT
|
||||
echo "pair=${platform//\//-}-${{ matrix.base_type }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
@@ -55,14 +85,14 @@ jobs:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=raw,value=base
|
||||
type=raw,value=base${{ matrix.tag_suffix }}
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.base
|
||||
file: ${{ matrix.dockerfile }}
|
||||
platforms: ${{ matrix.platform }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
outputs: type=image,name=${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||
@@ -87,6 +117,16 @@ jobs:
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
strategy:
|
||||
matrix:
|
||||
base_type: [debian, alpine, debian13]
|
||||
include:
|
||||
- base_type: debian
|
||||
tag: base
|
||||
- base_type: alpine
|
||||
tag: base-alpine
|
||||
- base_type: debian13
|
||||
tag: base-debian13
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -100,7 +140,7 @@ jobs:
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
pattern: digests-*-${{ matrix.base_type }}
|
||||
merge-multiple: true
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
@@ -120,7 +160,7 @@ jobs:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=raw,value=base
|
||||
type=raw,value=${{ matrix.tag }}
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
@@ -130,4 +170,4 @@ jobs:
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:base
|
||||
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ matrix.tag }}
|
||||
|
||||
@@ -12,6 +12,19 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
base_type: [debian, alpine, debian13]
|
||||
include:
|
||||
- base_type: debian
|
||||
base_tag: base
|
||||
tag_suffix: ""
|
||||
- base_type: alpine
|
||||
base_tag: base-alpine
|
||||
tag_suffix: "-alpine"
|
||||
- base_type: debian13
|
||||
base_tag: base-debian13
|
||||
tag_suffix: "-debian13"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -38,10 +51,9 @@ jobs:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}-amd64
|
||||
type=raw,value=latest-amd64,enable={{is_default_branch}}
|
||||
type=ref,event=branch,suffix=-amd64
|
||||
type=sha,prefix={{branch}}-,suffix=-amd64
|
||||
type=raw,value=latest-amd64${{ matrix.tag_suffix }},enable={{is_default_branch}}
|
||||
type=ref,event=branch,suffix=-amd64${{ matrix.tag_suffix }}
|
||||
type=sha,prefix={{branch}}-,suffix=-amd64${{ matrix.tag_suffix }}
|
||||
|
||||
- name: Get build time
|
||||
id: build_time
|
||||
@@ -51,6 +63,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
@@ -58,11 +71,13 @@ jobs:
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
BUILD_TIME=${{ steps.build_time.outputs.time }}
|
||||
cache-from: type=gha,scope=linux-amd64
|
||||
cache-to: type=gha,scope=linux-amd64,mode=max
|
||||
BASE_TAG=${{ matrix.base_tag }}
|
||||
cache-from: type=gha,scope=linux-amd64-${{ matrix.base_type }}
|
||||
cache-to: type=gha,scope=linux-amd64-${{ matrix.base_type }},mode=max
|
||||
provenance: false
|
||||
|
||||
- name: Deploy to Demo server
|
||||
if: github.ref == 'refs/heads/main' && matrix.base_type == 'debian'
|
||||
uses: appleboy/ssh-action@v1.2.0
|
||||
with:
|
||||
host: ${{ secrets.DEPLOY_HOST }}
|
||||
@@ -71,10 +86,11 @@ jobs:
|
||||
port: ${{ secrets.DEPLOY_PORT }}
|
||||
script: |
|
||||
cd ${{ secrets.DEPLOY_PATH }}
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
docker-compose -f docker/docker-compose.yml pull
|
||||
docker-compose -f docker/docker-compose.yml up -d
|
||||
|
||||
- name: Deploy to X server
|
||||
if: github.ref == 'refs/heads/main' && matrix.base_type == 'debian'
|
||||
uses: appleboy/ssh-action@v1.2.0
|
||||
with:
|
||||
host: ${{ secrets.DEPLOY_HOST }}
|
||||
@@ -83,5 +99,5 @@ jobs:
|
||||
port: ${{ secrets.DEPLOY_PORT }}
|
||||
script: |
|
||||
cd ${{ secrets.DEPLOY_X_PATH }}
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
docker-compose -f docker/docker-compose.yml pull
|
||||
docker-compose -f docker/docker-compose.yml up -d
|
||||
@@ -12,6 +12,19 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
base_type: [debian, alpine, debian13]
|
||||
include:
|
||||
- base_type: debian
|
||||
base_tag: base
|
||||
tag_suffix: ""
|
||||
- base_type: alpine
|
||||
base_tag: base-alpine
|
||||
tag_suffix: "-alpine"
|
||||
- base_type: debian13
|
||||
base_tag: base-debian13
|
||||
tag_suffix: "-debian13"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -38,8 +51,9 @@ jobs:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}-amd64
|
||||
type=raw,value=latest-amd64,enable={{is_default_branch}}
|
||||
type=semver,pattern={{version}}-amd64${{ matrix.tag_suffix }}
|
||||
type=raw,value=latest-amd64${{ matrix.tag_suffix }},enable={{is_default_branch}}
|
||||
type=ref,event=branch,suffix=-amd64${{ matrix.tag_suffix }}
|
||||
|
||||
- name: Get build time
|
||||
id: build_time
|
||||
@@ -49,6 +63,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
@@ -56,6 +71,7 @@ jobs:
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
BUILD_TIME=${{ steps.build_time.outputs.time }}
|
||||
cache-from: type=gha,scope=linux-amd64
|
||||
cache-to: type=gha,scope=linux-amd64,mode=max
|
||||
BASE_TAG=${{ matrix.base_tag }}
|
||||
cache-from: type=gha,scope=linux-amd64-${{ matrix.base_type }}
|
||||
cache-to: type=gha,scope=linux-amd64-${{ matrix.base_type }},mode=max
|
||||
provenance: false
|
||||
|
||||
@@ -12,6 +12,19 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
base_type: [debian, alpine, debian13]
|
||||
include:
|
||||
- base_type: debian
|
||||
base_tag: base
|
||||
tag_suffix: ""
|
||||
- base_type: alpine
|
||||
base_tag: base-alpine
|
||||
tag_suffix: "-alpine"
|
||||
- base_type: debian13
|
||||
base_tag: base-debian13
|
||||
tag_suffix: "-debian13"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -41,8 +54,9 @@ jobs:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}-arm64
|
||||
type=raw,value=latest-arm64,enable={{is_default_branch}}
|
||||
type=semver,pattern={{version}}-arm64${{ matrix.tag_suffix }}
|
||||
type=raw,value=latest-arm64${{ matrix.tag_suffix }},enable={{is_default_branch}}
|
||||
type=ref,event=branch,suffix=-arm64${{ matrix.tag_suffix }}
|
||||
|
||||
- name: Get build time
|
||||
id: build_time
|
||||
@@ -52,6 +66,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
platforms: linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
@@ -59,6 +74,7 @@ jobs:
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
BUILD_TIME=${{ steps.build_time.outputs.time }}
|
||||
cache-from: type=gha,scope=linux-arm64
|
||||
cache-to: type=gha,scope=linux-arm64,mode=max
|
||||
BASE_TAG=${{ matrix.base_tag }}
|
||||
cache-from: type=gha,scope=linux-arm64-${{ matrix.base_type }}
|
||||
cache-to: type=gha,scope=linux-arm64-${{ matrix.base_type }},mode=max
|
||||
provenance: false
|
||||
|
||||
@@ -14,9 +14,39 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
base_type: [debian, alpine, debian13]
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
include:
|
||||
- base_type: debian
|
||||
platform: linux/arm/v7
|
||||
base_tag: base
|
||||
tag_suffix: ""
|
||||
- base_type: debian
|
||||
platform: linux/amd64
|
||||
base_tag: base
|
||||
tag_suffix: ""
|
||||
- base_type: debian
|
||||
platform: linux/arm64
|
||||
base_tag: base
|
||||
tag_suffix: ""
|
||||
- base_type: alpine
|
||||
platform: linux/amd64
|
||||
base_tag: base-alpine
|
||||
tag_suffix: "-alpine"
|
||||
- base_type: alpine
|
||||
platform: linux/arm64
|
||||
base_tag: base-alpine
|
||||
tag_suffix: "-alpine"
|
||||
- base_type: debian13
|
||||
platform: linux/amd64
|
||||
base_tag: base-debian13
|
||||
tag_suffix: "-debian13"
|
||||
- base_type: debian13
|
||||
platform: linux/arm64
|
||||
base_tag: base-debian13
|
||||
tag_suffix: "-debian13"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -30,7 +60,7 @@ jobs:
|
||||
id: platform
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "pair=${platform//\//-}" >> $GITHUB_OUTPUT
|
||||
echo "pair=${platform//\//-}-${{ matrix.base_type }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
@@ -61,10 +91,12 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
platforms: ${{ matrix.platform }}
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
BUILD_TIME=${{ steps.build_time.outputs.time }}
|
||||
BASE_TAG=${{ matrix.base_tag }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
outputs: type=image,name=${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||
cache-from: type=gha,scope=${{ steps.platform.outputs.pair }}
|
||||
@@ -88,6 +120,16 @@ jobs:
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
strategy:
|
||||
matrix:
|
||||
base_type: [debian, alpine, debian13]
|
||||
include:
|
||||
- base_type: debian
|
||||
tag_suffix: ""
|
||||
- base_type: alpine
|
||||
tag_suffix: "-alpine"
|
||||
- base_type: debian13
|
||||
tag_suffix: "-debian13"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -101,7 +143,7 @@ jobs:
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
pattern: digests-*-${{ matrix.base_type }}
|
||||
merge-multiple: true
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
@@ -121,8 +163,8 @@ jobs:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=raw,value=latest
|
||||
type=semver,pattern={{version}}${{ matrix.tag_suffix }}
|
||||
type=raw,value=latest${{ matrix.tag_suffix }}
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
@@ -132,9 +174,10 @@ jobs:
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
|
||||
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}${{ matrix.tag_suffix }}
|
||||
|
||||
- name: Create GitHub Release
|
||||
if: matrix.base_type == 'debian'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
|
||||
@@ -48,3 +48,4 @@ configs/config.local.json
|
||||
__pycache__/
|
||||
|
||||
# Misc
|
||||
.stfolder
|
||||
@@ -6,7 +6,7 @@ GOGET=go get
|
||||
GOMOD=go mod
|
||||
VERSION=$(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
|
||||
BUILD_TIME=$(shell date '+%Y/%m/%d %H:%M:%S')
|
||||
LDFLAGS=-ldflags="-s -w -X 'baihu/internal/constant.Version=$(VERSION)' -X 'baihu/internal/constant.BuildTime=$(BUILD_TIME)'"
|
||||
LDFLAGS=-ldflags="-s -w -X 'github.com/engigu/baihu-panel/internal/constant.Version=$(VERSION)' -X 'github.com/engigu/baihu-panel/internal/constant.BuildTime=$(BUILD_TIME)'"
|
||||
|
||||
# Default target
|
||||
all: build
|
||||
@@ -66,7 +66,7 @@ deps:
|
||||
|
||||
# Docker build
|
||||
docker-build:
|
||||
docker build -t $(BINARY) .
|
||||
docker build -t $(BINARY) -f docker/Dockerfile .
|
||||
|
||||
# Docker run
|
||||
docker-run:
|
||||
@@ -74,11 +74,11 @@ docker-run:
|
||||
|
||||
# Docker compose up
|
||||
docker-up:
|
||||
docker-compose up -d
|
||||
docker-compose -f docker/docker-compose.yml up -d
|
||||
|
||||
# Docker compose down
|
||||
docker-down:
|
||||
docker-compose down
|
||||
docker-compose -f docker/docker-compose.yml down
|
||||
|
||||
# Help
|
||||
help:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# 白虎面板
|
||||
|
||||
[](https://hits.sh/github.com/engigu/baihu-panel/)
|
||||
[](https://ghcr-badge.egpl.dev/engigu/baihu/tags)
|
||||

|
||||

|
||||

|
||||
@@ -10,6 +9,14 @@
|
||||
|
||||
演示站点(演示站点的服务器比较烂,见谅) [演示站点](https://baihu-demo-site.qwapi.eu.org/)
|
||||
|
||||
## 更新日志 ☕
|
||||
|
||||
### 最近更新
|
||||
|
||||
**2026.02.06** - 整理 Docker 目录结构,增加 Alpine 及 Debian 13 (Trixie) 镜像支持
|
||||
|
||||
[查看完整更新日志](./CHANGELOG.md)
|
||||
|
||||
## 项目来由
|
||||
|
||||
多少和青龙面板有点关系,我自己也是青龙面板的使用者,但是现在的青龙面板性能我觉得有点难以接受。以我自己的使用(`机器1C2G`)为例,一个`python`的`requests`脚本每隔`30s`执行一次,有时候cpu执行的时候能跳变到`50%`以上。可以看看下面gif图片(如果不动,点击图片查看)
|
||||
@@ -24,6 +31,8 @@
|
||||
|
||||

|
||||
|
||||
如果项目有用,请帮忙点个star。
|
||||
|
||||
## 特色
|
||||
|
||||
- **轻量级:** docker/compose部署,无需复杂配置,开箱即用
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
ARG BASE_TAG=base
|
||||
# ================================
|
||||
# Stage 1: Build frontend
|
||||
# ================================
|
||||
FROM node:20-alpine AS frontend-builder
|
||||
FROM --platform=$BUILDPLATFORM node:20-alpine AS frontend-builder
|
||||
|
||||
WORKDIR /app/web
|
||||
|
||||
@@ -59,7 +60,7 @@ COPY --from=frontend-builder /app/web/dist ./internal/static/dist
|
||||
RUN VERSION_VAL=$(cat /build-info/version.txt) && \
|
||||
BUILD_TIME_VAL=$(cat /build-info/build_time.txt) && \
|
||||
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
|
||||
go build -ldflags="-s -w -X baihu/internal/constant.Version=${VERSION_VAL} -X 'baihu/internal/constant.BuildTime=${BUILD_TIME_VAL}'" \
|
||||
go build -ldflags="-s -w -X github.com/engigu/baihu-panel/internal/constant.Version=${VERSION_VAL} -X 'github.com/engigu/baihu-panel/internal/constant.BuildTime=${BUILD_TIME_VAL}'" \
|
||||
-o baihu .
|
||||
|
||||
# ================================
|
||||
@@ -104,7 +105,8 @@ RUN VERSION_VAL=$(cat /build-info/version.txt) && \
|
||||
# ================================
|
||||
# Stage 4: Final image
|
||||
# ================================
|
||||
FROM ghcr.io/engigu/baihu:base
|
||||
ARG BASE_TAG
|
||||
FROM ghcr.io/engigu/baihu:${BASE_TAG}
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
ENV PATH="/app/envs/node/bin:/app/envs/python/bin:$PATH"
|
||||
@@ -130,7 +132,7 @@ COPY --from=frontend-builder /app/web/dist ./internal/static/dist
|
||||
|
||||
# Copy configs and entrypoint
|
||||
COPY --from=backend-builder /app/configs ./configs
|
||||
COPY docker-entrypoint.sh .
|
||||
COPY docker/docker-entrypoint.sh .
|
||||
|
||||
# Copy sync.py to /opt
|
||||
COPY custom/sync.py /opt/sync.py
|
||||
@@ -0,0 +1,24 @@
|
||||
FROM alpine:3.19
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
ENV PATH="/app/envs/node/bin:/app/envs/python/bin:$PATH"
|
||||
ENV NODE_PATH="/app/envs/node/lib/node_modules"
|
||||
|
||||
# 安装必要系统工具 + Node + Python
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \
|
||||
&& apk add --no-cache \
|
||||
tzdata \
|
||||
git \
|
||||
gcc \
|
||||
musl-dev \
|
||||
curl \
|
||||
wget \
|
||||
vim \
|
||||
nodejs \
|
||||
npm \
|
||||
python3 \
|
||||
py3-pip \
|
||||
htop \
|
||||
&& cp /usr/share/zoneinfo/${TZ} /etc/localtime \
|
||||
&& echo "${TZ}" > /etc/timezone \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
@@ -0,0 +1,15 @@
|
||||
FROM debian:trixie-slim
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
ENV PATH="/app/envs/node/bin:/app/envs/python/bin:$PATH"
|
||||
ENV NODE_PATH="/app/envs/node/lib/node_modules"
|
||||
|
||||
# 安装必要系统工具 + Node + Python
|
||||
RUN sed -i 's@deb.debian.org@mirrors.tuna.tsinghua.edu.cn@g' /etc/apt/sources.list.d/debian.sources \
|
||||
&& sed -i 's@security.debian.org@mirrors.tuna.tsinghua.edu.cn@g' /etc/apt/sources.list.d/debian.sources \
|
||||
&& echo "${TZ}" > /etc/timezone \
|
||||
&& ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
tzdata git gcc curl wget vim nodejs htop npm python3 python3-venv python3-pip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
@@ -1,4 +1,4 @@
|
||||
module baihu
|
||||
module github.com/engigu/baihu-panel
|
||||
|
||||
go 1.24.0
|
||||
|
||||
@@ -11,8 +11,10 @@ require (
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/shirou/gopsutil/v3 v3.24.5
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
golang.org/x/text v0.32.0
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
gorm.io/driver/mysql v1.6.0
|
||||
gorm.io/driver/postgres v1.6.0
|
||||
gorm.io/gorm v1.31.1
|
||||
@@ -51,7 +53,6 @@ require (
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
@@ -64,7 +65,6 @@ require (
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
|
||||
@@ -41,9 +41,10 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
@@ -100,6 +101,8 @@ github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/i
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -111,8 +114,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
@@ -144,8 +148,6 @@ golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/logger"
|
||||
"baihu/internal/router"
|
||||
"baihu/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/router"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
Vendored
+3
-3
@@ -3,9 +3,9 @@ package cache
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
// siteCache 站点设置内存缓存
|
||||
|
||||
@@ -18,9 +18,9 @@ type Sentence struct {
|
||||
}
|
||||
|
||||
var (
|
||||
lineCount int
|
||||
lineOffsets []int64
|
||||
sentenceOnce sync.Once
|
||||
lineCount int
|
||||
lineOffsets []int64
|
||||
sentenceOnce sync.Once
|
||||
)
|
||||
|
||||
// initSentences 初始化:统计行数和记录每行偏移
|
||||
@@ -44,13 +44,16 @@ func GetRandomSentence() string {
|
||||
}
|
||||
|
||||
targetLine := rand.Intn(lineCount)
|
||||
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewReader(sentenceData))
|
||||
currentLine := 0
|
||||
for scanner.Scan() {
|
||||
if currentLine == targetLine {
|
||||
var s Sentence
|
||||
if err := json.Unmarshal(scanner.Bytes(), &s); err == nil && s.Name != "" {
|
||||
if s.From != "" {
|
||||
return "\"" + s.Name + "\"—— " + s.From
|
||||
}
|
||||
return s.Name
|
||||
}
|
||||
break
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"baihu/internal/logger"
|
||||
"baihu/internal/models"
|
||||
"baihu/internal/services"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
@@ -3,10 +3,10 @@ package controllers
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/middleware"
|
||||
"baihu/internal/services"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/middleware"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"baihu/internal/services/tasks"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/services/tasks"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"baihu/internal/models"
|
||||
"baihu/internal/services"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -3,8 +3,8 @@ package controllers
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"baihu/internal/services"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -3,8 +3,8 @@ package controllers
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"baihu/internal/services/tasks"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/services/tasks"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -3,9 +3,9 @@ package controllers
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -3,8 +3,8 @@ package controllers
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"baihu/internal/services"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -5,12 +5,12 @@ import (
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"baihu/internal/services"
|
||||
"baihu/internal/services/tasks"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/services/tasks"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/services"
|
||||
"baihu/internal/services/tasks"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/services/tasks"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/creack/pty"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"baihu/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/driver/mysql"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"baihu/internal/logger"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
func Migrate() error {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"baihu/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
)
|
||||
|
||||
// LoginLog 登录日志
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
)
|
||||
|
||||
// SendStats 任务执行统计
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
)
|
||||
|
||||
// Setting 系统设置
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/controllers"
|
||||
"baihu/internal/services"
|
||||
"baihu/internal/services/tasks"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/controllers"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/services/tasks"
|
||||
)
|
||||
|
||||
var cronService *tasks.CronService
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"baihu/internal/controllers"
|
||||
"baihu/internal/middleware"
|
||||
"baihu/internal/services"
|
||||
"baihu/internal/static"
|
||||
"github.com/engigu/baihu-panel/internal/controllers"
|
||||
"github.com/engigu/baihu-panel/internal/middleware"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/static"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/logger"
|
||||
"baihu/internal/models"
|
||||
"baihu/internal/services/tasks"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/services/tasks"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/logger"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"encoding/json"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
type BackupService struct {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
@@ -67,7 +67,7 @@ func LoadConfig(path string) (*AppConfig, error) {
|
||||
Port: 3306,
|
||||
User: "root",
|
||||
Password: "",
|
||||
DBName: "baihu",
|
||||
DBName: "github.com/engigu/baihu-panel",
|
||||
Path: constant.DefaultDBPath,
|
||||
TablePrefix: "baihu_",
|
||||
},
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/logger"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
type DependencyService struct{}
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
type EnvService struct{}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"baihu/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
)
|
||||
|
||||
type InitService struct {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
type LoginLogService struct{}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
type ScriptService struct{}
|
||||
|
||||
@@ -3,8 +3,8 @@ package services
|
||||
import (
|
||||
"time"
|
||||
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
type SendStatsService struct{}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"baihu/internal/cache"
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/cache"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
type SettingsService struct{}
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/logger"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/logger"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/logger"
|
||||
"baihu/internal/models"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/logger"
|
||||
"baihu/internal/models"
|
||||
"baihu/internal/utils"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
type TaskService struct{}
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
)
|
||||
|
||||
type UserService struct{}
|
||||
|
||||
@@ -3,8 +3,8 @@ package utils
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"baihu/internal/cache"
|
||||
"baihu/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/cache"
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package main
|
||||
|
||||
import "baihu/internal/bootstrap"
|
||||
import "github.com/engigu/baihu-panel/internal/bootstrap"
|
||||
|
||||
func main() {
|
||||
bootstrap.New().Run()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { RouterLink, RouterView, useRoute } from 'vue-router'
|
||||
import { resetAuthCache } from '@/router'
|
||||
import { LayoutDashboard, ListTodo, FileCode, Settings, LogOut, ScrollText, Terminal, Variable, KeyRound, Package, Menu, X, Server } from 'lucide-vue-next'
|
||||
@@ -17,7 +17,7 @@ function loadSentenceFromCache(): string | null {
|
||||
try {
|
||||
const cached = localStorage.getItem(SENTENCE_CACHE_KEY)
|
||||
const cacheTime = localStorage.getItem(SENTENCE_CACHE_TIME_KEY)
|
||||
|
||||
|
||||
if (cached && cacheTime) {
|
||||
const age = Date.now() - parseInt(cacheTime)
|
||||
// 如果缓存未过期,使用缓存
|
||||
@@ -46,6 +46,10 @@ const cachedSentence = loadSentenceFromCache()
|
||||
const sentence = ref(cachedSentence || '欢迎使用白虎面板')
|
||||
const { siteSettings, loadSettings } = useSiteSettings()
|
||||
const mobileMenuOpen = ref(false)
|
||||
const sentenceContent = computed(() => {
|
||||
const match = sentence.value.match(/^"(.+)"—— /)
|
||||
return match ? match[1] : sentence.value
|
||||
})
|
||||
|
||||
const navItems = [
|
||||
{ to: '/', icon: LayoutDashboard, label: '数据仪表', exact: true },
|
||||
@@ -101,19 +105,13 @@ onMounted(() => {
|
||||
<template>
|
||||
<div class="flex h-screen bg-muted/40">
|
||||
<!-- Mobile Menu Overlay -->
|
||||
<div
|
||||
v-if="mobileMenuOpen"
|
||||
class="fixed inset-0 bg-black/50 z-40 lg:hidden"
|
||||
@click="mobileMenuOpen = false"
|
||||
/>
|
||||
<div v-if="mobileMenuOpen" class="fixed inset-0 bg-black/50 z-40 lg:hidden" @click="mobileMenuOpen = false" />
|
||||
|
||||
<!-- Sidebar -->
|
||||
<aside
|
||||
:class="[
|
||||
'fixed lg:static inset-y-0 left-0 z-50 w-44 border-r bg-background flex flex-col transform transition-transform duration-200 ease-in-out lg:transform-none',
|
||||
mobileMenuOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'
|
||||
]"
|
||||
>
|
||||
<aside :class="[
|
||||
'fixed lg:static inset-y-0 left-0 z-50 w-44 border-r bg-background flex flex-col transform transition-transform duration-200 ease-in-out lg:transform-none',
|
||||
mobileMenuOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'
|
||||
]">
|
||||
<div class="h-14 flex items-center justify-center px-4 font-semibold text-lg border-b relative">
|
||||
<span>{{ siteSettings.title }}</span>
|
||||
<Button variant="ghost" size="icon" class="h-8 w-8 lg:hidden absolute right-2" @click="mobileMenuOpen = false">
|
||||
@@ -121,25 +119,18 @@ onMounted(() => {
|
||||
</Button>
|
||||
</div>
|
||||
<nav class="flex-1 px-3 py-6 space-y-1 flex flex-col items-center">
|
||||
<RouterLink
|
||||
v-for="item in navItems"
|
||||
:key="item.to"
|
||||
:to="item.to"
|
||||
custom
|
||||
v-slot="{ navigate }"
|
||||
>
|
||||
<Button
|
||||
variant="ghost"
|
||||
<RouterLink v-for="item in navItems" :key="item.to" :to="item.to" custom v-slot="{ navigate }">
|
||||
<Button variant="ghost"
|
||||
:class="['justify-start gap-3 h-9 px-3', isItemActive(item) && 'bg-accent text-accent-foreground']"
|
||||
@click="handleNavClick(navigate)"
|
||||
>
|
||||
@click="handleNavClick(navigate)">
|
||||
<component :is="item.icon" class="h-4 w-4" />
|
||||
{{ item.label }}
|
||||
</Button>
|
||||
</RouterLink>
|
||||
</nav>
|
||||
<div class="px-3 py-4 border-t flex justify-center">
|
||||
<Button variant="ghost" class="justify-start gap-3 h-9 px-3 text-muted-foreground hover:text-foreground" @click="logout">
|
||||
<Button variant="ghost" class="justify-start gap-3 h-9 px-3 text-muted-foreground hover:text-foreground"
|
||||
@click="logout">
|
||||
<LogOut class="h-4 w-4" />
|
||||
退出登录
|
||||
</Button>
|
||||
@@ -149,11 +140,14 @@ onMounted(() => {
|
||||
<!-- Main Content -->
|
||||
<main class="flex-1 overflow-auto w-full">
|
||||
<div class="h-14 border-b bg-background flex items-center justify-between px-4 lg:px-6">
|
||||
<div class="flex items-center gap-3">
|
||||
<Button variant="ghost" size="icon" class="h-8 w-8 lg:hidden" @click="mobileMenuOpen = true">
|
||||
<div class="flex items-center gap-3 flex-1 min-w-0">
|
||||
<Button variant="ghost" size="icon" class="h-8 w-8 lg:hidden shrink-0" @click="mobileMenuOpen = true">
|
||||
<Menu class="h-5 w-5" />
|
||||
</Button>
|
||||
<span class="text-sm text-muted-foreground truncate max-w-[200px] sm:max-w-none">{{ sentence }}</span>
|
||||
<span class="text-sm text-muted-foreground truncate" :title="sentence">
|
||||
<span class="hidden sm:inline">{{ sentence }}</span>
|
||||
<span class="sm:hidden">{{ sentenceContent }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
|
||||
@@ -37,23 +37,23 @@ function animateNumber(key: keyof Stats, target: number) {
|
||||
const start = displayStats.value[key]
|
||||
const duration = 800 // 动画持续时间
|
||||
const startTime = performance.now()
|
||||
|
||||
|
||||
function update(currentTime: number) {
|
||||
const elapsed = currentTime - startTime
|
||||
const progress = Math.min(elapsed / duration, 1)
|
||||
|
||||
|
||||
// 使用 easeOutCubic 缓动函数
|
||||
const easeProgress = 1 - Math.pow(1 - progress, 3)
|
||||
|
||||
|
||||
displayStats.value[key] = Math.round(start + (target - start) * easeProgress)
|
||||
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(update)
|
||||
} else {
|
||||
displayStats.value[key] = target
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
requestAnimationFrame(update)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ function getGridColor() {
|
||||
function handleThemeChange() {
|
||||
// 初始化期间忽略主题变化
|
||||
if (isInitializing) return
|
||||
|
||||
|
||||
const newIsDark = document.documentElement.classList.contains('dark')
|
||||
if (newIsDark !== isDark.value) {
|
||||
isDark.value = newIsDark
|
||||
@@ -127,11 +127,11 @@ async function reloadCharts() {
|
||||
// 等待 Vue 更新 DOM
|
||||
await nextTick()
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
|
||||
|
||||
// 检查容器是否存在再渲染
|
||||
const statsChart = document.querySelector("#stats-chart")
|
||||
const pieChartEl = document.querySelector("#pie-chart")
|
||||
|
||||
|
||||
if (statsChart && pieChartEl && statsChart.parentElement && pieChartEl.parentElement) {
|
||||
renderLineChart()
|
||||
renderPieChart()
|
||||
@@ -143,15 +143,15 @@ async function reloadCharts() {
|
||||
const renderLineChart = () => {
|
||||
const container = document.querySelector("#stats-chart")
|
||||
if (!container || !container.parentElement) return
|
||||
|
||||
|
||||
if (lineChart) {
|
||||
lineChart.destroy()
|
||||
lineChart = null
|
||||
}
|
||||
|
||||
|
||||
// 清空容器
|
||||
container.innerHTML = ''
|
||||
|
||||
|
||||
const textColor = getTextColor()
|
||||
const gridColor = getGridColor()
|
||||
const options = {
|
||||
@@ -282,18 +282,18 @@ const renderLineChart = () => {
|
||||
|
||||
const renderPieChart = () => {
|
||||
if (taskStats.value.length === 0) return
|
||||
|
||||
|
||||
const container = document.querySelector("#pie-chart")
|
||||
if (!container || !container.parentElement) return
|
||||
|
||||
|
||||
if (pieChart) {
|
||||
pieChart.destroy()
|
||||
pieChart = null
|
||||
}
|
||||
|
||||
|
||||
// 清空容器
|
||||
container.innerHTML = ''
|
||||
|
||||
|
||||
const totalCount = taskStats.value.reduce((sum, item) => sum + item.count, 0)
|
||||
const textColor = getTextColor()
|
||||
const options = {
|
||||
@@ -366,13 +366,13 @@ const renderPieChart = () => {
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
formatter: (val: number) => val.toFixed(1) + '%',
|
||||
style: {
|
||||
fontSize: '11px',
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
fontWeight: 'bold',
|
||||
style: {
|
||||
fontSize: '11px',
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
fontWeight: 'bold',
|
||||
colors: ['#ffffff']
|
||||
},
|
||||
dropShadow: {
|
||||
dropShadow: {
|
||||
enabled: true,
|
||||
top: 1,
|
||||
left: 1,
|
||||
@@ -395,7 +395,7 @@ const renderPieChart = () => {
|
||||
|
||||
onMounted(async () => {
|
||||
window.addEventListener('resize', handleResize)
|
||||
|
||||
|
||||
try {
|
||||
const [statsData, sendStatsData, taskStatsData] = await Promise.all([
|
||||
api.dashboard.stats(),
|
||||
@@ -405,13 +405,13 @@ onMounted(async () => {
|
||||
updateStats(statsData)
|
||||
sendStats.value = sendStatsData
|
||||
taskStats.value = taskStatsData
|
||||
|
||||
|
||||
// 渲染图表
|
||||
setTimeout(() => {
|
||||
renderLineChart()
|
||||
renderPieChart()
|
||||
chartsLoaded.value = true
|
||||
|
||||
|
||||
// 图表渲染完成后,延迟启动主题监听,避免初始化时的闪烁
|
||||
setTimeout(() => {
|
||||
isInitializing = false
|
||||
@@ -422,7 +422,7 @@ onMounted(async () => {
|
||||
themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] })
|
||||
}, 500)
|
||||
}, 100)
|
||||
} catch {}
|
||||
} catch { }
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -448,7 +448,8 @@ onUnmounted(() => {
|
||||
</div>
|
||||
|
||||
<div class="grid gap-4 grid-cols-2 sm:grid-cols-3 lg:grid-cols-6">
|
||||
<Card v-for="item in statItems" :key="item.key" class="cursor-pointer hover:bg-accent/50 transition-colors" @click="navigateTo(item.route)">
|
||||
<Card v-for="item in statItems" :key="item.key" class="cursor-pointer hover:bg-accent/50 transition-colors"
|
||||
@click="navigateTo(item.route)">
|
||||
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle class="text-xs sm:text-sm font-medium">{{ item.label }}</CardTitle>
|
||||
<component :is="item.icon" class="h-4 w-4 text-muted-foreground" />
|
||||
@@ -467,7 +468,8 @@ onUnmounted(() => {
|
||||
</CardHeader>
|
||||
<CardContent class="relative h-[300px]">
|
||||
<div id="stats-chart" class="w-full h-full"></div>
|
||||
<div v-if="!chartsLoaded" class="absolute inset-0 flex items-center justify-center text-muted-foreground text-sm bg-card">
|
||||
<div v-if="!chartsLoaded"
|
||||
class="absolute inset-0 flex items-center justify-center text-muted-foreground text-sm bg-card">
|
||||
加载中...
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -480,10 +482,12 @@ onUnmounted(() => {
|
||||
</CardHeader>
|
||||
<CardContent class="relative h-[300px]">
|
||||
<div id="pie-chart" class="w-full h-full"></div>
|
||||
<div v-if="!chartsLoaded" class="absolute inset-0 flex items-center justify-center text-muted-foreground text-sm bg-card">
|
||||
<div v-if="!chartsLoaded"
|
||||
class="absolute inset-0 flex items-center justify-center text-muted-foreground text-sm bg-card">
|
||||
加载中...
|
||||
</div>
|
||||
<div v-else-if="taskStats.length === 0" class="absolute inset-0 flex items-center justify-center text-muted-foreground text-sm bg-card">
|
||||
<div v-else-if="taskStats.length === 0"
|
||||
class="absolute inset-0 flex items-center justify-center text-muted-foreground text-sm bg-card">
|
||||
暂无数据
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
@@ -6,7 +6,6 @@ import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import DirTreeSelect from '@/components/DirTreeSelect.vue'
|
||||
import { Plus, ChevronDown, X } from 'lucide-vue-next'
|
||||
import { api, type Task, type EnvVar, type Agent } from '@/api'
|
||||
@@ -132,8 +131,7 @@ function addEnv(id: number) {
|
||||
}
|
||||
|
||||
function removeEnv(id: number) {
|
||||
const idx = selectedEnvIds.value.indexOf(id)
|
||||
if (idx !== -1) selectedEnvIds.value.splice(idx, 1)
|
||||
selectedEnvIds.value = selectedEnvIds.value.filter(envId => envId !== id)
|
||||
}
|
||||
|
||||
async function save() {
|
||||
@@ -266,10 +264,10 @@ async function save() {
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<div v-if="selectedEnvs.length > 0" class="flex flex-wrap gap-1">
|
||||
<Badge v-for="env in selectedEnvs" :key="env.id" variant="secondary" class="gap-0.5 pr-0.5 text-xs h-5">
|
||||
{{ env.name }}
|
||||
<X class="h-2.5 w-2.5 cursor-pointer hover:text-destructive" @click.stop="removeEnv(env.id)" />
|
||||
</Badge>
|
||||
<div v-for="env in selectedEnvs" :key="env.id" class="inline-flex items-center gap-0.5 px-2 py-0.5 text-xs h-5 rounded-full bg-secondary text-secondary-foreground">
|
||||
<span>{{ env.name }}</span>
|
||||
<X class="h-2.5 w-2.5 cursor-pointer hover:text-destructive" @click="removeEnv(env.id)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user