Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a31ae09af | |||
| 6f0713953a | |||
| d719181834 | |||
| 953b74bf52 | |||
| 0a77e67200 | |||
| 03287697c3 | |||
| 6cb273a8a9 | |||
| 4647921e01 | |||
| 54c84b6681 | |||
| 33133430f8 | |||
| d63074be71 | |||
| 75ae5ae01f | |||
| 9ced46c296 |
@@ -3,7 +3,7 @@
|
|||||||
在 Markdown 的 H2 标题前插入分隔线,第一个除外
|
在 Markdown 的 H2 标题前插入分隔线,第一个除外
|
||||||
"""
|
"""
|
||||||
|
|
||||||
MD_PATH = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/final-article.md"
|
MD_PATH = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/final-article.md"
|
||||||
|
|
||||||
with open(MD_PATH, "r", encoding="utf-8") as f:
|
with open(MD_PATH, "r", encoding="utf-8") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
HTML_PATH = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/article-optimized.html"
|
HTML_PATH = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/article-optimized.html"
|
||||||
|
|
||||||
with open(HTML_PATH, "r", encoding="utf-8") as f:
|
with open(HTML_PATH, "r", encoding="utf-8") as f:
|
||||||
html = f.read()
|
html = f.read()
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
import os
|
import os
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
IMAGES_DIR = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/publishing/images"
|
IMAGES_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/publishing/images"
|
||||||
OUTPUT_DIR = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/publishing/images_compressed"
|
OUTPUT_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/publishing/images_compressed"
|
||||||
|
|
||||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ from docx.shared import Inches, Pt, RGBColor
|
|||||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||||
|
|
||||||
# 路径配置
|
# 路径配置
|
||||||
MARKDOWN_FILE = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/final-article.md"
|
MARKDOWN_FILE = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/final-article.md"
|
||||||
IMAGES_DIR = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/publishing/images"
|
IMAGES_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/publishing/images"
|
||||||
OUTPUT_DOCX = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/上海阳台种菜一年_最终版.docx"
|
OUTPUT_DOCX = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/上海阳台种菜一年_最终版.docx"
|
||||||
|
|
||||||
# 读取 Markdown
|
# 读取 Markdown
|
||||||
with open(MARKDOWN_FILE, "r", encoding="utf-8") as f:
|
with open(MARKDOWN_FILE, "r", encoding="utf-8") as f:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from docx import Document
|
|||||||
from docx.shared import Inches, Pt
|
from docx.shared import Inches, Pt
|
||||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||||
|
|
||||||
BASE_DIR = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
||||||
MD_FILE = os.path.join(BASE_DIR, "final-article.md")
|
MD_FILE = os.path.join(BASE_DIR, "final-article.md")
|
||||||
IMAGES_DIR = os.path.join(BASE_DIR, "images") # 已复制的图片
|
IMAGES_DIR = os.path.join(BASE_DIR, "images") # 已复制的图片
|
||||||
OUTPUT_DOCX = os.path.join(BASE_DIR, "上海阳台种菜一年_最终版.docx")
|
OUTPUT_DOCX = os.path.join(BASE_DIR, "上海阳台种菜一年_最终版.docx")
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
BASE_DIR = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
||||||
MD_FILE = os.path.join(BASE_DIR, "final-article.md")
|
MD_FILE = os.path.join(BASE_DIR, "final-article.md")
|
||||||
OUT_HTML = os.path.join(BASE_DIR, "上海阳台种菜一年_可复制.html")
|
OUT_HTML = os.path.join(BASE_DIR, "上海阳台种菜一年_可复制.html")
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
BASE_DIR = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
||||||
MD_FILE = os.path.join(BASE_DIR, "final-article.md")
|
MD_FILE = os.path.join(BASE_DIR, "final-article.md")
|
||||||
IMAGES_DIR = os.path.join(BASE_DIR, "images") # 使用发布目录内的 images
|
IMAGES_DIR = os.path.join(BASE_DIR, "images") # 使用发布目录内的 images
|
||||||
OUT_HTML = os.path.join(BASE_DIR, "上海阳台种菜一年_内联.html")
|
OUT_HTML = os.path.join(BASE_DIR, "上海阳台种菜一年_内联.html")
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
BASE_DIR = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
||||||
MD_FILE = os.path.join(BASE_DIR, "final-article.md")
|
MD_FILE = os.path.join(BASE_DIR, "final-article.md")
|
||||||
OUT_MD = os.path.join(BASE_DIR, "final-article-optimized.md")
|
OUT_MD = os.path.join(BASE_DIR, "final-article-optimized.md")
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from docx import Document
|
|||||||
from docx.shared import Inches, Pt
|
from docx.shared import Inches, Pt
|
||||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||||
|
|
||||||
BASE_DIR = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
||||||
MD_FILE = os.path.join(BASE_DIR, "final-article-optimized.md")
|
MD_FILE = os.path.join(BASE_DIR, "final-article-optimized.md")
|
||||||
IMAGES_DIR = os.path.join(BASE_DIR, "images")
|
IMAGES_DIR = os.path.join(BASE_DIR, "images")
|
||||||
OUTPUT_DOCX = os.path.join(BASE_DIR, "上海阳台种菜一年_发布版.docx")
|
OUTPUT_DOCX = os.path.join(BASE_DIR, "上海阳台种菜一年_发布版.docx")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
python3 - << 'PYEOF'
|
python3 - << 'PYEOF'
|
||||||
import os, re, base64
|
import os, re, base64
|
||||||
|
|
||||||
BASE_DIR = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
BASE_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年"
|
||||||
MD_FILE = os.path.join(BASE_DIR, "final-article-optimized.md")
|
MD_FILE = os.path.join(BASE_DIR, "final-article-optimized.md")
|
||||||
IMAGES_DIR = os.path.join(BASE_DIR, "images")
|
IMAGES_DIR = os.path.join(BASE_DIR, "images")
|
||||||
OUT_HTML = os.path.join(BASE_DIR, "上海阳台种菜一年_发布版.html")
|
OUT_HTML = os.path.join(BASE_DIR, "上海阳台种菜一年_发布版.html")
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
PROJECT_ROOT="/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran"
|
PROJECT_ROOT="/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran"
|
||||||
SESSION_STATE="/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/automation/wechat_state.json"
|
SESSION_STATE="/root/openclaw-workspace/projects/yu-zhi-ran/automation/wechat_state.json"
|
||||||
|
|
||||||
if [ $# -ne 2 ]; then
|
if [ $# -ne 2 ]; then
|
||||||
echo "用法: $0 <markdown_file> <images_dir>"
|
echo "用法: $0 <markdown_file> <images_dir>"
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ if (!editor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 上传封面图(如需自动上传)
|
// 上传封面图(如需自动上传)
|
||||||
const coverPath = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/publishing/images/05-封面图.png";
|
const coverPath = "/root/openclaw-workspace/projects/yu-zhi-ran/content/publishing/images/05-封面图.png";
|
||||||
console.log("📸 封面上传:请手动点击编辑器图片按钮,选择封面图文件");
|
console.log("📸 封面上传:请手动点击编辑器图片按钮,选择封面图文件");
|
||||||
console.log(" 文件路径:", coverPath);
|
console.log(" 文件路径:", coverPath);
|
||||||
|
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ if (!editor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 提示封面上传
|
// 提示封面上传
|
||||||
const coverPath = "/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/content/publishing/images/05-封面图.png";
|
const coverPath = "/root/openclaw-workspace/projects/yu-zhi-ran/content/publishing/images/05-封面图.png";
|
||||||
console.log("\n📸 封面上传:");
|
console.log("\n📸 封面上传:");
|
||||||
console.log(" 1. 点击编辑器工具栏的图片按钮(🖼️)");
|
console.log(" 1. 点击编辑器工具栏的图片按钮(🖼️)");
|
||||||
console.log(" 2. 选择 '上传图片'");
|
console.log(" 2. 选择 '上传图片'");
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -4,9 +4,9 @@ from fastapi import APIRouter, Depends, HTTPException, status
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from ..core.security import get_current_admin_user
|
from core.security import get_current_admin_user
|
||||||
from ..database import get_db
|
from app.database import get_db
|
||||||
from ..models import User, AuditLog
|
from app.models import User, AuditLog
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ async def create_user(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 导入密码哈希函数
|
# 导入密码哈希函数
|
||||||
from ..core.security import get_password_hash
|
from core.security import get_password_hash
|
||||||
|
|
||||||
# 创建新用户
|
# 创建新用户
|
||||||
new_user = User(
|
new_user = User(
|
||||||
@@ -69,7 +69,7 @@ async def create_user(
|
|||||||
db.refresh(new_user)
|
db.refresh(new_user)
|
||||||
|
|
||||||
# 记录审计日志
|
# 记录审计日志
|
||||||
from ..core.security import create_audit_log
|
from core.security import create_audit_log
|
||||||
create_audit_log(
|
create_audit_log(
|
||||||
db=db,
|
db=db,
|
||||||
user_id=current_user.id,
|
user_id=current_user.id,
|
||||||
@@ -129,7 +129,7 @@ async def update_user(
|
|||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
# 记录审计日志
|
# 记录审计日志
|
||||||
from ..core.security import create_audit_log
|
from core.security import create_audit_log
|
||||||
create_audit_log(
|
create_audit_log(
|
||||||
db=db,
|
db=db,
|
||||||
user_id=current_user.id,
|
user_id=current_user.id,
|
||||||
@@ -169,7 +169,7 @@ async def delete_user(
|
|||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
# 记录审计日志
|
# 记录审计日志
|
||||||
from ..core.security import create_audit_log
|
from core.security import create_audit_log
|
||||||
create_audit_log(
|
create_audit_log(
|
||||||
db=db,
|
db=db,
|
||||||
user_id=current_user.id,
|
user_id=current_user.id,
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ from fastapi import APIRouter, Depends, HTTPException, status
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from ..database import get_db
|
from app.database import get_db
|
||||||
from ..models import Topic
|
from app.models import Topic
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ from sqlalchemy.orm import Session
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
import secrets
|
import secrets
|
||||||
|
|
||||||
from ..core.security import (
|
from core.security import (
|
||||||
verify_password, get_password_hash, create_access_token,
|
verify_password, get_password_hash, create_access_token,
|
||||||
create_audit_log
|
create_audit_log
|
||||||
)
|
)
|
||||||
from ..database import get_db
|
from app.database import get_db
|
||||||
from ..models import User
|
from app.models import User
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
# 宇之然内容创作平台 - 文章生成API
|
# 宇之然内容创作平台 - 文章生成API
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from ..core.security import get_current_user, create_audit_log
|
from core.security import get_current_user, create_audit_log
|
||||||
from ..database import get_db
|
from app.database import get_db
|
||||||
from ..models import Topic, User, GenerateTask
|
from app.models import Topic, User, GenerateTask
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ from fastapi import APIRouter, Depends
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from ..database import get_db
|
from app.database import get_db
|
||||||
from ..models import AuditLog
|
from app.models import AuditLog
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
# 宇之然内容创作平台 - 文章发布API
|
# 宇之然内容创作平台 - 文章发布API
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from ..core.security import get_current_user, create_audit_log
|
from core.security import get_current_user, create_audit_log
|
||||||
from ..database import get_db
|
from app.database import get_db
|
||||||
from ..models import Topic, User
|
from app.models import Topic, User
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
# 宇之然内容创作平台 - 系统管理API
|
# 宇之然内容创作平台 - 系统管理API
|
||||||
|
|
||||||
|
from sqlalchemy import func
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ..database import get_db
|
from app.database import get_db
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
# 宇之然内容创作平台 - 选题管理API
|
# 宇之然内容创作平台 - 选题管理API
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from ..core.security import get_current_admin_user, create_audit_log
|
from core.security import get_current_admin_user, create_audit_log
|
||||||
from ..database import get_db
|
from app.database import get_db
|
||||||
from ..models import Topic, User
|
from app.models import Topic, User
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ from fastapi.security import OAuth2PasswordBearer
|
|||||||
from fastapi import Depends, HTTPException, status
|
from fastapi import Depends, HTTPException, status
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from ..models import User
|
from app.models import User
|
||||||
from ..database import get_db
|
from app.database import get_db
|
||||||
|
|
||||||
# 密码加密
|
# 密码加密
|
||||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||||
|
|||||||
@@ -39,5 +39,5 @@ def get_db():
|
|||||||
|
|
||||||
def init_db():
|
def init_db():
|
||||||
"""初始化数据库(创建表)"""
|
"""初始化数据库(创建表)"""
|
||||||
from .models import Base
|
from app.models import Base
|
||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
@@ -1,13 +1,17 @@
|
|||||||
# 宇之然内容创作平台 - 主应用入口
|
# 宇之然内容创作平台 - 主应用入口
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
|
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
from .database import init_db
|
from app.database import init_db
|
||||||
from .core.security import SECRET_KEY
|
from core.security import SECRET_KEY
|
||||||
from .api import auth, topics, system, generate, publishing, articles, logs, admin
|
from api import auth, topics, system, publishing, articles, logs, admin
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
@@ -42,7 +46,6 @@ app.add_middleware(
|
|||||||
app.include_router(auth.router, prefix="/api/auth", tags=["认证"])
|
app.include_router(auth.router, prefix="/api/auth", tags=["认证"])
|
||||||
app.include_router(topics.router, prefix="/api/topics", tags=["选题管理"])
|
app.include_router(topics.router, prefix="/api/topics", tags=["选题管理"])
|
||||||
app.include_router(system.router, prefix="/api/system", tags=["系统状态"])
|
app.include_router(system.router, prefix="/api/system", tags=["系统状态"])
|
||||||
app.include_router(generate.router, prefix="/api/system", tags=["批量操作"])
|
|
||||||
app.include_router(publishing.router, prefix="/api/publishing", tags=["文章发布"])
|
app.include_router(publishing.router, prefix="/api/publishing", tags=["文章发布"])
|
||||||
app.include_router(articles.router, prefix="/api/articles", tags=["文章预览"])
|
app.include_router(articles.router, prefix="/api/articles", tags=["文章预览"])
|
||||||
app.include_router(logs.router, prefix="/api/logs", tags=["日志系统"])
|
app.include_router(logs.router, prefix="/api/logs", tags=["日志系统"])
|
||||||
|
|||||||
Regular → Executable
+1
-1
@@ -32,6 +32,6 @@ fi
|
|||||||
|
|
||||||
# 启动服务
|
# 启动服务
|
||||||
echo "正在启动后端服务 (端口 8001)..."
|
echo "正在启动后端服务 (端口 8001)..."
|
||||||
uvicorn main:app --host 0.0.0.0 --port 8001 --reload
|
PYTHONPATH=$(pwd) uvicorn main:app --host 0.0.0.0 --port 8001 --reload
|
||||||
|
|
||||||
echo "服务已停止"
|
echo "服务已停止"
|
||||||
@@ -81,10 +81,10 @@
|
|||||||
</nav>
|
</nav>
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<aside class="sidebar">
|
<aside class="sidebar">
|
||||||
<button class="sidebar-btn" :class="{ active: currentPage === 'overview' }" @click="currentPage = 'overview'">📊 系统概览</button>
|
<button class="sidebar-btn" :class="{ active: currentPage === 'overview' }" @click="redirectToPage('/')">📊 系统概览</button>
|
||||||
<button class="sidebar-btn" :class="{ active: currentPage === 'topics' }" @click="currentPage = 'topics'">📋 选题管理</button>
|
<button class="sidebar-btn" :class="{ active: currentPage === 'topics' }" @click="redirectToPage('topics.html')">📋 选题管理</button>
|
||||||
<button class="sidebar-btn" :class="{ active: currentPage === 'logs' }" @click="currentPage = 'logs'">📄 系统日志</button>
|
<button class="sidebar-btn" :class="{ active: currentPage === 'logs' }" @click="redirectToPage('logs.html')">📄 系统日志</button>
|
||||||
<button v-if="isAdmin" class="sidebar-btn" :class="{ active: currentPage === 'users' }" @click="currentPage = 'users'">👥 用户管理</button>
|
<button v-if="isAdmin" class="sidebar-btn" :class="{ active: currentPage === 'users' }" @click="redirectToPage('users.html')">👥 用户管理</button>
|
||||||
</aside>
|
</aside>
|
||||||
<main class="content-area">
|
<main class="content-area">
|
||||||
<div id="page-overview" class="page" :class="{ active: currentPage === 'overview' }">
|
<div id="page-overview" class="page" :class="{ active: currentPage === 'overview' }">
|
||||||
@@ -111,10 +111,10 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<nav class="mobile-nav">
|
<nav class="mobile-nav">
|
||||||
<button class="mobile-nav-btn" :class="{ active: currentPage === 'overview' }" @click="currentPage = 'overview'">📊 概览</button>
|
<button class="mobile-nav-btn" :class="{ active: currentPage === 'overview' }" @click="redirectToPage('/')">📊 概览</button>
|
||||||
<button class="mobile-nav-btn" :class="{ active: currentPage === 'topics' }" @click="currentPage = 'topics'">📋 选题</button>
|
<button class="mobile-nav-btn" :class="{ active: currentPage === 'topics' }" @click="redirectToPage('topics.html')">📋 选题</button>
|
||||||
<button class="mobile-nav-btn" :class="{ active: currentPage === 'logs' }" @click="currentPage = 'logs'">📄 日志</button>
|
<button class="mobile-nav-btn" :class="{ active: currentPage === 'logs' }" @click="redirectToPage('logs.html')">📄 日志</button>
|
||||||
<button v-if="isAdmin" class="mobile-nav-btn" :class="{ active: currentPage === 'users' }" @click="currentPage = 'users'">👥 用户</button>
|
<button v-if="isAdmin" class="mobile-nav-btn" :class="{ active: currentPage === 'users' }" @click="redirectToPage('users.html')">👥 用户</button>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -29,6 +29,15 @@
|
|||||||
.mobile-nav { display: flex; }
|
.mobile-nav { display: flex; }
|
||||||
.content-area { padding: 16px; padding-bottom: 80px; }
|
.content-area { padding: 16px; padding-bottom: 80px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* logs.html 移动端优化 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.log-controls { flex-direction: column; gap: 8px; }
|
||||||
|
.log-controls .el-select, .log-controls .el-date-picker { width: 100% !important; }
|
||||||
|
.el-card { margin: 0 -16px; border-radius: 0; min-height: calc(100vh - 180px); }
|
||||||
|
.el-card .el-card__body { padding: 12px; }
|
||||||
|
pre { font-size: 11px; line-height: 1.4; }
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "frontend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "debug-vue.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"type": "commonjs"
|
||||||
|
}
|
||||||
@@ -35,6 +35,48 @@
|
|||||||
.mobile-nav { display: flex; }
|
.mobile-nav { display: flex; }
|
||||||
.content-area { padding: 16px; padding-bottom: 80px; }
|
.content-area { padding: 16px; padding-bottom: 80px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 移动端卡片布局 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.el-table { font-size: 12px; display: none; }
|
||||||
|
.el-table .el-button { padding: 4px 8px; font-size: 11px; min-height: auto; }
|
||||||
|
.el-table .cell { padding: 0 4px; }
|
||||||
|
.el-table .el-table__cell { padding: 6px 0; }
|
||||||
|
.topic-card-list { display: block; margin: 0 -16px; }
|
||||||
|
.topic-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
.topic-card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.topic-card-title { font-size: 16px; font-weight: 600; color: #303133; flex: 1; margin-right: 8px; }
|
||||||
|
.topic-card-tags { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
|
||||||
|
.topic-card-meta {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #606266;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.topic-card-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
.topic-card-actions .el-button { flex: 1; min-width: 60px; }
|
||||||
|
.mobile-nav { display: flex; }
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -43,7 +85,7 @@
|
|||||||
<div class="navbar-content">
|
<div class="navbar-content">
|
||||||
<h1 class="navbar-title">宇之然内容创作平台 - 选题管理</h1>
|
<h1 class="navbar-title">宇之然内容创作平台 - 选题管理</h1>
|
||||||
<div class="navbar-user">
|
<div class="navbar-user">
|
||||||
<div class="user-info"><div class="avatar">{{ currentUser.username.charAt(0).toUpperCase() }}</div><span>{{ currentUser.username }}</span></div>
|
<div class="user-info"><div class="avatar">{{ currentUser.username ? currentUser.username.charAt(0).toUpperCase() : '?' }}</div><span>{{ currentUser.username }}</span></div>
|
||||||
<el-button type="danger" size="small" @click="handleLogout">退出</el-button>
|
<el-button type="danger" size="small" @click="handleLogout">退出</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -100,6 +142,32 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
<!-- 移动端卡片列表 -->
|
||||||
|
<div class="topic-card-list" v-if="filteredTopics && filteredTopics.length > 0">
|
||||||
|
<div v-for="topic in filteredTopics" :key="topic.id" class="topic-card">
|
||||||
|
<div class="topic-card-header">
|
||||||
|
<div class="topic-card-title">{{ topic.title }}</div>
|
||||||
|
<el-tag :type="getStatusType(topic.status)" size="small">{{ topic.status }}</el-tag>
|
||||||
|
</div>
|
||||||
|
<div class="topic-card-tags">
|
||||||
|
<el-tag size="small" type="info">{{ topic.field }}</el-tag>
|
||||||
|
<el-tag size="small" type="warning">合规{{ topic.compliance_score }}</el-tag>
|
||||||
|
</div>
|
||||||
|
<div class="topic-card-meta">
|
||||||
|
<div>创建: {{ formatDate(topic.created_at) }}</div>
|
||||||
|
<div>创作: {{ topic.generated_at ? formatDate(topic.generated_at) : '-' }}</div>
|
||||||
|
<div>发布: {{ topic.published_at ? formatDate(topic.published_at) : '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="topic-card-actions">
|
||||||
|
<el-button size="small" @click="openPreview(topic)" type="primary">预览</el-button>
|
||||||
|
<el-button size="small" type="success" :disabled="topic.status !== '待处理'" @click="createTopic(topic)">创作</el-button>
|
||||||
|
<el-button size="small" type="warning" :disabled="topic.status !== '待审查'" @click="optimizeTopic(topic)">审查</el-button>
|
||||||
|
<el-button v-if="topic.status === '待发布'" size="small" type="primary" @click="handlePublish(topic)">发布</el-button>
|
||||||
|
<el-button size="small" type="danger" @click="deleteTopic(topic.id)">删除</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@@ -113,12 +181,31 @@
|
|||||||
</div>
|
</div>
|
||||||
<script src="/static/vue/vue.global.js"></script>
|
<script src="/static/vue/vue.global.js"></script>
|
||||||
<script src="/static/element-plus/index.full.min.js"></script>
|
<script src="/static/element-plus/index.full.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const TopicsApp = {
|
const TopicsApp = {
|
||||||
data() { return { isLoggedIn: false, isAdmin: false, currentUser: { username: '' }, topics: [], filterStatus: '', selectedTopicIds: [], loadingTable: false } },
|
data() {
|
||||||
|
return {
|
||||||
|
currentPage: 'topics',
|
||||||
|
isLoggedIn: false,
|
||||||
|
isAdmin: false,
|
||||||
|
currentUser: { username: '' },
|
||||||
|
loadingTable: false,
|
||||||
|
selectedTopicIds: [],
|
||||||
|
filterStatus: '',
|
||||||
|
stats: { total: 0, pending: 0, review: 0, ready: 0, published: 0, today: 0 },
|
||||||
|
topics: []
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
filteredTopics() { if (!this.topics.length) return []; if (!this.filterStatus) return this.topics; return this.topics.filter(t => t.status === this.filterStatus); },
|
filteredTopics() {
|
||||||
countByStatus() { return (status) => this.topics.filter(t => t.status === status).length; }
|
if (!this.topics || !this.topics.length) { return []; }
|
||||||
|
if (!this.filterStatus) { return this.topics; }
|
||||||
|
return this.topics.filter(t => t.status === this.filterStatus);
|
||||||
|
},
|
||||||
|
countByStatus() {
|
||||||
|
return (status) => this.topics.filter(t => t.status === status).length;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchTopics() {
|
async fetchTopics() {
|
||||||
@@ -129,14 +216,17 @@
|
|||||||
if (!response.ok) throw new Error('获取失败');
|
if (!response.ok) throw new Error('获取失败');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.topics = data || [];
|
this.topics = data || [];
|
||||||
|
this.loadingTable = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('使用模拟数据');
|
console.log('获取选题失败,使用模拟数据');
|
||||||
|
this.$message.error('获取选题失败,使用模拟数据');
|
||||||
this.topics = [
|
this.topics = [
|
||||||
{ id: 'A01', title: '可持续发展趋势分析', field: '环保', status: '待处理', compliance_score: 85, created_at: '2026-04-27 10:30', generated_at: null, published_at: null },
|
{ id: 'A01', title: '可持续发展趋势分析', field: '环保', status: '待处理', compliance_score: 85, created_at: '2026-04-27 10:30', generated_at: null, published_at: null },
|
||||||
{ id: 'B02', title: 'AI 在内容创作中的应用', field: '科技', status: '待审查', compliance_score: 92, created_at: '2026-04-27 11:15', generated_at: '2026-04-27 11:45', published_at: null },
|
{ id: 'B02', title: 'AI 在内容创作中的应用', field: '科技', status: '待审查', compliance_score: 92, created_at: '2026-04-27 11:15', generated_at: '2026-04-27 11:45', published_at: null },
|
||||||
{ id: 'C03', title: '数字化转型案例研究', field: '商业', status: '待发布', compliance_score: 78, created_at: '2026-04-27 12:00', generated_at: '2026-04-27 12:30', published_at: '2026-04-27 13:00' }
|
{ id: 'C03', title: '数字化转型案例研究', field: '商业', status: '待发布', compliance_score: 78, created_at: '2026-04-27 12:00', generated_at: '2026-04-27 12:30', published_at: '2026-04-27 13:00' }
|
||||||
];
|
];
|
||||||
} finally { this.loadingTable = false; }
|
this.loadingTable = false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
refreshAll() { this.$message.info('执行批量刷新'); },
|
refreshAll() { this.$message.info('执行批量刷新'); },
|
||||||
async triggerGenerateSelected() {
|
async triggerGenerateSelected() {
|
||||||
@@ -170,15 +260,40 @@
|
|||||||
.then(async () => { this.$message.success('删除成功'); await this.fetchTopics(); }).catch(() => {});
|
.then(async () => { this.$message.success('删除成功'); await this.fetchTopics(); }).catch(() => {});
|
||||||
},
|
},
|
||||||
handleLogout() { localStorage.removeItem('authToken'); window.location.href = '/'; },
|
handleLogout() { localStorage.removeItem('authToken'); window.location.href = '/'; },
|
||||||
redirectToPage(page) { window.location.href = '/' + page; },
|
redirectToPage(page) { window.location.href = page.startsWith('/') ? page : '/' + page; },
|
||||||
formatDate(dateStr) { if (!dateStr) return '-'; return new Date(dateStr.replace(' ', 'T')).toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); }
|
formatDate(dateStr) {
|
||||||
|
if (!dateStr) return '-';
|
||||||
|
try {
|
||||||
|
return new Date(dateStr.replace(' ', 'T')).toLocaleString('zh-CN', {
|
||||||
|
year: 'numeric', month: '2-digit', day: '2-digit',
|
||||||
|
hour: '2-digit', minute: '2-digit'
|
||||||
|
});
|
||||||
|
} catch (e) { return dateStr; }
|
||||||
|
},
|
||||||
|
getStatusType(status) {
|
||||||
|
const map = { '待处理': 'warning', '待审查': 'danger', '待发布': 'success', '已发布': 'info' };
|
||||||
|
return map[status] || 'primary';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
console.log('[DEBUG] TopicsApp mounted');
|
||||||
const token = localStorage.getItem('authToken');
|
const token = localStorage.getItem('authToken');
|
||||||
|
console.log('[DEBUG] Token exists:', !!token);
|
||||||
if (!token) { window.location.href = '/'; return; }
|
if (!token) { window.location.href = '/'; return; }
|
||||||
|
// 解析 URL filter 参数
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const filter = urlParams.get('filter');
|
||||||
|
console.log('[DEBUG] URL filter:', filter);
|
||||||
|
if (filter) { this.filterStatus = filter; }
|
||||||
fetch('/api/auth/me', { headers: { 'Authorization': 'Bearer ' + token } })
|
fetch('/api/auth/me', { headers: { 'Authorization': 'Bearer ' + token } })
|
||||||
.then(response => response.ok ? response.json() : Promise.reject())
|
.then(response => response.ok ? response.json() : Promise.reject())
|
||||||
.then(data => { this.currentUser = data.user; this.isAdmin = data.user.role === 'admin'; this.isLoggedIn = true; this.fetchTopics(); })
|
.then(data => {
|
||||||
|
console.log('[DEBUG] Auth success, user:', data.user);
|
||||||
|
this.currentUser = data.user;
|
||||||
|
this.isAdmin = data.user.role === 'admin';
|
||||||
|
this.isLoggedIn = true;
|
||||||
|
this.fetchTopics();
|
||||||
|
})
|
||||||
.catch(() => { localStorage.removeItem('authToken'); window.location.href = '/'; });
|
.catch(() => { localStorage.removeItem('authToken'); window.location.href = '/'; });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -186,5 +301,6 @@
|
|||||||
app.use(ElementPlus);
|
app.use(ElementPlus);
|
||||||
app.mount('#app');
|
app.mount('#app');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -29,6 +29,41 @@
|
|||||||
.mobile-nav { display: flex; }
|
.mobile-nav { display: flex; }
|
||||||
.content-area { padding: 16px; padding-bottom: 80px; }
|
.content-area { padding: 16px; padding-bottom: 80px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* users.html 移动端优化 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.user-table { display: none; }
|
||||||
|
.user-card-list { display: block; margin: 0 -16px; }
|
||||||
|
.user-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
.user-card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.user-card-name { font-size: 16px; font-weight: 600; }
|
||||||
|
.user-card-meta {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #606266;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.user-card-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -56,7 +91,7 @@
|
|||||||
<h3 style="font-size: 18px; font-weight: 600;">用户列表</h3>
|
<h3 style="font-size: 18px; font-weight: 600;">用户列表</h3>
|
||||||
<el-button type="primary" @click="addUser">+ 新建用户</el-button>
|
<el-button type="primary" @click="addUser">+ 新建用户</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="users" stripe>
|
<el-table :data="users" stripe :cell-class-name="getMobileUserCellClass" class="user-table">
|
||||||
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||||||
<el-table-column prop="username" label="用户名"></el-table-column>
|
<el-table-column prop="username" label="用户名"></el-table-column>
|
||||||
<el-table-column prop="role" label="角色" width="100">
|
<el-table-column prop="role" label="角色" width="100">
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Collector 修复脚本
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
sys.path.insert(0, '/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/platform/backend')
|
sys.path.insert(0, '/root/openclaw-workspace/projects/yu-zhi-ran/platform/backend')
|
||||||
|
|
||||||
from app.models import Topic
|
from app.models import Topic
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ topics = [
|
|||||||
{"id":"D05","title":"科技与自然共生:如何用AI让阳台农场更'自然'","field":"科技人文交叉","format":"理念 + 实操方案","core_concept":"对比荷兰智能温室与中国人'回归原始'误区,实现技术隐形化(传感器+提醒)+ 自然反馈闭环 + 人工仪式感","audience_pain":"想用科技但又怕失去'自然感',追求矛盾","unique_angle":"技术与情感连接的平衡方案,AI只做幕后,人工保留仪式","priority":"高","priority_score":10,"total_score":48,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}
|
{"id":"D05","title":"科技与自然共生:如何用AI让阳台农场更'自然'","field":"科技人文交叉","format":"理念 + 实操方案","core_concept":"对比荷兰智能温室与中国人'回归原始'误区,实现技术隐形化(传感器+提醒)+ 自然反馈闭环 + 人工仪式感","audience_pain":"想用科技但又怕失去'自然感',追求矛盾","unique_angle":"技术与情感连接的平衡方案,AI只做幕后,人工保留仪式","priority":"高","priority_score":10,"total_score":48,"status":"待处理","cases":[],"source_file":"strategy/全球-本土比较研究与全新内容战略规划-2026-04-15.md","created_at":datetime.datetime.now().isoformat()}
|
||||||
]
|
]
|
||||||
|
|
||||||
with open(OUTPUT_FILE:= '/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/automation/data/sustainability_topics.json', 'w', encoding='utf-8') as f:
|
with open(OUTPUT_FILE:= '/root/openclaw-workspace/projects/yu-zhi-ran/automation/data/sustainability_topics.json', 'w', encoding='utf-8') as f:
|
||||||
json.dump(topics, f, ensure_ascii=False, indent=2)
|
json.dump(topics, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
print(f"✅ 已创建全新选题库:{len(topics)} 个选题")
|
print(f"✅ 已创建全新选题库:{len(topics)} 个选题")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, '/root/.openclaw/workspaces/yzr-yxl/projects/yu-zhi-ran/platform/backend')
|
sys.path.insert(0, '/root/openclaw-workspace/projects/yu-zhi-ran/platform/backend')
|
||||||
from app.core.generator import run_creator
|
from app.core.generator import run_creator
|
||||||
result = run_creator('A05')
|
result = run_creator('A05')
|
||||||
print('RESULT:', result)
|
print('RESULT:', result)
|
||||||
|
|||||||
Reference in New Issue
Block a user