This commit is contained in:
2026-06-26 11:11:25 +08:00
11 changed files with 234 additions and 1143 deletions
+2 -33
View File
@@ -1,5 +1,4 @@
import asyncio
import logging
from datetime import datetime, timezone
from sqlalchemy import select, update
@@ -15,42 +14,12 @@ from app.models.user_oauth_account import UserOAuthAccount
from app.models.pre_test_template import PreTestTemplate
from app.utils.id_gen import generate_id
from app.utils.douyinApi import DouyinApi
from app.utils.logger import get_logger
import os
import hashlib
import json
LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "logs")
os.makedirs(LOG_DIR, exist_ok=True)
logger = logging.getLogger("upload_queue")
logger.setLevel(logging.INFO)
class DailyRotatingFileHandler(logging.FileHandler):
def __init__(self, directory, encoding=None):
self.directory = directory
filename = self._get_log_filename()
super().__init__(filename, encoding=encoding)
def _get_log_filename(self):
return os.path.join(self.directory, f"upload_queue-{datetime.now(timezone.utc).strftime('%Y-%m-%d')}.log")
def emit(self, record):
current_filename = self._get_log_filename()
if self.baseFilename != current_filename:
self.close()
self.baseFilename = current_filename
self.stream = self._open()
super().emit(record)
if not logger.handlers:
handler = DailyRotatingFileHandler(LOG_DIR, encoding="utf-8")
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s", "%Y-%m-%d %H:%M:%S"))
logger.addHandler(handler)
logger = get_logger("upload_queue", "upload_queue")
douyin_api = DouyinApi()
#上传素材队列,处理上传素材的任务
@@ -1,7 +1,5 @@
from datetime import datetime, timezone
import asyncio
import os
import logging
import json
from sqlalchemy import select, update
@@ -11,38 +9,9 @@ from app.models.base import async_session
from app.models.resources_material import ResourcesMaterial
from app.models.user_oauth import UserOAuth
from app.utils.douyinApi import DouyinApi
from app.utils.logger import get_logger
LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "logs")
os.makedirs(LOG_DIR, exist_ok=True)
#前测结果和上传素材属于一种任务,放到一起日志里边
logger = logging.getLogger("upload_queue")
logger.setLevel(logging.INFO)
class DailyRotatingFileHandler(logging.FileHandler):
def __init__(self, directory, encoding=None):
self.directory = directory
filename = self._get_log_filename()
super().__init__(filename, encoding=encoding)
def _get_log_filename(self):
return os.path.join(self.directory, f"pre_test_result_task-{datetime.now(timezone.utc).strftime('%Y-%m-%d')}.log")
def emit(self, record):
current_filename = self._get_log_filename()
if self.baseFilename != current_filename:
self.close()
self.baseFilename = current_filename
self.stream = self._open()
super().emit(record)
if not logger.handlers:
handler = DailyRotatingFileHandler(LOG_DIR, encoding="utf-8")
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s", "%Y-%m-%d %H:%M:%S"))
logger.addHandler(handler)
logger = get_logger("pre_test_result_task", "pre_test_result_task")
douyin_api = DouyinApi()
#获取前测结果并更新数据库,计划任务,每2分钟执行一次
+2 -32
View File
@@ -2,9 +2,6 @@ from datetime import datetime, timedelta, timezone
import asyncio
import httpx
import json
import os
import logging
from logging.handlers import TimedRotatingFileHandler
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
@@ -14,37 +11,10 @@ from app.models.user_oauth_app import UserOAuthApp
from app.models.base import async_session
from app.config import settings
from app.utils.redis import get_redis
from app.utils.logger import get_logger
REDIS_KEY = "douyin:tokens"
LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "logs")
os.makedirs(LOG_DIR, exist_ok=True)
logger = logging.getLogger("token_refresh")
logger.setLevel(logging.INFO)
def get_log_filename():
return os.path.join(LOG_DIR, f"token_refresh-{datetime.now().strftime('%Y-%m-%d')}.log")
class DailyRotatingFileHandler(logging.FileHandler):
def __init__(self, directory, encoding=None):
self.directory = directory
filename = get_log_filename()
super().__init__(filename, encoding=encoding)
def emit(self, record):
current_filename = get_log_filename()
if self.baseFilename != current_filename:
self.close()
self.baseFilename = current_filename
self.stream = self._open()
super().emit(record)
handler = DailyRotatingFileHandler(LOG_DIR, encoding="utf-8")
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s", "%Y-%m-%d %H:%M:%S"))
logger.addHandler(handler)
logger = get_logger("token_refresh", "token_refresh")
+27 -5
View File
@@ -11,6 +11,9 @@ from app.models.user_oauth import UserOAuth
from app.models.user_oauth_app import UserOAuthApp
from app.models.base import async_session
from app.utils.redis import get_redis
from app.utils.logger import get_logger
logger = get_logger("douyin_request", "douyin_request")
class DouyinRequest:
@@ -244,8 +247,6 @@ class DouyinRequest:
await asyncio.sleep(i * 10)
continue
res = json.dumps(data) if 'data' in locals() else ''
options_log = {}
if options:
for key, value in options.items():
@@ -254,10 +255,31 @@ class DouyinRequest:
else:
options_log[key] = value
raise RuntimeError(
f'DouYin API request failed after 5 retries. '
f'url:{url};oauthId:{oauth_id};options:{json.dumps(options_log)};response:{res}'
res = json.dumps(data) if 'data' in locals() else ''
logger.error(
f'DouYin API request failed after {request_count} retries. '
f'url:{url};method:{method};oauth_id:{oauth_id};options:{json.dumps(options_log)};response:{res}'
)
if 'data' in locals() and data.get('code', 0) != 0:
raise ValueError(f'接口返回错误[code:{data.get("code", "接口编码")}]{data.get("message", "接口返回错误")}')
else:
raise ValueError('网络错误,稍后重试。')
# options_log = {}
# if options:
# for key, value in options.items():
# if key == 'files':
# options_log[key] = {k: (v[0], 'bytes_content', v[2]) for k, v in value.items()}
# else:
# options_log[key] = value
# raise RuntimeError(
# f'DouYin API request failed after 5 retries. '
# f'url:{url};oauthId:{oauth_id};options:{json.dumps(options_log)};response:{res}'
# )
# if code != 0:
# raise ValueError(f'response:{res}')
# 无token请求
async def request_with_context(
+49
View File
@@ -0,0 +1,49 @@
import os
import logging
from datetime import datetime
def get_logger(name: str, log_filename: str) -> logging.Logger:
"""
创建并配置一个每日滚动的日志记录器
Args:
name: 日志记录器名称
log_filename: 日志文件名(不含日期和扩展名)
Returns:
配置好的日志记录器对象
"""
logger = logging.getLogger(name)
logger.setLevel(logging.INFO)
if logger.handlers:
return logger
LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "logs")
os.makedirs(LOG_DIR, exist_ok=True)
class DailyRotatingFileHandler(logging.FileHandler):
def __init__(self, directory, filename_prefix, encoding=None):
self.directory = directory
self.filename_prefix = filename_prefix
filename = self._get_log_filename()
super().__init__(filename, encoding=encoding)
def _get_log_filename(self):
return os.path.join(self.directory, f"{self.filename_prefix}-{datetime.now().strftime('%Y-%m-%d')}.log")
def emit(self, record):
current_filename = self._get_log_filename()
if self.baseFilename != current_filename:
self.close()
self.baseFilename = current_filename
self.stream = self._open()
super().emit(record)
handler = DailyRotatingFileHandler(LOG_DIR, log_filename, encoding="utf-8")
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s", "%Y-%m-%d %H:%M:%S"))
logger.addHandler(handler)
return logger
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+36 -40
View File
@@ -1,41 +1,37 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<title>民众智创</title>
<script>
(function() {
var cached = localStorage.getItem('siteInfo');
if (cached) {
try {
var info = JSON.parse(cached);
if (info.siteName) {
document.title = info.siteName;
}
if (info.siteLogo) {
var link = document.querySelector('link[rel="icon"]');
if (link) {
link.href = info.siteLogo;
link.type = 'image/png';
}
}
} catch (e) {}
}
})();
</script>
<<<<<<< HEAD
<script type="module" crossorigin src="/assets/index-D9QoFfGP.js"></script>
=======
<script type="module" crossorigin src="/assets/index-WjS6rFiW.js"></script>
>>>>>>> 3b9e5fab104c33eca7e35adc1c6a4ff8ed9cbd60
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<title>民众智创</title>
<script>
(function() {
var cached = localStorage.getItem('siteInfo');
if (cached) {
try {
var info = JSON.parse(cached);
if (info.siteName) {
document.title = info.siteName;
}
if (info.siteLogo) {
var link = document.querySelector('link[rel="icon"]');
if (link) {
link.href = info.siteLogo;
link.type = 'image/png';
}
}
} catch (e) {}
}
})();
</script>
<script type="module" crossorigin src="/assets/index-Dm7vTAAt.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-eLRg4pQk.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
</head>
<body>
<div id="root"></div>
</body>
</html>
+3 -1
View File
@@ -1500,7 +1500,7 @@ const GeneratedRecord: React.FC = () => {
title: '授权账户角色',
dataIndex: 'accountRole',
key: 'accountRole',
width: 200,
width: 160,
render: (role: string) => {
const roleMap: Record<string, string> = {
ADVERTISER: '客户',
@@ -1548,10 +1548,12 @@ const GeneratedRecord: React.FC = () => {
}}
rowKey="id"
size="small"
scroll={{ x: 'max-content' }}
onRow={(record) => ({
onClick: () => {
const id = String(record.id);
setSelectedOauthItems({ value: id, label: String(record.accountUserid) });
setOauthSelectOpen(false);
},
style: {
cursor: 'pointer',
+7 -9
View File
@@ -35,10 +35,9 @@ const resourceTypeConfig: Record<string, { label: string; color: string }> = {
// 状态配置
const statusConfig: Record<string, { label: string; color: string }> = {
'1': { label: '待上传', color: 'orange' },
'2': { label: '上传中', color: 'processing' },
'3': { label: '上传成功', color: 'success' },
'4': { label: '上传失败', color: 'error' },
'FAILED': { label: '失败', color: 'error' },
'PENDING': { label: '处理中', color: 'processing' },
'SUCCESS': { label: '成功', color: 'success' },
};
interface MaterialResource {
@@ -233,11 +232,10 @@ const MaterialListPage: React.FC = () => {
dataIndex: 'status',
key: 'status',
width: 100,
render: (text: string) => <span style={{ color: '#64748b' }}>{text || '-'}</span>,
// render: (text: string) => {
// const config = statusConfig[text];
// return <Tag color={config?.color}>{config?.label || text}</Tag>;
// },
render: (text: string) => {
const config = statusConfig[text];
return <Tag color={config?.color}>{config?.label || text || '-'}</Tag>;
},
},
{
title: '前测结果',