mirror of
https://github.com/basketikun/infinite-canvas.git
synced 2026-08-01 06:01:13 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ab499bc54 | |||
| fd533dd261 | |||
| c20faa665b | |||
| 979f1facf0 |
+5
-2
@@ -6,8 +6,11 @@ ADMIN_PASSWORD=infinite-canvas
|
|||||||
JWT_SECRET=infinite-canvas
|
JWT_SECRET=infinite-canvas
|
||||||
JWT_EXPIRE_HOURS=168
|
JWT_EXPIRE_HOURS=168
|
||||||
|
|
||||||
# 后端对外监听端口,Docker 默认由 Go 统一暴露 3000。
|
# 后端监听端口
|
||||||
PORT=3000
|
PORT=8080
|
||||||
|
|
||||||
|
# 前端开发代理默认使用 http://127.0.0.1:8080,如后端开发端口不同,启动前端时可单独设置 API_BASE_URL。
|
||||||
|
# API_BASE_URL=http://127.0.0.1:8080
|
||||||
|
|
||||||
# 数据库配置,默认使用本地 SQLite。
|
# 数据库配置,默认使用本地 SQLite。
|
||||||
STORAGE_DRIVER=sqlite
|
STORAGE_DRIVER=sqlite
|
||||||
|
|||||||
@@ -2,6 +2,17 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
|
||||||
|
## v0.0.4 - 2026-05-20
|
||||||
|
|
||||||
|
|
||||||
|
+ [调整] Docker 运行入口改为 Next.js 对外提供页面,`/api/*` 由 Next.js 代理到内部 Go 服务。
|
||||||
|
+ [修复] 文本复制在局域网 IP 访问时可能失败的问题。
|
||||||
|
|
||||||
|
## v0.0.3 - 2026-05-19
|
||||||
|
|
||||||
|
+ [修复] 更新 nanoid 依赖并修改 ID 生成方式,防止其他ip无法使用crypto模块导致的ID生成失败问题。
|
||||||
|
|
||||||
## v0.0.2 - 2026-05-19
|
## v0.0.2 - 2026-05-19
|
||||||
|
|
||||||
+ [新增] 增加生图工作台功能,支持文生图、图生图、查看历史记录,并增加移动端适配。
|
+ [新增] 增加生图工作台功能,支持文生图、图生图、查看历史记录,并增加移动端适配。
|
||||||
|
|||||||
+3
-3
@@ -23,7 +23,7 @@ COPY service ./service
|
|||||||
COPY main.go ./
|
COPY main.go ./
|
||||||
RUN go build -o /server .
|
RUN go build -o /server .
|
||||||
|
|
||||||
# 运行镜像:Go 对外监听 3000,Next.js 只在容器内部监听 3001。
|
# 运行镜像:Next.js 对外监听 3000,Go 只在容器内部监听 8080。
|
||||||
FROM oven/bun:1
|
FROM oven/bun:1
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@@ -35,5 +35,5 @@ RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates
|
|||||||
RUN mkdir -p /app/data/prompts
|
RUN mkdir -p /app/data/prompts
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
# 先启动内部 Next.js,再由 Go 统一处理 /api/* 和页面反代。
|
# 先启动内部 Go API,再由 Next.js 提供页面并代理 /api/*。
|
||||||
CMD ["sh", "-c", "cd /app/web && HOSTNAME=0.0.0.0 PORT=3001 bun run start & PORT=3000 /app/server"]
|
CMD ["sh", "-c", "PORT=8080 /app/server & cd /app/web && HOSTNAME=0.0.0.0 PORT=3000 bun run start"]
|
||||||
|
|||||||
+1
-1
@@ -152,7 +152,7 @@
|
|||||||
## 后端能力
|
## 后端能力
|
||||||
|
|
||||||
- Gin 提供 API 服务。
|
- Gin 提供 API 服务。
|
||||||
- Docker 运行时由 Go 提供统一入口,`/api/*` 直接处理,其它页面请求转到内部 Next.js 服务。
|
- Docker 运行时由 Next.js 提供页面入口,`/api/*` 请求代理到内部 Go 服务。
|
||||||
- GORM 管理数据库连接和自动迁移。
|
- GORM 管理数据库连接和自动迁移。
|
||||||
- 支持 SQLite、MySQL、PostgreSQL。
|
- 支持 SQLite、MySQL、PostgreSQL。
|
||||||
- 数据库保存用户、提示词分组、提示词和服务器素材。
|
- 数据库保存用户、提示词分组、提示词和服务器素材。
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
# 待测试
|
# 待测试
|
||||||
|
|
||||||
|
- 通过局域网 IP 访问前台提示词、素材库、我的素材和后台相关页面时,复制文本应能正常写入剪贴板。
|
||||||
|
|||||||
+1
-15
@@ -2,17 +2,12 @@ package router
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/basketikun/infinite-canvas/handler"
|
"github.com/basketikun/infinite-canvas/handler"
|
||||||
"github.com/basketikun/infinite-canvas/middleware"
|
"github.com/basketikun/infinite-canvas/middleware"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
const webBaseURL = "http://127.0.0.1:3001"
|
|
||||||
|
|
||||||
func New() *gin.Engine {
|
func New() *gin.Engine {
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
router.RedirectTrailingSlash = false
|
router.RedirectTrailingSlash = false
|
||||||
@@ -47,16 +42,7 @@ func New() *gin.Engine {
|
|||||||
handler.AdminDeleteAsset(c.Writer, c.Request, c.Param("id"))
|
handler.AdminDeleteAsset(c.Writer, c.Request, c.Param("id"))
|
||||||
})
|
})
|
||||||
|
|
||||||
webURL, _ := url.Parse(webBaseURL)
|
router.NoRoute(middleware.NotFoundJSON)
|
||||||
webProxy := httputil.NewSingleHostReverseProxy(webURL)
|
|
||||||
router.NoRoute(func(c *gin.Context) {
|
|
||||||
path := c.Request.URL.Path
|
|
||||||
if path == "/api" || strings.HasPrefix(path, "/api/") {
|
|
||||||
middleware.NotFoundJSON(c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
webProxy.ServeHTTP(c.Writer, c.Request)
|
|
||||||
})
|
|
||||||
|
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -12,9 +12,11 @@
|
|||||||
"axios": "^1.16.0",
|
"axios": "^1.16.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"copy-to-clipboard": "^4.0.2",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lucide-react": "^1.16.0",
|
"lucide-react": "^1.16.0",
|
||||||
"motion": "^12.38.0",
|
"motion": "^12.38.0",
|
||||||
|
"nanoid": "^5.1.11",
|
||||||
"next": "16.2.3",
|
"next": "16.2.3",
|
||||||
"radix-ui": "^1.4.3",
|
"radix-ui": "^1.4.3",
|
||||||
"react": "19.2.5",
|
"react": "19.2.5",
|
||||||
@@ -645,6 +647,8 @@
|
|||||||
|
|
||||||
"cookie-signature": ["cookie-signature@1.2.2", "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.2.2.tgz", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
"cookie-signature": ["cookie-signature@1.2.2", "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.2.2.tgz", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
||||||
|
|
||||||
|
"copy-to-clipboard": ["copy-to-clipboard@4.0.2", "", {}, "sha512-gklSft7IuhriZKHKpuoA1fpJSLPNgvUMWMo5BlnzAJm0zNKnznoSv23IjtNqclx8eKi6ZcdvFFzYEER/+U1LoQ=="],
|
||||||
|
|
||||||
"cors": ["cors@2.8.6", "https://registry.npmmirror.com/cors/-/cors-2.8.6.tgz", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="],
|
"cors": ["cors@2.8.6", "https://registry.npmmirror.com/cors/-/cors-2.8.6.tgz", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="],
|
||||||
|
|
||||||
"cosmiconfig": ["cosmiconfig@9.0.1", "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-9.0.1.tgz", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ=="],
|
"cosmiconfig": ["cosmiconfig@9.0.1", "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-9.0.1.tgz", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ=="],
|
||||||
@@ -1055,7 +1059,7 @@
|
|||||||
|
|
||||||
"mute-stream": ["mute-stream@3.0.0", "https://registry.npmmirror.com/mute-stream/-/mute-stream-3.0.0.tgz", {}, "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw=="],
|
"mute-stream": ["mute-stream@3.0.0", "https://registry.npmmirror.com/mute-stream/-/mute-stream-3.0.0.tgz", {}, "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw=="],
|
||||||
|
|
||||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
"nanoid": ["nanoid@5.1.11", "https://registry.npmmirror.com/nanoid/-/nanoid-5.1.11.tgz", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg=="],
|
||||||
|
|
||||||
"negotiator": ["negotiator@1.0.0", "https://registry.npmmirror.com/negotiator/-/negotiator-1.0.0.tgz", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
"negotiator": ["negotiator@1.0.0", "https://registry.npmmirror.com/negotiator/-/negotiator-1.0.0.tgz", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
||||||
|
|
||||||
@@ -1487,6 +1491,8 @@
|
|||||||
|
|
||||||
"npm-run-path/path-key": ["path-key@4.0.0", "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
"npm-run-path/path-key": ["path-key@4.0.0", "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
||||||
|
|
||||||
|
"postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||||
|
|
||||||
"prompts/kleur": ["kleur@3.0.3", "https://registry.npmmirror.com/kleur/-/kleur-3.0.3.tgz", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
"prompts/kleur": ["kleur@3.0.3", "https://registry.npmmirror.com/kleur/-/kleur-3.0.3.tgz", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
||||||
|
|
||||||
"prop-types/react-is": ["react-is@16.13.1", "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
"prop-types/react-is": ["react-is@16.13.1", "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
||||||
@@ -1535,6 +1541,8 @@
|
|||||||
|
|
||||||
"express/mime-types/mime-db": ["mime-db@1.54.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
"express/mime-types/mime-db": ["mime-db@1.54.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
|
"next/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||||
|
|
||||||
"send/mime-types/mime-db": ["mime-db@1.54.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
"send/mime-types/mime-db": ["mime-db@1.54.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
"type-is/mime-types/mime-db": ["mime-db@1.54.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
"type-is/mime-types/mime-db": ["mime-db@1.54.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|||||||
+8
-2
@@ -1,21 +1,27 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
import { PHASE_DEVELOPMENT_SERVER } from "next/constants";
|
import { PHASE_DEVELOPMENT_SERVER } from "next/constants";
|
||||||
|
import { loadEnvConfig } from "@next/env";
|
||||||
import { readFileSync } from "node:fs";
|
import { readFileSync } from "node:fs";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { dirname, resolve } from "node:path";
|
import { dirname, resolve } from "node:path";
|
||||||
|
|
||||||
const apiBaseUrl = process.env.API_BASE_URL || "http://127.0.0.1:3000";
|
|
||||||
const webDir = dirname(fileURLToPath(import.meta.url));
|
const webDir = dirname(fileURLToPath(import.meta.url));
|
||||||
const version = readFileSync(resolve(webDir, "../VERSION"), "utf8").trim() || "dev";
|
const version = readFileSync(resolve(webDir, "../VERSION"), "utf8").trim() || "dev";
|
||||||
|
|
||||||
export default function nextConfig(phase: string): NextConfig {
|
export default function nextConfig(phase: string): NextConfig {
|
||||||
const isDev = phase === PHASE_DEVELOPMENT_SERVER;
|
const isDev = phase === PHASE_DEVELOPMENT_SERVER;
|
||||||
|
loadEnvConfig(resolve(webDir, ".."), isDev, undefined, true);
|
||||||
|
const apiBaseUrl = process.env.API_BASE_URL || "http://127.0.0.1:8080";
|
||||||
return {
|
return {
|
||||||
|
allowedDevOrigins: isDev ? ["*.*.*.*"] : [],
|
||||||
|
typescript: {
|
||||||
|
ignoreBuildErrors: true,
|
||||||
|
},
|
||||||
env: {
|
env: {
|
||||||
NEXT_PUBLIC_APP_VERSION: version,
|
NEXT_PUBLIC_APP_VERSION: version,
|
||||||
},
|
},
|
||||||
async rewrites() {
|
async rewrites() {
|
||||||
return isDev ? [{ source: "/api/:path*", destination: `${apiBaseUrl}/api/:path*` }] : [];
|
return [{ source: "/api/:path*", destination: `${apiBaseUrl}/api/:path*` }];
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -4,7 +4,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --webpack -H 0.0.0.0 -p 3001",
|
"dev": "next dev --webpack -H 0.0.0.0 -p 3000",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start"
|
"start": "next start"
|
||||||
},
|
},
|
||||||
@@ -16,9 +16,11 @@
|
|||||||
"axios": "^1.16.0",
|
"axios": "^1.16.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"copy-to-clipboard": "^4.0.2",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lucide-react": "^1.16.0",
|
"lucide-react": "^1.16.0",
|
||||||
"motion": "^12.38.0",
|
"motion": "^12.38.0",
|
||||||
|
"nanoid": "^5.1.11",
|
||||||
"next": "16.2.3",
|
"next": "16.2.3",
|
||||||
"radix-ui": "^1.4.3",
|
"radix-ui": "^1.4.3",
|
||||||
"react": "19.2.5",
|
"react": "19.2.5",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { CopyOutlined, DeleteOutlined, EditOutlined, EyeOutlined, PlusOutlined,
|
|||||||
import { ProTable, type ProColumns } from "@ant-design/pro-components";
|
import { ProTable, type ProColumns } from "@ant-design/pro-components";
|
||||||
import { App, Button, Card, Col, Flex, Form, Image, Input, Modal, Row, Select, Space, Tag, Tooltip, Typography } from "antd";
|
import { App, Button, Card, Col, Flex, Form, Image, Input, Modal, Row, Select, Space, Tag, Tooltip, Typography } from "antd";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
|
||||||
import type { AdminAsset } from "@/services/api/admin";
|
import type { AdminAsset } from "@/services/api/admin";
|
||||||
import { useAdminAssets } from "../hooks/use-admin-assets";
|
import { useAdminAssets } from "../hooks/use-admin-assets";
|
||||||
@@ -33,7 +34,7 @@ export default function AdminAssetsPage() {
|
|||||||
}, [editingAsset, form]);
|
}, [editingAsset, form]);
|
||||||
|
|
||||||
const copyValue = async (value: string) => {
|
const copyValue = async (value: string) => {
|
||||||
await navigator.clipboard.writeText(value);
|
copy(value);
|
||||||
message.success("已复制");
|
message.success("已复制");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { CopyOutlined, DeleteOutlined, EditOutlined, ExportOutlined, EyeOutlined
|
|||||||
import { ProTable, type ProColumns } from "@ant-design/pro-components";
|
import { ProTable, type ProColumns } from "@ant-design/pro-components";
|
||||||
import { App, Button, Card, Col, Flex, Form, Image, Input, Modal, Row, Select, Space, Table, Tag, Tooltip, Typography } from "antd";
|
import { App, Button, Card, Col, Flex, Form, Image, Input, Modal, Row, Select, Space, Table, Tag, Tooltip, Typography } from "antd";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
|
||||||
import type { Prompt } from "@/services/api/prompts";
|
import type { Prompt } from "@/services/api/prompts";
|
||||||
import { useAdminPrompts } from "../hooks/use-admin-prompts";
|
import { useAdminPrompts } from "../hooks/use-admin-prompts";
|
||||||
@@ -26,7 +27,7 @@ export default function AdminPromptsPage() {
|
|||||||
}, [editingPrompt, form]);
|
}, [editingPrompt, form]);
|
||||||
|
|
||||||
const copyPrompt = async (value: string) => {
|
const copyPrompt = async (value: string) => {
|
||||||
await navigator.clipboard.writeText(value);
|
copy(value);
|
||||||
message.success("已复制");
|
message.success("已复制");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useEffect, useState } from "react";
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { App, Button, Card, Drawer, Empty, Image, Input, Pagination, Spin, Tag, Typography } from "antd";
|
import { App, Button, Card, Drawer, Empty, Image, Input, Pagination, Spin, Tag, Typography } from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { useAssetStore } from "@/stores/use-asset-store";
|
import { useAssetStore } from "@/stores/use-asset-store";
|
||||||
@@ -77,7 +78,7 @@ export default function AssetLibraryPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const copyText = async (value: string) => {
|
const copyText = async (value: string) => {
|
||||||
await navigator.clipboard.writeText(value);
|
copy(value);
|
||||||
message.success("已复制");
|
message.success("已复制");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { Copy, Download, PencilLine, Search, Trash2, Upload } from "lucide-react";
|
import { Copy, Download, PencilLine, Search, Trash2, Upload } from "lucide-react";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { App, Button, Card, Drawer, Empty, Form, Image, Input, Modal, Pagination, Select, Space, Tag, Typography } from "antd";
|
import { App, Button, Card, Drawer, Empty, Form, Image, Input, Modal, Pagination, Select, Space, Tag, Typography } from "antd";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
|
||||||
import { formatBytes, readFileAsDataUrl } from "@/lib/image-utils";
|
import { formatBytes, readFileAsDataUrl } from "@/lib/image-utils";
|
||||||
import { uploadImage } from "@/services/image-storage";
|
import { uploadImage } from "@/services/image-storage";
|
||||||
@@ -139,7 +140,7 @@ export default function AssetsPage() {
|
|||||||
|
|
||||||
const copyText = async (asset: Asset) => {
|
const copyText = async (asset: Asset) => {
|
||||||
if (asset.kind !== "text") return;
|
if (asset.kind !== "text") return;
|
||||||
await navigator.clipboard.writeText(asset.data.content);
|
copy(asset.data.content);
|
||||||
message.success("文本已复制");
|
message.success("文本已复制");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { FolderPlus, Search } from "lucide-react";
|
import { FolderPlus, Search } from "lucide-react";
|
||||||
import { type UIEvent, useEffect, useState } from "react";
|
import { type UIEvent, useEffect, useState } from "react";
|
||||||
import { App, Button, Empty, Input, Spin, Tag } from "antd";
|
import { App, Button, Empty, Input, Spin, Tag } from "antd";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
|
||||||
import { PromptCard } from "@/components/prompts/prompt-card";
|
import { PromptCard } from "@/components/prompts/prompt-card";
|
||||||
import { PromptDetailDialog } from "@/components/prompts/prompt-detail-dialog";
|
import { PromptDetailDialog } from "@/components/prompts/prompt-detail-dialog";
|
||||||
@@ -32,7 +33,7 @@ export default function PromptsPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const copyPrompt = async (prompt: string) => {
|
const copyPrompt = async (prompt: string) => {
|
||||||
await navigator.clipboard.writeText(prompt);
|
copy(prompt);
|
||||||
message.success("提示词已复制");
|
message.success("提示词已复制");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -1,3 +1,5 @@
|
|||||||
|
import { nanoid } from "nanoid";
|
||||||
|
|
||||||
export function createId() {
|
export function createId() {
|
||||||
return crypto.randomUUID();
|
return nanoid();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user