diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml new file mode 100644 index 0000000..448efc1 --- /dev/null +++ b/.gitea/workflows/deploy.yaml @@ -0,0 +1,42 @@ +name: Deploy Docker Image + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build-and-deploy: + runs-on: ubuntu + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + push: true + tags: ${{ secrets.DOCKER_USERNAME }}/wx-pyq:latest + + - name: Deploy to Server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.SERVER_HOST }} + username: ${{ secrets.SERVER_USERNAME }} + key: ${{ secrets.SERVER_KEY }} + script: | + docker pull ${{ secrets.DOCKER_USERNAME }}/wx-pyq:latest + docker stop wx-pyq || true + docker rm wx-pyq || true + docker run -d --name wx-pyq -p 80:80 ${{ secrets.DOCKER_USERNAME }}/wx-pyq:latest diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 048bd03..3de77d4 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useRef } from 'react'; -import { Button, Input, Card, Toast, ErrorBlock } from 'antd-mobile'; -import { Copy, RefreshCw, Sparkles, Wand2, Quote, UserCircle2, Download } from 'lucide-react'; +import { Button, Input, Toast, ErrorBlock } from 'antd-mobile'; +import { Copy, RefreshCw, Sparkles, Wand2, Quote, UserCircle2, Download, Image as ImageIcon } from 'lucide-react'; import { useAppStore } from '../store/useAppStore'; import { generateCopyStream } from '../services/api'; import { Header } from '../components/Header'; @@ -91,17 +91,44 @@ export const Home: React.FC = () => { const copyToClipboard = () => { if (!result) return; navigator.clipboard.writeText(result).then(() => { - Toast.show({ content: '已复制到剪贴板', icon: 'success' }); + Toast.show({ content: '已复制文案', icon: 'success' }); }); }; + const copyPosterImage = async () => { + if (!posterRef.current || !result) return; + try { + const canvas = await html2canvas(posterRef.current, { + useCORS: true, + scale: 2, + backgroundColor: null + }); + + canvas.toBlob(async (blob) => { + if (!blob) return; + try { + // Attempt to write to clipboard + const item = new ClipboardItem({ 'image/png': blob }); + await navigator.clipboard.write([item]); + Toast.show({ content: '海报已复制', icon: 'success' }); + } catch (err) { + console.error('Clipboard write failed:', err); + Toast.show({ content: '复制失败,请尝试保存', icon: 'fail' }); + } + }, 'image/png'); + } catch (err) { + console.error('Capture failed:', err); + Toast.show({ content: '生成图片失败', icon: 'fail' }); + } + }; + const handleSaveImage = async () => { if (!posterRef.current || !result) return; try { const canvas = await html2canvas(posterRef.current, { useCORS: true, scale: 2, - backgroundColor: null // Transparent background if needed, but poster usually has bg + backgroundColor: null }); const link = document.createElement('a'); link.download = `wx-moments-${Date.now()}.png`; @@ -179,7 +206,7 @@ export const Home: React.FC = () => {

- 基于 DashScope 大模型 · 智能匹配场景 + 基于 DashScope 大模型 (qwen3.5-plus) · 智能匹配场景

@@ -233,7 +260,11 @@ export const Home: React.FC = () => { )} -
+ {/* Poster Container */} +
{/* Background Image Layer */} {currentPosterUrl && (
@@ -243,33 +274,36 @@ export const Home: React.FC = () => { className="w-full h-full object-cover" crossOrigin="anonymous" /> -
{/* Overlay for readability */} +
)} - -
-
- - -
- {result} - {loading && ( - - )} -
-
-
-
- +
+ + +
+ {result} + {loading && ( + + )} +
+
+ +
+
+
+ Generated by AI +
+
+ +
+
+
+
{/* Actions Bar (Outside of Poster Ref) */} -
+
{currentPosterUrl && result && !loading && ( - + <> + + + + )}