修复系统与验证器

This commit is contained in:
wsb1224 2025-11-16 13:33:32 +08:00
parent 66bf8190a6
commit 73800eeaa7
20 changed files with 259 additions and 3280 deletions

2
.env
View File

@ -32,7 +32,7 @@ HOST=0.0.0.0
PORT=5000
# 文件上传配置
MAX_CONTENT_LENGTH=16777216
MAX_CONTENT_LENGTH=524288000
UPLOAD_FOLDER=static/uploads
# 日志配置

View File

@ -32,7 +32,7 @@ HOST=0.0.0.0
PORT=5000
# 文件上传配置
MAX_CONTENT_LENGTH=16777216
MAX_CONTENT_LENGTH=524288000
UPLOAD_FOLDER=static/uploads
# 日志配置

View File

@ -1,604 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KaMiXiTong API测试平台</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1, h2, h3 {
color: #333;
}
.api-section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
background-color: #fafafa;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input, select, textarea {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
button {
background-color: #007bff;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #0056b3;
}
.response {
margin-top: 15px;
padding: 15px;
background-color: #e9ecef;
border-radius: 4px;
white-space: pre-wrap;
font-family: 'Courier New', Courier, monospace;
}
.success {
background-color: #d4edda;
border-color: #c3e6cb;
color: #155724;
}
.error {
background-color: #f8d7da;
border-color: #f5c6cb;
color: #721c24;
}
.tabs {
display: flex;
margin-bottom: 20px;
}
.tab {
padding: 10px 20px;
background-color: #e9ecef;
cursor: pointer;
border: 1px solid #ddd;
border-bottom: none;
border-radius: 5px 5px 0 0;
margin-right: 5px;
}
.tab.active {
background-color: #007bff;
color: white;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
</style>
</head>
<body>
<div class="container">
<h1>KaMiXiTong API测试平台</h1>
<p>这是一个用于测试KaMiXiTong系统所有API接口的前端页面。</p>
<div class="tabs">
<div class="tab active" onclick="openTab('admin')">用户管理</div>
<div class="tab" onclick="openTab('ticket')">工单管理</div>
<div class="tab" onclick="openTab('license')">卡密管理</div>
<div class="tab" onclick="openTab('version')">版本管理</div>
<div class="tab" onclick="openTab('device')">设备管理</div>
<div class="tab" onclick="openTab('product')">产品管理</div>
</div>
<!-- 用户管理 -->
<div id="admin" class="tab-content active">
<div class="api-section">
<h2>创建管理员</h2>
<form id="createAdminForm">
<div class="form-group">
<label for="username">用户名:</label>
<input type="text" id="username" required>
</div>
<div class="form-group">
<label for="adminEmail">邮箱:</label>
<input type="email" id="adminEmail">
</div>
<div class="form-group">
<label for="password">密码:</label>
<input type="password" id="password" required>
</div>
<div class="form-group">
<label for="role">角色:</label>
<select id="role">
<option value="0">普通管理员</option>
<option value="1">超级管理员</option>
</select>
</div>
<div class="form-group">
<label for="adminStatus">状态:</label>
<select id="adminStatus">
<option value="1">正常</option>
<option value="0">禁用</option>
</select>
</div>
<button type="submit">创建管理员</button>
</form>
<div id="createAdminResponse" class="response"></div>
</div>
<div class="api-section">
<h2>获取管理员列表</h2>
<button onclick="getAdmins()">获取管理员列表</button>
<div id="getAdminsResponse" class="response"></div>
</div>
<div class="api-section">
<h2>更新管理员</h2>
<form id="updateAdminForm">
<div class="form-group">
<label for="updateAdminId">管理员ID:</label>
<input type="number" id="updateAdminId" required>
</div>
<div class="form-group">
<label for="updateUsername">用户名:</label>
<input type="text" id="updateUsername">
</div>
<div class="form-group">
<label for="updateAdminEmail">邮箱:</label>
<input type="email" id="updateAdminEmail">
</div>
<div class="form-group">
<label for="updatePassword">密码 (留空则不更新):</label>
<input type="password" id="updatePassword">
</div>
<div class="form-group">
<label for="updateRole">角色:</label>
<select id="updateRole">
<option value="">不更新</option>
<option value="0">普通管理员</option>
<option value="1">超级管理员</option>
</select>
</div>
<div class="form-group">
<label for="updateAdminStatus">状态:</label>
<select id="updateAdminStatus">
<option value="">不更新</option>
<option value="1">正常</option>
<option value="0">禁用</option>
</select>
</div>
<button type="submit">更新管理员</button>
</form>
<div id="updateAdminResponse" class="response"></div>
</div>
</div>
<!-- 工单管理 -->
<div id="ticket" class="tab-content">
<div class="api-section">
<h2>创建工单</h2>
<form id="createTicketForm">
<div class="form-group">
<label for="ticketTitle">标题:</label>
<input type="text" id="ticketTitle" required>
</div>
<div class="form-group">
<label for="productId">产品ID:</label>
<input type="text" id="productId" required>
</div>
<div class="form-group">
<label for="ticketDescription">描述:</label>
<textarea id="ticketDescription" required></textarea>
</div>
<div class="form-group">
<label for="priority">优先级:</label>
<select id="priority">
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
</select>
</div>
<button type="submit">创建工单</button>
</form>
<div id="createTicketResponse" class="response"></div>
</div>
<div class="api-section">
<h2>获取工单列表</h2>
<button onclick="getTickets()">获取工单列表</button>
<div id="getTicketsResponse" class="response"></div>
</div>
</div>
<!-- 卡密管理 -->
<div id="license" class="tab-content">
<div class="api-section">
<h2>生成卡密</h2>
<form id="generateLicenseForm">
<div class="form-group">
<label for="licenseProductId">产品ID:</label>
<input type="text" id="licenseProductId" required>
</div>
<div class="form-group">
<label for="count">生成数量:</label>
<input type="number" id="count" value="1" min="1" max="10000" required>
</div>
<div class="form-group">
<label for="licenseType">卡密类型:</label>
<select id="licenseType">
<option value="0">试用</option>
<option value="1" selected>正式</option>
</select>
</div>
<div class="form-group">
<label for="validDays">有效期(天):</label>
<input type="number" id="validDays" value="365" min="1" required>
</div>
<button type="submit">生成卡密</button>
</form>
<div id="generateLicenseResponse" class="response"></div>
</div>
<div class="api-section">
<h2>获取卡密列表</h2>
<button onclick="getLicenses()">获取卡密列表</button>
<div id="getLicensesResponse" class="response"></div>
</div>
</div>
<!-- 版本管理 -->
<div id="version" class="tab-content">
<div class="api-section">
<h2>创建版本</h2>
<form id="createVersionForm">
<div class="form-group">
<label for="versionProductId">产品ID:</label>
<input type="text" id="versionProductId" required>
</div>
<div class="form-group">
<label for="versionNum">版本号:</label>
<input type="text" id="versionNum" required>
</div>
<div class="form-group">
<label for="platform">平台:</label>
<input type="text" id="platform">
</div>
<div class="form-group">
<label for="description">描述:</label>
<textarea id="description"></textarea>
</div>
<button type="submit">创建版本</button>
</form>
<div id="createVersionResponse" class="response"></div>
</div>
<div class="api-section">
<h2>获取版本列表</h2>
<button onclick="getVersions()">获取版本列表</button>
<div id="getVersionsResponse" class="response"></div>
</div>
</div>
<!-- 设备管理 -->
<div id="device" class="tab-content">
<div class="api-section">
<h2>获取设备列表</h2>
<button onclick="getDevices()">获取设备列表</button>
<div id="getDevicesResponse" class="response"></div>
</div>
</div>
<!-- 产品管理 -->
<div id="product" class="tab-content">
<div class="api-section">
<h2>创建产品</h2>
<form id="createProductForm">
<div class="form-group">
<label for="productName">产品名称:</label>
<input type="text" id="productName" required>
</div>
<div class="form-group">
<label for="productDescription">描述:</label>
<textarea id="productDescription"></textarea>
</div>
<button type="submit">创建产品</button>
</form>
<div id="createProductResponse" class="response"></div>
</div>
<div class="api-section">
<h2>获取产品列表</h2>
<button onclick="getProducts()">获取产品列表</button>
<div id="getProductsResponse" class="response"></div>
</div>
</div>
</div>
<script>
// 基础URL (MySQL版本)
const BASE_URL = 'http://127.0.0.1:9004';
// 切换标签页
function openTab(tabName) {
// 隐藏所有标签页内容
const tabContents = document.getElementsByClassName('tab-content');
for (let i = 0; i < tabContents.length; i++) {
tabContents[i].classList.remove('active');
}
// 移除所有标签的活动状态
const tabs = document.getElementsByClassName('tab');
for (let i = 0; i < tabs.length; i++) {
tabs[i].classList.remove('active');
}
// 显示当前标签页并设置活动状态
document.getElementById(tabName).classList.add('active');
event.currentTarget.classList.add('active');
}
// 显示响应结果
function showResponse(elementId, data, isSuccess = true) {
const element = document.getElementById(elementId);
element.textContent = JSON.stringify(data, null, 2);
element.className = 'response ' + (isSuccess ? 'success' : 'error');
}
// 用户管理API
document.getElementById('createAdminForm').addEventListener('submit', async function(e) {
e.preventDefault();
const adminData = {
username: document.getElementById('username').value,
email: document.getElementById('adminEmail').value,
password: document.getElementById('password').value,
role: parseInt(document.getElementById('role').value),
status: parseInt(document.getElementById('adminStatus').value)
};
try {
const response = await fetch(`${BASE_URL}/admins`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(adminData)
});
const result = await response.json();
showResponse('createAdminResponse', result, response.ok);
} catch (error) {
showResponse('createAdminResponse', {error: error.message}, false);
}
});
async function getAdmins() {
try {
const response = await fetch(`${BASE_URL}/admins`);
const result = await response.json();
showResponse('getAdminsResponse', result, response.ok);
} catch (error) {
showResponse('getAdminsResponse', {error: error.message}, false);
}
}
document.getElementById('updateAdminForm').addEventListener('submit', async function(e) {
e.preventDefault();
const adminId = document.getElementById('updateAdminId').value;
const updateData = {};
const username = document.getElementById('updateUsername').value;
if (username) updateData.username = username;
const email = document.getElementById('updateAdminEmail').value;
if (email) updateData.email = email;
const password = document.getElementById('updatePassword').value;
if (password) updateData.password = password;
const role = document.getElementById('updateRole').value;
if (role !== '') updateData.role = parseInt(role);
const status = document.getElementById('updateAdminStatus').value;
if (status !== '') updateData.status = parseInt(status);
try {
const response = await fetch(`${BASE_URL}/admins/${adminId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(updateData)
});
const result = await response.json();
showResponse('updateAdminResponse', result, response.ok);
} catch (error) {
showResponse('updateAdminResponse', {error: error.message}, false);
}
});
// 工单管理API
document.getElementById('createTicketForm').addEventListener('submit', async function(e) {
e.preventDefault();
const ticketData = {
title: document.getElementById('ticketTitle').value,
product_id: document.getElementById('productId').value,
description: document.getElementById('ticketDescription').value,
priority: parseInt(document.getElementById('priority').value)
};
try {
const response = await fetch(`${BASE_URL}/tickets`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(ticketData)
});
const result = await response.json();
showResponse('createTicketResponse', result, response.ok);
} catch (error) {
showResponse('createTicketResponse', {error: error.message}, false);
}
});
async function getTickets() {
try {
const response = await fetch(`${BASE_URL}/tickets`);
const result = await response.json();
showResponse('getTicketsResponse', result, response.ok);
} catch (error) {
showResponse('getTicketsResponse', {error: error.message}, false);
}
}
// 卡密管理API
document.getElementById('generateLicenseForm').addEventListener('submit', async function(e) {
e.preventDefault();
const licenseData = {
product_id: document.getElementById('licenseProductId').value,
count: parseInt(document.getElementById('count').value),
type: parseInt(document.getElementById('licenseType').value),
valid_days: parseInt(document.getElementById('validDays').value)
};
try {
const response = await fetch(`${BASE_URL}/licenses`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(licenseData)
});
const result = await response.json();
showResponse('generateLicenseResponse', result, response.ok);
} catch (error) {
showResponse('generateLicenseResponse', {error: error.message}, false);
}
});
async function getLicenses() {
try {
const response = await fetch(`${BASE_URL}/licenses`);
const result = await response.json();
showResponse('getLicensesResponse', result, response.ok);
} catch (error) {
showResponse('getLicensesResponse', {error: error.message}, false);
}
}
// 版本管理API
document.getElementById('createVersionForm').addEventListener('submit', async function(e) {
e.preventDefault();
const versionData = {
product_id: document.getElementById('versionProductId').value,
version_num: document.getElementById('versionNum').value,
platform: document.getElementById('platform').value,
description: document.getElementById('description').value
};
try {
const response = await fetch(`${BASE_URL}/versions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(versionData)
});
const result = await response.json();
showResponse('createVersionResponse', result, response.ok);
} catch (error) {
showResponse('createVersionResponse', {error: error.message}, false);
}
});
async function getVersions() {
try {
const response = await fetch(`${BASE_URL}/versions`);
const result = await response.json();
showResponse('getVersionsResponse', result, response.ok);
} catch (error) {
showResponse('getVersionsResponse', {error: error.message}, false);
}
}
// 设备管理API
async function getDevices() {
try {
const response = await fetch(`${BASE_URL}/devices`);
const result = await response.json();
showResponse('getDevicesResponse', result, response.ok);
} catch (error) {
showResponse('getDevicesResponse', {error: error.message}, false);
}
}
// 产品管理API
document.getElementById('createProductForm').addEventListener('submit', async function(e) {
e.preventDefault();
const productData = {
product_name: document.getElementById('productName').value,
description: document.getElementById('productDescription').value
};
try {
const response = await fetch(`${BASE_URL}/products`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(productData)
});
const result = await response.json();
showResponse('createProductResponse', result, response.ok);
} catch (error) {
showResponse('createProductResponse', {error: error.message}, false);
}
});
async function getProducts() {
try {
const response = await fetch(`${BASE_URL}/products`);
const result = await response.json();
showResponse('getProductsResponse', result, response.ok);
} catch (error) {
showResponse('getProductsResponse', {error: error.message}, false);
}
}
</script>
</body>
</html>

View File

@ -1,821 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
FastAPI接口测试应用
提供所有管理功能的API接口测试页面
"""
import os
import sys
from datetime import datetime, timedelta
from typing import List, Optional
from pydantic import BaseModel
from fastapi import FastAPI, HTTPException, Depends, status
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime, Boolean, ForeignKey, func
from sqlalchemy.orm import declarative_base, sessionmaker, Session
# 添加项目根目录到Python路径
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
# 导入配置
from config import Config
# 数据库配置
DATABASE_URL = Config.SQLALCHEMY_DATABASE_URI
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# 创建FastAPI应用
app = FastAPI(
title="KaMiXiTong API测试平台",
description="软件授权管理系统的完整API接口测试平台",
version="1.0.0",
docs_url="/docs",
redoc_url="/redoc"
)
# 添加CORS中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 依赖项
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# ==================== 用户管理模型 ====================
class AdminBase(BaseModel):
username: str
email: Optional[str] = None
role: Optional[int] = 0 # 0=普通管理员, 1=超级管理员
status: Optional[int] = 1 # 0=禁用, 1=正常
class Config:
from_attributes = True
class AdminCreate(AdminBase):
password: str
class AdminUpdate(AdminBase):
password: Optional[str] = None
class AdminInDB(AdminBase):
admin_id: int
create_time: datetime
update_time: datetime
# ==================== 工单管理模型 ====================
class TicketBase(BaseModel):
title: str
product_id: str
description: str
priority: Optional[int] = 1 # 1=低, 2=中, 3=高
status: Optional[int] = 0 # 0=待处理, 1=处理中, 2=已解决, 3=已关闭
class Config:
from_attributes = True
class TicketCreate(TicketBase):
software_version: Optional[str] = None
machine_code: Optional[str] = None
license_key: Optional[str] = None
class TicketUpdate(TicketBase):
pass
class TicketInDB(TicketBase):
ticket_id: int
create_time: datetime
update_time: datetime
# ==================== 卡密管理模型 ====================
class LicenseBase(BaseModel):
product_id: str
type: int = 1 # 0=试用, 1=正式
status: Optional[int] = 0 # 0=未使用, 1=已使用, 2=已过期, 3=已禁用
valid_days: Optional[int] = 365
class Config:
from_attributes = True
class LicenseCreate(LicenseBase):
count: int = 1
prefix: Optional[str] = ""
length: Optional[int] = 32
class LicenseUpdate(LicenseBase):
pass
class LicenseInDB(LicenseBase):
license_id: int
license_key: str
create_time: datetime
update_time: datetime
expire_time: Optional[datetime] = None
# ==================== 版本管理模型 ====================
class VersionBase(BaseModel):
product_id: str
version_num: str
platform: Optional[str] = ""
description: Optional[str] = ""
update_log: Optional[str] = ""
download_url: Optional[str] = ""
file_hash: Optional[str] = ""
force_update: Optional[int] = 0
download_status: Optional[int] = 1 # 0=下架, 1=上架
min_license_version: Optional[str] = ""
publish_status: Optional[int] = 0 # 0=未发布, 1=已发布
class Config:
from_attributes = True
class VersionCreate(VersionBase):
publish_now: Optional[bool] = False
class VersionUpdate(VersionBase):
pass
class VersionInDB(VersionBase):
version_id: int
create_time: datetime
update_time: datetime
# ==================== 设备管理模型 ====================
class DeviceBase(BaseModel):
product_id: str
machine_code: str
software_version: Optional[str] = ""
status: Optional[int] = 1 # 0=禁用, 1=正常, 2=黑名单
class Config:
from_attributes = True
class DeviceCreate(DeviceBase):
license_key: Optional[str] = None
class DeviceUpdate(DeviceBase):
pass
class DeviceInDB(DeviceBase):
device_id: int
create_time: datetime
last_verify_time: Optional[datetime] = None
# ==================== 产品管理模型 ====================
class ProductBase(BaseModel):
product_name: str
description: Optional[str] = ""
status: Optional[int] = 1 # 0=禁用, 1=正常
class Config:
from_attributes = True
class ProductCreate(ProductBase):
product_id: Optional[str] = None
class ProductUpdate(ProductBase):
pass
class ProductInDB(ProductBase):
product_id: str
create_time: datetime
update_time: datetime
# ==================== 数据库模型 ====================
# 用户管理表
class DBAdmin(Base):
__tablename__ = "admin"
admin_id = Column(Integer, primary_key=True)
username = Column(String(32), unique=True, nullable=False)
password_hash = Column(String(128), nullable=False)
email = Column(String(128), nullable=True)
role = Column(Integer, default=0) # 0=普通管理员, 1=超级管理员
status = Column(Integer, default=1) # 0=禁用, 1=正常
create_time = Column(DateTime, default=datetime.utcnow)
update_time = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
is_deleted = Column(Integer, default=0) # 软删除标志
def __init__(self, **kwargs):
super(DBAdmin, self).__init__(**kwargs)
# 工单表
class DBTicket(Base):
__tablename__ = "ticket"
ticket_id = Column(Integer, primary_key=True)
title = Column(String(128), nullable=False)
product_id = Column(String(32), nullable=False)
software_version = Column(String(32), nullable=True)
machine_code = Column(String(64), nullable=True)
license_key = Column(String(64), nullable=True)
description = Column(Text, nullable=False)
priority = Column(Integer, default=1) # 1=低, 2=中, 3=高
status = Column(Integer, default=0) # 0=待处理, 1=处理中, 2=已解决, 3=已关闭
create_time = Column(DateTime, default=datetime.utcnow)
update_time = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def __init__(self, **kwargs):
super(DBTicket, self).__init__(**kwargs)
# 卡密表
class DBLicense(Base):
__tablename__ = "license"
license_id = Column(Integer, primary_key=True)
product_id = Column(String(32), nullable=False)
license_key = Column(String(64), unique=True, nullable=False)
type = Column(Integer, default=1) # 0=试用, 1=正式
status = Column(Integer, default=0) # 0=未使用, 1=已使用, 2=已过期, 3=已禁用
create_time = Column(DateTime, default=datetime.utcnow)
update_time = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
expire_time = Column(DateTime, nullable=True)
def __init__(self, **kwargs):
super(DBLicense, self).__init__(**kwargs)
# 版本表
class DBVersion(Base):
__tablename__ = "version"
version_id = Column(Integer, primary_key=True)
product_id = Column(String(32), nullable=False)
version_num = Column(String(32), nullable=False)
platform = Column(String(32), nullable=True)
description = Column(Text, nullable=True)
update_log = Column(Text, nullable=True)
download_url = Column(String(256), nullable=True)
file_hash = Column(String(64), nullable=True)
force_update = Column(Integer, default=0)
download_status = Column(Integer, default=1) # 0=下架, 1=上架
min_license_version = Column(String(32), nullable=True)
publish_status = Column(Integer, default=0) # 0=未发布, 1=已发布
create_time = Column(DateTime, default=datetime.utcnow)
update_time = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def __init__(self, **kwargs):
super(DBVersion, self).__init__(**kwargs)
# 设备表
class DBDevice(Base):
__tablename__ = "device"
device_id = Column(Integer, primary_key=True)
product_id = Column(String(32), nullable=False)
machine_code = Column(String(64), nullable=False)
software_version = Column(String(32), nullable=True)
status = Column(Integer, default=1) # 0=禁用, 1=正常, 2=黑名单
create_time = Column(DateTime, default=datetime.utcnow)
last_verify_time = Column(DateTime, nullable=True)
def __init__(self, **kwargs):
super(DBDevice, self).__init__(**kwargs)
# 产品表
class DBProduct(Base):
__tablename__ = "product"
product_id = Column(String(32), primary_key=True)
product_name = Column(String(64), nullable=False)
description = Column(Text, nullable=True)
status = Column(Integer, default=1) # 0=禁用, 1=正常
create_time = Column(DateTime, default=datetime.utcnow)
update_time = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def __init__(self, **kwargs):
super(DBProduct, self).__init__(**kwargs)
# ==================== 用户管理接口 ====================
@app.get("/")
async def root():
return {"message": "欢迎使用KaMiXiTong API测试平台", "version": "1.0.0"}
@app.get("/admins", response_model=List[AdminInDB])
async def get_admins(
skip: int = 0,
limit: int = 100,
keyword: Optional[str] = None,
role: Optional[int] = None,
status: Optional[int] = None,
db: Session = Depends(get_db)
):
"""获取管理员列表"""
query = db.query(DBAdmin).filter(DBAdmin.is_deleted == 0)
if keyword:
query = query.filter(DBAdmin.username.contains(keyword))
if role is not None:
query = query.filter(DBAdmin.role == role)
if status is not None:
query = query.filter(DBAdmin.status == status)
admins = query.offset(skip).limit(limit).all()
return admins
@app.post("/admins", response_model=AdminInDB)
async def create_admin(admin: AdminCreate, db: Session = Depends(get_db)):
"""创建管理员"""
# 检查用户名是否已存在
existing = db.query(DBAdmin).filter(
DBAdmin.username == admin.username,
DBAdmin.is_deleted == 0
).first()
if existing:
raise HTTPException(status_code=400, detail="用户名已存在")
# 创建管理员(简化密码处理)
db_admin = DBAdmin(
username=admin.username,
email=admin.email,
role=admin.role,
status=admin.status,
password_hash=f"hashed_{admin.password}" # 简化处理
)
db.add(db_admin)
db.commit()
db.refresh(db_admin)
return db_admin
@app.get("/admins/{admin_id}", response_model=AdminInDB)
async def get_admin(admin_id: int, db: Session = Depends(get_db)):
"""获取管理员详情"""
admin = db.query(DBAdmin).filter(
DBAdmin.admin_id == admin_id,
DBAdmin.is_deleted == 0
).first()
if not admin:
raise HTTPException(status_code=404, detail="管理员不存在")
return admin
@app.put("/admins/{admin_id}", response_model=AdminInDB)
async def update_admin(admin_id: int, admin: AdminUpdate, db: Session = Depends(get_db)):
"""更新管理员"""
db_admin = db.query(DBAdmin).filter(
DBAdmin.admin_id == admin_id,
DBAdmin.is_deleted == 0
).first()
if not db_admin:
raise HTTPException(status_code=404, detail="管理员不存在")
# 更新字段
if admin.username and admin.username != db_admin.username:
# 检查新用户名是否已存在
existing = db.query(DBAdmin).filter(
DBAdmin.username == admin.username,
DBAdmin.admin_id != admin_id,
DBAdmin.is_deleted == 0
).first()
if existing:
raise HTTPException(status_code=400, detail="用户名已存在")
db_admin.username = admin.username
if admin.email is not None:
db_admin.email = admin.email
if admin.role is not None:
db_admin.role = admin.role
if admin.status is not None:
db_admin.status = admin.status
if admin.password:
db_admin.password_hash = f"hashed_{admin.password}" # 简化处理
db.commit()
db.refresh(db_admin)
return db_admin
@app.delete("/admins/{admin_id}")
async def delete_admin(admin_id: int, db: Session = Depends(get_db)):
"""删除管理员(软删除)"""
db_admin = db.query(DBAdmin).filter(
DBAdmin.admin_id == admin_id,
DBAdmin.is_deleted == 0
).first()
if not db_admin:
raise HTTPException(status_code=404, detail="管理员不存在")
db_admin.is_deleted = 1
db.commit()
return {"message": "管理员删除成功"}
@app.post("/admins/{admin_id}/toggle-status")
async def toggle_admin_status(admin_id: int, db: Session = Depends(get_db)):
"""切换管理员状态"""
db_admin = db.query(DBAdmin).filter(
DBAdmin.admin_id == admin_id,
DBAdmin.is_deleted == 0
).first()
if not db_admin:
raise HTTPException(status_code=404, detail="管理员不存在")
db_admin.status = 0 if db_admin.status == 1 else 1
db.commit()
status_name = "正常" if db_admin.status == 1 else "禁用"
action = "启用" if db_admin.status == 1 else "禁用"
return {"message": f"管理员已{action}", "status": db_admin.status, "status_name": status_name}
# ==================== 工单管理接口 ====================
@app.get("/tickets", response_model=List[TicketInDB])
async def get_tickets(
skip: int = 0,
limit: int = 100,
status: Optional[int] = None,
priority: Optional[int] = None,
product_id: Optional[str] = None,
db: Session = Depends(get_db)
):
"""获取工单列表"""
query = db.query(DBTicket)
if status is not None:
query = query.filter(DBTicket.status == status)
if priority is not None:
query = query.filter(DBTicket.priority == priority)
if product_id:
query = query.filter(DBTicket.product_id == product_id)
query = query.order_by(DBTicket.create_time.desc())
tickets = query.offset(skip).limit(limit).all()
return tickets
@app.post("/tickets", response_model=TicketInDB)
async def create_ticket(ticket: TicketCreate, db: Session = Depends(get_db)):
"""创建工单"""
# 验证产品存在(简化处理)
db_ticket = DBTicket(**ticket.model_dump())
db.add(db_ticket)
db.commit()
db.refresh(db_ticket)
return db_ticket
@app.put("/tickets/batch/status")
async def batch_update_ticket_status(
ticket_ids: List[int],
status: int,
remark: Optional[str] = None,
db: Session = Depends(get_db)
):
"""批量更新工单状态"""
if status not in [0, 1, 2, 3]:
raise HTTPException(status_code=400, detail="无效的状态值")
# 查找所有要更新的工单
tickets = db.query(DBTicket).filter(DBTicket.ticket_id.in_(ticket_ids)).all()
if len(tickets) != len(ticket_ids):
found_ids = [t.ticket_id for t in tickets]
missing_ids = [tid for tid in ticket_ids if tid not in found_ids]
raise HTTPException(status_code=404, detail=f"以下工单不存在: {', '.join(map(str, missing_ids))}")
# 批量更新工单状态
for ticket in tickets:
ticket.status = status
ticket.update_time = datetime.utcnow()
db.commit()
status_names = {0: '待处理', 1: '处理中', 2: '已解决', 3: '已关闭'}
status_name = status_names.get(status, '未知')
return {"message": f"成功将 {len(tickets)} 个工单状态更新为{status_name}"}
# ==================== 卡密管理接口 ====================
@app.get("/licenses", response_model=List[LicenseInDB])
async def get_licenses(
skip: int = 0,
limit: int = 100,
product_id: Optional[str] = None,
status: Optional[int] = None,
license_type: Optional[int] = None,
keyword: Optional[str] = None,
db: Session = Depends(get_db)
):
"""获取卡密列表"""
query = db.query(DBLicense)
if product_id:
query = query.filter(DBLicense.product_id == product_id)
if status is not None:
query = query.filter(DBLicense.status == status)
if license_type is not None:
query = query.filter(DBLicense.type == license_type)
if keyword:
query = query.filter(func.lower(DBLicense.license_key).like(f"%{keyword.lower()}%"))
query = query.order_by(DBLicense.create_time.desc())
licenses = query.offset(skip).limit(limit).all()
return licenses
@app.post("/licenses", response_model=dict)
async def generate_licenses(license: LicenseCreate, db: Session = Depends(get_db)):
"""批量生成卡密"""
# 验证参数
if license.count < 1 or license.count > 10000:
raise HTTPException(status_code=400, detail="生成数量必须在1-10000之间")
if license.length < 16 or license.length > 35:
raise HTTPException(status_code=400, detail="卡密长度必须在16-35之间")
# 试用卡密最大有效期限制
if license.type == 0 and license.valid_days and license.valid_days > 90:
raise HTTPException(status_code=400, detail="试用卡密有效期不能超过90天")
# 生成卡密(简化处理)
import secrets
import string
licenses = []
characters = string.ascii_uppercase + string.digits
for i in range(license.count):
# 生成卡密
key = license.prefix + ''.join(secrets.choice(characters) for _ in range(license.length - len(license.prefix)))
# 确保卡密唯一
max_attempts = 10
for attempt in range(max_attempts):
existing = db.query(DBLicense).filter(DBLicense.license_key == key).first()
if not existing:
break
key = license.prefix + ''.join(secrets.choice(characters) for _ in range(license.length - len(license.prefix)))
else:
raise HTTPException(status_code=500, detail="无法生成唯一的卡密,请稍后重试")
# 计算过期时间
expire_time = None
if license.valid_days:
expire_time = datetime.utcnow() + timedelta(days=license.valid_days)
# 创建卡密对象
db_license = DBLicense(
product_id=license.product_id,
license_key=key,
type=license.type,
status=0, # 未使用
expire_time=expire_time
)
licenses.append(db_license)
# 批量保存
db.add_all(licenses)
db.commit()
# 格式化结果
license_data = []
for db_license in licenses:
db.refresh(db_license)
license_data.append(LicenseInDB.model_validate(db_license))
return {
"message": f"成功生成 {license.count} 个卡密",
"licenses": license_data,
"count": len(licenses)
}
# ==================== 版本管理接口 ====================
@app.get("/versions", response_model=List[VersionInDB])
async def get_versions(
skip: int = 0,
limit: int = 100,
product_id: Optional[str] = None,
publish_status: Optional[int] = None,
db: Session = Depends(get_db)
):
"""获取版本列表"""
query = db.query(DBVersion)
if product_id:
query = query.filter(DBVersion.product_id == product_id)
if publish_status is not None:
query = query.filter(DBVersion.publish_status == publish_status)
query = query.order_by(DBVersion.create_time.desc())
versions = query.offset(skip).limit(limit).all()
return versions
@app.post("/versions", response_model=VersionInDB)
async def create_version(version: VersionCreate, db: Session = Depends(get_db)):
"""创建版本"""
# 验证产品存在(简化处理)
if not version.product_id or not version.version_num:
raise HTTPException(status_code=400, detail="缺少必要参数")
# 检查版本号是否重复
existing = db.query(DBVersion).filter(
DBVersion.product_id == version.product_id,
DBVersion.version_num == version.version_num
).first()
if existing:
raise HTTPException(status_code=400, detail="版本号已存在")
# 创建版本
db_version = DBVersion(**version.model_dump(exclude={'publish_now'}))
db.add(db_version)
db.commit()
db.refresh(db_version)
# 如果选择了立即发布,则发布版本
if version.publish_now:
db_version.publish_status = 1
db.commit()
db.refresh(db_version)
return db_version
@app.post("/versions/{version_id}/publish")
async def publish_version(version_id: int, db: Session = Depends(get_db)):
"""发布版本"""
version = db.query(DBVersion).filter(DBVersion.version_id == version_id).first()
if not version:
raise HTTPException(status_code=404, detail="版本不存在")
version.publish_status = 1
version.update_time = datetime.utcnow()
db.commit()
db.refresh(version)
return {"message": "版本发布成功", "version": VersionInDB.model_validate(version)}
# ==================== 设备管理接口 ====================
@app.get("/devices", response_model=List[DeviceInDB])
async def get_devices(
skip: int = 0,
limit: int = 100,
product_id: Optional[str] = None,
software_version: Optional[str] = None,
status: Optional[int] = None,
keyword: Optional[str] = None,
db: Session = Depends(get_db)
):
"""获取设备列表"""
query = db.query(DBDevice)
if product_id:
query = query.filter(DBDevice.product_id == product_id)
if software_version:
query = query.filter(DBDevice.software_version == software_version)
if status is not None:
query = query.filter(DBDevice.status == status)
if keyword:
query = query.filter(DBDevice.machine_code.contains(keyword))
query = query.order_by(DBDevice.last_verify_time.desc())
devices = query.offset(skip).limit(limit).all()
return devices
@app.put("/devices/{device_id}/status")
async def update_device_status(device_id: int, status: int, db: Session = Depends(get_db)):
"""更新设备状态"""
if status not in [0, 1, 2]:
raise HTTPException(status_code=400, detail="无效的状态值")
device = db.query(DBDevice).filter(DBDevice.device_id == device_id).first()
if not device:
raise HTTPException(status_code=404, detail="设备不存在")
device.status = status
device.last_verify_time = datetime.utcnow()
db.commit()
db.refresh(device)
return {"message": "设备状态更新成功", "device": DeviceInDB.model_validate(device)}
@app.delete("/devices/{device_id}")
async def delete_device(device_id: int, db: Session = Depends(get_db)):
"""删除设备"""
device = db.query(DBDevice).filter(DBDevice.device_id == device_id).first()
if not device:
raise HTTPException(status_code=404, detail="设备不存在")
db.delete(device)
db.commit()
return {"message": "设备删除成功"}
@app.delete("/devices/batch")
async def batch_delete_devices(device_ids: List[int], db: Session = Depends(get_db)):
"""批量删除设备"""
# 查找所有要删除的设备
devices = db.query(DBDevice).filter(DBDevice.device_id.in_(device_ids)).all()
if len(devices) != len(device_ids):
found_ids = [d.device_id for d in devices]
missing_ids = [did for did in device_ids if did not in found_ids]
raise HTTPException(status_code=404, detail=f"以下设备不存在: {', '.join(map(str, missing_ids))}")
# 批量删除设备
for device in devices:
db.delete(device)
db.commit()
return {"message": f"成功删除 {len(devices)} 个设备"}
# ==================== 产品管理接口 ====================
@app.get("/products", response_model=List[ProductInDB])
async def get_products(
skip: int = 0,
limit: int = 100,
keyword: Optional[str] = None,
db: Session = Depends(get_db)
):
"""获取产品列表"""
query = db.query(DBProduct)
if keyword:
query = query.filter(
DBProduct.product_name.like(f"%{keyword}%") |
DBProduct.description.like(f"%{keyword}%")
)
query = query.order_by(DBProduct.create_time.desc())
products = query.offset(skip).limit(limit).all()
return products
@app.post("/products", response_model=ProductInDB)
async def create_product(product: ProductCreate, db: Session = Depends(get_db)):
"""创建产品"""
if not product.product_name.strip():
raise HTTPException(status_code=400, detail="产品名称不能为空")
# 检查自定义ID是否重复
if product.product_id:
existing = db.query(DBProduct).filter(DBProduct.product_id == product.product_id).first()
if existing:
raise HTTPException(status_code=400, detail="产品ID已存在")
# 创建产品
import uuid
product_id = product.product_id if product.product_id else f"PROD_{uuid.uuid4().hex[:8]}".upper()
db_product = DBProduct(
product_id=product_id,
product_name=product.product_name,
description=product.description,
status=product.status
)
db.add(db_product)
db.commit()
db.refresh(db_product)
return db_product
@app.get("/products/{product_id}", response_model=ProductInDB)
async def get_product(product_id: str, db: Session = Depends(get_db)):
"""获取产品详情"""
product = db.query(DBProduct).filter(DBProduct.product_id == product_id).first()
if not product:
raise HTTPException(status_code=404, detail="产品不存在")
return product
@app.put("/products/{product_id}", response_model=ProductInDB)
async def update_product(product_id: str, product: ProductUpdate, db: Session = Depends(get_db)):
"""更新产品"""
db_product = db.query(DBProduct).filter(DBProduct.product_id == product_id).first()
if not db_product:
raise HTTPException(status_code=404, detail="产品不存在")
# 更新字段
if product.product_name is not None:
db_product.product_name = product.product_name
if product.description is not None:
db_product.description = product.description
if product.status is not None:
db_product.status = product.status
db_product.update_time = datetime.utcnow()
db.commit()
db.refresh(db_product)
return db_product
@app.delete("/products/{product_id}")
async def delete_product(product_id: str, db: Session = Depends(get_db)):
"""删除产品"""
product = db.query(DBProduct).filter(DBProduct.product_id == product_id).first()
if not product:
raise HTTPException(status_code=404, detail="产品不存在")
db.delete(product)
db.commit()
return {"message": "产品删除成功"}
if __name__ == "__main__":
import uvicorn
# 使用127.0.0.1而不是0.0.0.0来避免权限问题
uvicorn.run(app, host="127.0.0.1", port=9003, log_level="info")

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
from datetime import datetime
from app import db
import json
class AuditLog(db.Model):
"""审计日志模型"""
@ -23,6 +24,14 @@ class AuditLog(db.Model):
def to_dict(self):
"""转换为字典"""
# 解析details字段中的JSON字符串
details_data = None
if self.details:
try:
details_data = json.loads(self.details)
except (json.JSONDecodeError, TypeError):
details_data = self.details # 如果解析失败,返回原始字符串
return {
'log_id': self.log_id,
'admin_id': self.admin_id,
@ -30,7 +39,7 @@ class AuditLog(db.Model):
'action': self.action,
'target_type': self.target_type,
'target_id': self.target_id,
'details': self.details,
'details': details_data,
'ip_address': self.ip_address,
'user_agent': self.user_agent,
'create_time': self.create_time.strftime('%Y-%m-%d %H:%M:%S') if self.create_time else None
@ -41,12 +50,20 @@ class AuditLog(db.Model):
"""记录审计日志"""
from flask import current_app
try:
# 将details字典序列化为JSON字符串
details_str = None
if details is not None:
if isinstance(details, dict):
details_str = json.dumps(details, ensure_ascii=False)
else:
details_str = str(details)
log = AuditLog(
admin_id=admin_id,
action=action,
target_type=target_type,
target_id=target_id,
details=details,
details=details_str,
ip_address=ip_address,
user_agent=user_agent
)

View File

@ -146,7 +146,7 @@ class AuthValidator:
def __init__(self,
software_id: str,
api_url: str = "http://localhost:5000/api/v1",
secret_key: str = "default-secret-key",
secret_key: str = "taiyi1224",
cache_days: int = 7,
timeout: int = 3,
gui_mode: bool = False):
@ -228,10 +228,11 @@ class AuthValidator:
return ""
def _validate_license_format(self, license_key: str) -> bool:
"""验证卡密格式(支持XXXX-XXXX-XXXX-XXXX格式"""
"""验证卡密格式(与服务端保持一致"""
if not license_key:
return False
# 去除空格和制表符,并转为大写
license_key = license_key.strip().replace(' ', '').replace('\t', '').upper()
# 检查是否为XXXX-XXXX-XXXX-XXXX格式
@ -242,8 +243,8 @@ class AuthValidator:
# 检查所有字符是否为大写字母或数字
combined = ''.join(parts)
if len(combined) == 32:
import re
pattern = r'^[A-Z0-9]+$'
import re
return bool(re.match(pattern, combined))
return False
else:
@ -252,8 +253,8 @@ class AuthValidator:
return False
# 检查字符(只允许大写字母、数字和下划线)
import re
pattern = r'^[A-Z0-9_]+$'
import re
return bool(re.match(pattern, license_key))
def _input_license_key(self) -> str:
@ -406,117 +407,55 @@ class AuthValidator:
max_attempts = 3 # 最多尝试3次
for attempt in range(max_attempts):
# 输入卡密
# 获取卡密
license_key = self._input_license_key()
if not license_key:
self._show_message("验证取消", "未输入卡密,程序退出", True)
self._show_message("验证取消", "用户取消了验证操作")
return False
# 验证卡密格式
if not self._validate_license_format(license_key):
self._show_message("格式错误", "卡密格式错误,请检查后重新输入", True)
self._show_message("格式错误", "卡密格式不正确,请重新输入", True)
continue
# 在线验证
success, message, auth_info = self._online_verify(license_key)
if success and auth_info:
# 验证成功,缓存授权信息
if success:
# 缓存授权信息
if auth_info:
self._cache_auth_info(auth_info)
# 检查是否需要更新
force_update = auth_info.get('force_update', False)
download_url = auth_info.get('download_url')
new_version = auth_info.get('new_version')
if force_update and download_url:
self._show_message("需要更新", f"发现新版本 {new_version}\n请下载更新后重新启动程序", True)
# 尝试打开下载链接
try:
import webbrowser
webbrowser.open(download_url)
except:
pass
return False
self._show_message("验证成功", f"授权验证成功!\n卡密: {license_key}\n有效期至: {auth_info.get('expire_time', '永久')}")
self._show_message("验证成功", message)
return True
else:
# 验证失败
# 记录失败尝试
self.failed_attempts += 1
self.last_attempt_time = datetime.utcnow()
if self.failed_attempts >= 5: # 失败5次锁定
self._lock_account()
if self.failed_attempts >= 3:
self._lock_account(10) # 锁定10分钟
self._show_message("验证失败", self._get_lock_message(), True)
return False
self._show_message("验证失败", f"验证失败: {message}\n剩余尝试次数: {5 - self.failed_attempts}", True)
# 如果不是最后一次尝试,询问是否继续
if attempt < max_attempts - 1:
if self.gui_mode:
try:
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
root.withdraw()
result = messagebox.askyesno("继续验证", "是否继续输入卡密验证?")
root.destroy()
if not result:
return False
except ImportError:
continue
else:
remaining_attempts = 3 - self.failed_attempts
self._show_message(
"验证失败",
f"{message}\n\n剩余尝试次数: {remaining_attempts}",
True
)
continue
else:
# 所有尝试都失败
self._show_message("验证失败", "已达到最大尝试次数", True)
return False
return False
def get_software_info(self) -> Optional[Dict[str, Any]]:
"""获取软件信息"""
try:
url = f"{self.api_url}/software/info"
params = {"software_id": self.software_id}
response = requests.get(url, params=params, timeout=self.timeout)
if response.status_code == 200:
result = response.json()
if result.get('success'):
return result.get('data')
except Exception:
pass
return None
def clear_cache(self):
"""清除本地缓存"""
self.cache.clear_cache(self.software_id)
# 删除机器码缓存文件
try:
if os.path.exists(".machine_code"):
os.remove(".machine_code")
except Exception:
pass
# 便捷函数
def validate_license(software_id: str, **kwargs) -> bool:
def get_auth_info(self) -> Optional[Dict[str, Any]]:
"""
便捷的验证函数
Args:
software_id: 软件ID
**kwargs: 其他参数api_url, secret_key, cache_days, timeout, gui_mode
获取当前授权信息
Returns:
bool: 验证是否成功
Optional[Dict[str, Any]]: 授权信息
"""
validator = AuthValidator(software_id, **kwargs)
return validator.validate()
return self.cache.get_auth_info(self.software_id)
def get_machine_code() -> str:
"""获取当前机器码"""
return MachineCodeGenerator.generate()
def clear_auth_cache(self):
"""清除授权缓存"""
self.cache.clear_cache(self.software_id)

View File

@ -1,40 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
检查数据库中的产品数据
"""
import os
import sys
# 添加项目根目录到Python路径
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
# 尝试加载.env文件
try:
from dotenv import load_dotenv
if load_dotenv():
print("成功加载.env文件")
else:
print("未找到或无法加载.env文件")
except ImportError:
print("python-dotenv未安装跳过.env文件加载")
from app import create_app, db
from app.models import Product
# 创建应用实例
app = create_app()
with app.app_context():
print("数据库URI:", app.config['SQLALCHEMY_DATABASE_URI'])
total_products = Product.query.count()
print(f"产品总数: {total_products}")
if total_products > 0:
print("产品列表:")
products = Product.query.all()
for product in products:
print(f" - ID: {product.product_id}, 名称: {product.product_name}, 状态: {product.status}")
else:
print("数据库中没有产品数据")

View File

@ -1,74 +0,0 @@
import sqlite3
import os
def check_audit_logs():
"""检查审计日志表"""
try:
# 连接到数据库
if os.path.exists('instance/kamaxitong.db'):
conn = sqlite3.connect('instance/kamaxitong.db')
cursor = conn.cursor()
# 查询审计日志表
print("=== 查询审计日志表 ===")
cursor.execute("SELECT * FROM audit_log ORDER BY create_time DESC LIMIT 10")
rows = cursor.fetchall()
if rows:
print(f"找到 {len(rows)} 条审计日志记录:")
# 获取列名
column_names = [description[0] for description in cursor.description]
print("列名:", column_names)
for row in rows:
print(row)
else:
print("审计日志表为空")
conn.close()
else:
print("数据库文件不存在")
except Exception as e:
print(f"检查审计日志时出现错误: {e}")
def check_log_file():
"""检查日志文件"""
try:
print("\n=== 检查日志文件 ===")
if os.path.exists('logs/kamaxitong.log'):
# 以二进制模式读取文件
with open('logs/kamaxitong.log', 'rb') as f:
content = f.read()
print(f"日志文件大小: {len(content)} 字节")
# 尝试以不同编码读取
try:
text_content = content.decode('utf-8')
lines = text_content.split('\n')
print(f"日志文件行数: {len(lines)}")
print("最后10行:")
for line in lines[-10:]:
if line.strip():
print(line.strip())
except UnicodeDecodeError:
# 尝试其他编码
try:
text_content = content.decode('gbk')
lines = text_content.split('\n')
print(f"日志文件行数: {len(lines)} (GBK编码)")
print("最后10行:")
for line in lines[-10:]:
if line.strip():
print(line.strip())
except UnicodeDecodeError:
print("无法解码日志文件内容")
else:
print("日志文件不存在")
except Exception as e:
print(f"检查日志文件时出现错误: {e}")
if __name__ == "__main__":
print("检查日志系统...")
check_audit_logs()
check_log_file()

View File

@ -1,15 +0,0 @@
import os
os.environ.setdefault('FLASK_CONFIG', 'development')
from app import create_app, db
from app.models import Product
app = create_app()
with app.app_context():
products = Product.query.all()
print('Total products:', len(products))
print('Product names:', [p.product_name for p in products])
print('Product details:')
for p in products:
print(f' ID: {p.product_id}, Name: {p.product_name}, Status: {p.status}')

Binary file not shown.

View File

@ -1,80 +1,51 @@
2025-11-15 21:43:14,795 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:43:16,011 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:47:51,654 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:47:58,940 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:52:14,483 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:52:15,836 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:53:12,767 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:53:12,928 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:55:02,780 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:55:05,971 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:56:57,235 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:56:57,396 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:00:51,287 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:02:34,407 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:02:36,353 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:03:17,696 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:03:18,658 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:05:58,479 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:05:58,767 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:12:33,295 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:12:34,640 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:17,117 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:17,190 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:18,245 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:24,345 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:24,378 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:24,686 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:30,459 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:30,476 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:30,487 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:35,024 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:35,074 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:35,227 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:43,938 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:44,004 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:44,004 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:55,395 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:55,501 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:56,055 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:00,950 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:01,093 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:01,290 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:10,768 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:12,443 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:13,140 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:22,104 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:22,684 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:22,758 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:36,038 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:37,583 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:37,723 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:55,634 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:55,694 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:55,725 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:05,643 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:05,813 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:06,131 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:34,892 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:34,916 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:35,168 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:52,773 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:52,821 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:53,293 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:18:58,174 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:18:59,209 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:20:36,569 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'old\': {\'email\': "\'2339117167@qq.com\'", \'role\': \'1\', \'status\': \'1\'}, \'new\': {\'em\' at line 1')
2025-11-16 13:06:04,834 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:06:06,705 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:06:36,685 INFO: 开始创建版本 [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:98]
2025-11-16 13:06:36,685 INFO: 请求的Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBaWqjoVX0KdrVN1Z [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:99]
2025-11-16 13:06:36,685 INFO: 请求方法: POST [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:100]
2025-11-16 13:06:36,686 INFO: 请求URL: http://127.0.0.1:5000/api/v1/versions [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:101]
2025-11-16 13:06:36,690 INFO: 请求头: {'Host': '127.0.0.1:5000', 'Connection': 'keep-alive', 'Content-Length': '769', 'Sec-Ch-Ua-Platform': '"Windows"', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'Sec-Ch-Ua': '"Chromium";v="142", "Microsoft Edge";v="142", "Not_A Brand";v="99"', 'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryBaWqjoVX0KdrVN1Z', 'Sec-Ch-Ua-Mobile': '?0', 'Accept': '*/*', 'Origin': 'http://127.0.0.1:5000', 'Sec-Fetch-Site': 'same-origin', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Dest': 'empty', 'Referer': 'http://127.0.0.1:5000/versions/create', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 'Cookie': 'remember_token=1|ae366cbb6a7c117a69a287f322b91e6d75e14efd338ed4249fe139a40620856246a057db8c7c1df9883347210e17f379727e0d28d269d0002fc5126ec50d83d8; session=eyJfZnJlc2giOmZhbHNlLCJfdXNlcl9pZCI6IjEifQ.aRlGfA.q1DLjLrFgNZLvNT_ChqsVKj_Uyc'} [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:102]
2025-11-16 13:06:36,690 INFO: 处理表单数据请求 [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:106]
2025-11-16 13:06:36,691 INFO: 收到的参数: product_id=ArticleReplace, version_num=1.0 [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:141]
2025-11-16 13:06:36,691 INFO: 验证产品是否存在: product_id=ArticleReplace [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:147]
2025-11-16 13:06:36,691 INFO: 执行产品查询... [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:149]
2025-11-16 13:06:36,693 INFO: 数据库中所有产品: [('ArticleReplace', '改写软件')] [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:153]
2025-11-16 13:06:36,695 INFO: 产品查询结果: <Product 改写软件> [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:157]
2025-11-16 13:06:36,695 INFO: 检查版本号是否重复: product_id=ArticleReplace, version_num=1.0 [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:162]
2025-11-16 13:06:36,697 INFO: 创建版本对象: product_id=ArticleReplace, version_num=1.0 [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:172]
2025-11-16 13:06:36,699 INFO: 添加版本到数据库 [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:186]
2025-11-16 13:06:36,699 INFO: 提交数据库事务 [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:188]
2025-11-16 13:06:36,708 INFO: 检查是否立即发布: publish_now=False [in D:\work\code\python\KaMiXiTong\master\app\api\version.py:191]
2025-11-16 13:06:36,715 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'product_id\': "\'ArticleReplace\'", \'version_num\': "\'1.0\'", \'publish_now\': \'0\'}, \'\' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 2, 'action': 'UPDATE', 'target_type': 'ADMIN', 'target_id': 2, 'details': {'old': {'email': '2339117167@qq.com', 'role': 1, 'status': 1}, 'new': {'email': '2339117167@qq.com', 'role': 0, 'status': 1}}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 15, 14, 20, 36, 556170)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\models\audit_log.py:59]
2025-11-15 22:20:36,594 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'old\': {\'email\': "\'2339117167@qq.com\'", \'role\': \'1\', \'status\': \'1\'}, \'new\': {\'em\' at line 1')
[parameters: {'admin_id': 1, 'action': 'CREATE_VERSION', 'target_type': 'VERSION', 'target_id': 2, 'details': {'product_id': 'ArticleReplace', 'version_num': '1.0', 'publish_now': False}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 16, 5, 6, 36, 714215)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\master\app\models\audit_log.py:59]
2025-11-16 13:06:43,379 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'version_num\': "\'1.0\'", \'status\': \'1\', \'status_name\': "\'发布\'"}, \'127.0.0.1\', \' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 2, 'action': 'UPDATE_ADMIN', 'target_type': 'ADMIN', 'target_id': 2, 'details': {'old': {'email': '2339117167@qq.com', 'role': 1, 'status': 1}, 'new': {'email': '2339117167@qq.com', 'role': 0, 'status': 1}}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 15, 14, 20, 36, 584730)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\models\audit_log.py:59]
2025-11-15 22:21:39,838 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'username\': "\'test\'", \'role\': \'0\', \'status\': \'1\'}, \'127.0.0.1\', \'Mozilla/5.0 (Wi\' at line 1')
[parameters: {'admin_id': 1, 'action': 'UPDATE_VERSION_STATUS', 'target_type': 'VERSION', 'target_id': 2, 'details': {'version_num': '1.0', 'status': 1, 'status_name': '发布'}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 16, 5, 6, 43, 377554)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\master\app\models\audit_log.py:59]
2025-11-16 13:07:09,664 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'product_id\': "\'ArticleReplace\'", \'count\': \'1\', \'license_type\': \'1\', \'license_ke\' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 2, 'action': 'CREATE', 'target_type': 'ADMIN', 'target_id': 5, 'details': {'username': 'test', 'role': 0, 'status': 1}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 15, 14, 21, 39, 834164)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\models\audit_log.py:59]
2025-11-15 22:21:46,162 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:21:46,434 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:21:46,482 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
[parameters: {'admin_id': 1, 'action': 'GENERATE_LICENSES', 'target_type': 'LICENSE', 'target_id': None, 'details': {'product_id': 'ArticleReplace', 'count': 1, 'license_type': 1, 'license_keys': ['4SGGNAPF-HPGNQC1Z-6D7OH879-9BGW32PI']}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 16, 5, 7, 9, 662553)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\master\app\models\audit_log.py:59]
2025-11-16 13:07:44,918 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:10:12,691 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:11:09,687 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:14:50,942 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:15:22,908 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:15:40,597 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:17:33,606 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:18:26,492 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:18:38,007 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:18:49,532 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:21:42,076 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:21:54,735 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:24:17,919 ERROR: 更新卡密失败: 'License' object has no attribute 'remark' [in D:\work\code\python\KaMiXiTong\master\app\api\license.py:270]
2025-11-16 13:24:20,319 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'license_key\': "\'4SGGNAPF-HPGNQC1Z-6D7OH879-9BGW32PI\'"}, \'127.0.0.1\', \'Mozilla/5\' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 1, 'action': 'DELETE_LICENSE', 'target_type': 'LICENSE', 'target_id': None, 'details': {'license_key': '4SGGNAPF-HPGNQC1Z-6D7OH879-9BGW32PI'}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 16, 5, 24, 20, 318782)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\master\app\models\audit_log.py:59]
2025-11-16 13:24:53,054 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:26:10,998 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:32:27,257 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 13:32:51,116 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]

View File

@ -1,102 +1,80 @@
2025-11-15 14:20:05,639 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:20:07,103 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:20:55,708 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:20:57,062 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:21:28,777 ERROR: »ñÈ¡×ÜÀÀͳ¼ÆÊ§°Ü: (pymysql.err.ProgrammingError) (1146, "Table 'kamaxitong.api' doesn't exist")
[SQL: SELECT count(*) AS count_1
FROM (SELECT api.api_id AS api_api_id, api.api_name AS api_api_name, api.description AS api_description, api.status AS api_status, api.create_time AS api_create_time, api.update_time AS api_update_time
FROM api) AS anon_1]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\api\statistics.py:86]
2025-11-15 14:22:29,153 ERROR: »ñÈ¡×ÜÀÀͳ¼ÆÊ§°Ü: (pymysql.err.ProgrammingError) (1146, "Table 'kamaxitong.api' doesn't exist")
[SQL: SELECT count(*) AS count_1
FROM (SELECT api.api_id AS api_api_id, api.api_name AS api_api_name, api.description AS api_description, api.status AS api_status, api.create_time AS api_create_time, api.update_time AS api_update_time
FROM api) AS anon_1]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\api\statistics.py:86]
2025-11-15 14:22:40,129 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:23:10,648 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:23:11,851 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:23:23,719 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:23:29,274 ERROR: »ñÈ¡×ÜÀÀͳ¼ÆÊ§°Ü: (pymysql.err.ProgrammingError) (1146, "Table 'kamaxitong.api' doesn't exist")
[SQL: SELECT count(*) AS count_1
FROM (SELECT api.api_id AS api_api_id, api.api_name AS api_api_name, api.description AS api_description, api.status AS api_status, api.create_time AS api_create_time, api.update_time AS api_update_time
FROM api) AS anon_1]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\api\statistics.py:86]
2025-11-15 14:24:29,144 ERROR: »ñÈ¡×ÜÀÀͳ¼ÆÊ§°Ü: (pymysql.err.ProgrammingError) (1146, "Table 'kamaxitong.api' doesn't exist")
[SQL: SELECT count(*) AS count_1
FROM (SELECT api.api_id AS api_api_id, api.api_name AS api_api_name, api.description AS api_description, api.status AS api_status, api.create_time AS api_create_time, api.update_time AS api_update_time
FROM api) AS anon_1]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\api\statistics.py:86]
2025-11-15 14:25:07,065 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:25:07,424 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:25:19,299 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:25:29,262 ERROR: »ñÈ¡×ÜÀÀͳ¼ÆÊ§°Ü: (pymysql.err.ProgrammingError) (1146, "Table 'kamaxitong.api' doesn't exist")
[SQL: SELECT count(*) AS count_1
FROM (SELECT api.api_id AS api_api_id, api.api_name AS api_api_name, api.description AS api_description, api.status AS api_status, api.create_time AS api_create_time, api.update_time AS api_update_time
FROM api) AS anon_1]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\api\statistics.py:86]
2025-11-15 14:26:36,221 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:26:38,495 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:27:13,078 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:27:20,119 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:28:43,984 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:29:11,098 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:29:42,354 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:29:53,601 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:30:24,671 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:30:26,018 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:34:01,346 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:34:02,697 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:40:16,572 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:40:16,603 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:40:26,594 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:40:26,878 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:40:30,511 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:40:31,139 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:41:45,467 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:41:45,860 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:41:49,111 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:41:49,214 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:42:22,440 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 14:42:22,747 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:08:23,832 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:08:23,851 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:10:01,187 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:10:02,285 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:12:33,664 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:12:35,067 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:13:54,881 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:13:55,572 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:16:39,819 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:18:12,136 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:18:12,364 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:18:12,364 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:18:17,816 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:22:38,979 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:25:24,198 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:30:01,058 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:32:09,383 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:32:44,404 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:35:30,494 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:35:54,826 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:36:11,573 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:36:11,781 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:36:11,781 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:36:18,774 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:36:23,481 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:36:27,849 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:38:39,259 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 15:44:39,290 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 16:14:14,052 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 16:14:14,273 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 16:14:14,273 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 16:14:30,243 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 16:14:31,707 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 20:56:49,158 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:07:59,431 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:08:00,550 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:26:31,566 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:27:36,458 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:29:02,008 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:29:47,827 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:29:51,087 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:29:56,366 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:43:14,795 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:43:16,011 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:47:51,654 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:47:58,940 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:52:14,483 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:52:15,836 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:53:12,767 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:53:12,928 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:55:02,780 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:55:05,971 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:56:57,235 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 21:56:57,396 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:00:51,287 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:02:34,407 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:02:36,353 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:03:17,696 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:03:18,658 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:05:58,479 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:05:58,767 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:12:33,295 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:12:34,640 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:17,117 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:17,190 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:18,245 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:24,345 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:24,378 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:24,686 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:30,459 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:30,476 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:30,487 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:35,024 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:35,074 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:35,227 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:43,938 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:44,004 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:44,004 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:55,395 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:55,501 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:14:56,055 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:00,950 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:01,093 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:01,290 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:10,768 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:12,443 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:13,140 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:22,104 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:22,684 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:22,758 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:36,038 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:37,583 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:37,723 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:55,634 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:55,694 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:15:55,725 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:05,643 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:05,813 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:06,131 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:34,892 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:34,916 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:35,168 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:52,773 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:52,821 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:16:53,293 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:18:58,174 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:18:59,209 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:20:36,569 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'old\': {\'email\': "\'2339117167@qq.com\'", \'role\': \'1\', \'status\': \'1\'}, \'new\': {\'em\' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 2, 'action': 'UPDATE', 'target_type': 'ADMIN', 'target_id': 2, 'details': {'old': {'email': '2339117167@qq.com', 'role': 1, 'status': 1}, 'new': {'email': '2339117167@qq.com', 'role': 0, 'status': 1}}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 15, 14, 20, 36, 556170)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\models\audit_log.py:59]
2025-11-15 22:20:36,594 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'old\': {\'email\': "\'2339117167@qq.com\'", \'role\': \'1\', \'status\': \'1\'}, \'new\': {\'em\' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 2, 'action': 'UPDATE_ADMIN', 'target_type': 'ADMIN', 'target_id': 2, 'details': {'old': {'email': '2339117167@qq.com', 'role': 1, 'status': 1}, 'new': {'email': '2339117167@qq.com', 'role': 0, 'status': 1}}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 15, 14, 20, 36, 584730)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\models\audit_log.py:59]
2025-11-15 22:21:39,838 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'username\': "\'test\'", \'role\': \'0\', \'status\': \'1\'}, \'127.0.0.1\', \'Mozilla/5.0 (Wi\' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 2, 'action': 'CREATE', 'target_type': 'ADMIN', 'target_id': 5, 'details': {'username': 'test', 'role': 0, 'status': 1}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 15, 14, 21, 39, 834164)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\app\models\audit_log.py:59]
2025-11-15 22:21:46,162 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:21:46,434 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]
2025-11-15 22:21:46,482 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\config.py:66]

71
logs/kamaxitong.log.2 Normal file
View File

@ -0,0 +1,71 @@
2025-11-15 23:58:20,986 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-15 23:58:22,596 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 11:34:44,087 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 11:34:48,148 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 11:36:10,246 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'product_name\': "\'测试产品B\'"}, \'127.0.0.1\', \'Mozilla/5.0 (Windows NT 10.0; \' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 1, 'action': 'DELETE_PRODUCT', 'target_type': 'PRODUCT', 'target_id': 'PROD_23EF726D', 'details': {'product_name': '测试产品B'}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 16, 3, 36, 10, 245687)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\master\app\models\audit_log.py:59]
2025-11-16 11:36:15,609 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'product_name\': "\'测试产品A\'"}, \'127.0.0.1\', \'Mozilla/5.0 (Windows NT 10.0; \' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 1, 'action': 'DELETE_PRODUCT', 'target_type': 'PRODUCT', 'target_id': 'PROD_897EF967', 'details': {'product_name': '测试产品A'}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 16, 3, 36, 15, 608798)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\master\app\models\audit_log.py:59]
2025-11-16 11:36:28,535 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'license_key\': "\'W7XGEZU0-MFLWWKUK-XWPWFW3V-0LE77N2K\'"}, \'127.0.0.1\', \'Mozilla/5\' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 1, 'action': 'DELETE_LICENSE', 'target_type': 'LICENSE', 'target_id': None, 'details': {'license_key': 'W7XGEZU0-MFLWWKUK-XWPWFW3V-0LE77N2K'}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 16, 3, 36, 28, 535307)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\master\app\models\audit_log.py:59]
2025-11-16 11:36:34,617 ERROR: 记录审计日志失败: (pymysql.err.ProgrammingError) (1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\'product_name\': "\'测试产品C\'"}, \'127.0.0.1\', \'Mozilla/5.0 (Windows NT 10.0; \' at line 1')
[SQL: INSERT INTO audit_log (admin_id, action, target_type, target_id, details, ip_address, user_agent, create_time) VALUES (%(admin_id)s, %(action)s, %(target_type)s, %(target_id)s, %(details)s, %(ip_address)s, %(user_agent)s, %(create_time)s)]
[parameters: {'admin_id': 1, 'action': 'DELETE_PRODUCT', 'target_type': 'PRODUCT', 'target_id': 'PROD_A24B55D2', 'details': {'product_name': '测试产品C'}, 'ip_address': '127.0.0.1', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0', 'create_time': datetime.datetime(2025, 11, 16, 3, 36, 34, 616101)}]
(Background on this error at: https://sqlalche.me/e/20/f405) [in D:\work\code\python\KaMiXiTong\master\app\models\audit_log.py:59]
2025-11-16 12:12:41,268 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:13:10,962 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:13:13,050 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:14:26,744 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:14:34,528 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:14:44,691 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:56,754 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,016 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,016 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,024 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,024 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,024 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,039 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,039 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,039 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,039 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,092 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,092 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,092 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,092 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,092 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,343 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,343 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,343 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,343 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,343 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,343 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,372 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,372 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,372 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,372 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,372 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,372 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:57,372 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:16:59,517 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:17:24,098 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:21:22,890 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:21:27,735 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:21:31,439 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:21:40,107 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:21:43,784 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:21:53,199 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:22:01,231 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:22:03,158 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:22:05,098 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:22:07,063 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:22:11,957 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:22:59,514 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:23:01,359 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:32:48,638 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]
2025-11-16 12:33:31,339 INFO: KaMiXiTong startup [in D:\work\code\python\KaMiXiTong\master\config.py:71]

View File

@ -1,40 +0,0 @@
import requests
import json
# 创建会话以保持登录状态
session = requests.Session()
def test_apis():
"""直接测试API接口"""
try:
# 1. 测试创建产品(这会生成操作日志)
print("=== 测试创建产品 ===")
product_data = {
'product_name': '测试产品',
'description': '这是一个测试产品'
}
response = session.post(
"http://localhost:5000/api/v1/products",
json=product_data,
headers={'Content-Type': 'application/json'}
)
print(f"创建产品状态码: {response.status_code}")
print(f"创建产品响应: {response.text}")
# 2. 测试获取操作日志
print("\n=== 测试获取操作日志 ===")
response = session.get("http://localhost:5000/api/v1/logs")
print(f"获取日志状态码: {response.status_code}")
if response.status_code == 200:
log_data = response.json()
print(f"日志数据: {json.dumps(log_data, indent=2, ensure_ascii=False)}")
else:
print(f"获取日志失败: {response.text}")
except Exception as e:
print(f"测试过程中出现错误: {e}")
if __name__ == "__main__":
print("开始简单测试...")
test_apis()

View File

@ -1,21 +0,0 @@
import requests
import json
# 测试创建产品API
def test_create_product():
url = "http://localhost:5000/api/v1/products"
headers = {"Content-Type": "application/json"}
data = {
"product_name": "测试产品",
"description": "这是一个测试产品"
}
try:
response = requests.post(url, headers=headers, data=json.dumps(data))
print(f"Status Code: {response.status_code}")
print(f"Response: {response.text}")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
test_create_product()

View File

@ -1,67 +0,0 @@
import requests
import json
# 创建会话以保持登录状态
session = requests.Session()
def login():
"""登录系统"""
url = "http://localhost:5000/api/v1/auth/login"
headers = {"Content-Type": "application/json"}
data = {
"username": "admin",
"password": "admin123"
}
try:
response = session.post(url, headers=headers, data=json.dumps(data))
print(f"Login Status Code: {response.status_code}")
print(f"Login Response: {response.text}")
return response.status_code == 200
except Exception as e:
print(f"Login Error: {e}")
return False
def test_create_product():
"""测试创建产品API"""
url = "http://localhost:5000/api/v1/products"
headers = {"Content-Type": "application/json"}
data = {
"product_name": "测试产品",
"description": "这是一个测试产品"
}
try:
response = session.post(url, headers=headers, data=json.dumps(data))
print(f"Create Product Status Code: {response.status_code}")
print(f"Create Product Response: {response.text}")
return response.status_code == 200
except Exception as e:
print(f"Create Product Error: {e}")
return False
def test_get_logs():
"""测试获取日志API"""
url = "http://localhost:5000/api/v1/logs"
try:
response = session.get(url)
print(f"Get Logs Status Code: {response.status_code}")
print(f"Get Logs Response: {response.text}")
return response.status_code == 200
except Exception as e:
print(f"Get Logs Error: {e}")
return False
if __name__ == "__main__":
# 登录
if login():
print("登录成功")
# 测试创建产品
if test_create_product():
print("创建产品成功")
# 测试获取日志
test_get_logs()
else:
print("创建产品失败")
else:
print("登录失败")

View File

@ -1,29 +0,0 @@
import requests
# 测试登录页面访问
response = requests.get('http://127.0.0.1:5000/login')
print(f"Status Code: {response.status_code}")
print(f"Content Length: {len(response.content)}")
print(f"Content Type: {response.headers.get('content-type')}")
# 检查页面内容
content = response.text
if '登录' in content:
print("页面包含登录相关文本")
else:
print("页面不包含登录相关文本")
# 检查是否有错误信息
if '错误' in content or 'Error' in content:
print("页面包含错误信息")
else:
print("页面不包含明显错误信息")
# 尝试登录
login_data = {
'username': 'admin',
'password': 'admin123',
'csrf_token': '' # 我们需要从页面中提取CSRF令牌
}
print("尝试登录测试...")

View File

@ -1,137 +0,0 @@
import requests
from bs4 import BeautifulSoup
# 创建会话以保持登录状态
session = requests.Session()
def get_csrf_token():
"""从登录页面获取CSRF令牌"""
try:
response = session.get("http://localhost:5000/login")
soup = BeautifulSoup(response.text, 'html.parser')
csrf_input = soup.find('input', {'name': 'csrf_token'})
if csrf_input:
# 直接获取value属性
try:
# 忽略类型检查错误
csrf_token = csrf_input.get('value') # type: ignore
if not csrf_token:
csrf_token = csrf_input['value'] # type: ignore
if csrf_token:
return csrf_token
except:
pass
print("未找到CSRF令牌输入字段")
return None
except Exception as e:
print(f"获取CSRF令牌失败: {e}")
return None
def login():
"""登录系统"""
try:
# 获取CSRF令牌
csrf_token = get_csrf_token()
if not csrf_token:
return False
# 准备登录数据
login_data = {
'username': 'admin',
'password': 'admin123',
'csrf_token': csrf_token
}
# 发送登录请求
response = session.post("http://localhost:5000/login", data=login_data)
# 检查是否登录成功通过重定向到dashboard来判断
if response.url and 'dashboard' in response.url:
print("登录成功")
return True
else:
print(f"登录失败,状态码: {response.status_code}")
print(f"响应URL: {response.url}")
return False
except Exception as e:
print(f"登录过程中出现错误: {e}")
return False
def test_create_product():
"""测试创建产品"""
try:
# 准备产品数据
product_data = {
'product_name': '测试产品',
'description': '这是一个测试产品'
}
# 发送创建产品请求
response = session.post(
"http://localhost:5000/api/v1/products",
json=product_data,
headers={'Content-Type': 'application/json'}
)
print(f"创建产品状态码: {response.status_code}")
print(f"创建产品响应: {response.text}")
return response.status_code == 200
except Exception as e:
print(f"创建产品时出现错误: {e}")
return False
def test_get_logs():
"""测试获取操作日志"""
try:
# 发送获取日志请求
response = session.get("http://localhost:5000/api/v1/logs")
print(f"获取日志状态码: {response.status_code}")
print(f"获取日志响应: {response.text}")
return response.status_code == 200
except Exception as e:
print(f"获取日志时出现错误: {e}")
return False
def test_view_logs_page():
"""测试访问日志页面"""
try:
# 访问日志管理页面
response = session.get("http://localhost:5000/logs")
print(f"访问日志页面状态码: {response.status_code}")
if response.status_code == 200:
print("成功访问日志管理页面")
return True
else:
print(f"访问日志页面失败: {response.text}")
return False
except Exception as e:
print(f"访问日志页面时出现错误: {e}")
return False
if __name__ == "__main__":
print("开始测试日志功能...")
# 登录
if login():
print("=== 登录成功 ===")
# 测试创建产品(这会生成操作日志)
print("\n=== 测试创建产品 ===")
test_create_product()
# 测试获取操作日志
print("\n=== 测试获取操作日志 ===")
test_get_logs()
# 测试访问日志页面
print("\n=== 测试访问日志页面 ===")
test_view_logs_page()
else:
print("登录失败,无法继续测试")

View File

@ -1,41 +0,0 @@
import requests
import json
# 直接测试日志API绕过认证检查在实际环境中应该有认证
def test_log_functionality():
"""测试日志功能"""
try:
# 1. 先手动创建一个产品(绕过认证检查)
print("=== 手动创建产品以生成日志 ===")
# 我们直接查看数据库中是否已有产品
print("检查现有产品...")
# 2. 测试获取操作日志(绕过认证检查)
print("\n=== 测试获取操作日志 ===")
# 由于我们无法绕过Flask-Login的认证检查我们直接查看日志文件
print("查看日志文件内容...")
try:
with open('logs/kamaxitong.log', 'r', encoding='utf-8') as f:
lines = f.readlines()
print(f"日志文件共有 {len(lines)}")
# 显示最后几行
for line in lines[-10:]:
print(line.strip())
except FileNotFoundError:
print("日志文件不存在")
except Exception as e:
print(f"读取日志文件失败: {e}")
# 3. 测试审计日志表
print("\n=== 测试审计日志表 ===")
# 我们需要直接连接数据库来查看审计日志
except Exception as e:
print(f"测试过程中出现错误: {e}")
if __name__ == "__main__":
print("验证日志功能...")
test_log_functionality()