增加发布正式版的命令

This commit is contained in:
2026-07-21 15:37:36 +08:00
parent cff1074474
commit 22f9bccb09
8 changed files with 371 additions and 29 deletions

21
.env.example Normal file
View File

@@ -0,0 +1,21 @@
# ========================================
# 订单日报系统 - 环境变量配置示例
# ========================================
# 使用方法:复制本文件为 .env然后修改相应配置
# 注意:如果使用 .env 文件,需要安装 python-dotenv
# 服务监听地址
DEPLOY_RUN_HOST=0.0.0.0
# 服务监听端口
DEPLOY_RUN_PORT=5000
# 数据库配置
DB_HOST=haoslm2.xicp.net
DB_PORT=10216
DB_USER=root
DB_PASSWORD=your_password
DB_NAME=your_database
# 日志级别DEBUG/INFO/WARNING/ERROR
LOG_LEVEL=INFO

19
.env.prod Normal file
View File

@@ -0,0 +1,19 @@
# ========================================
# 订单日报系统 - 正式环境配置
# ========================================
# 服务监听地址
DEPLOY_RUN_HOST=0.0.0.0
# 服务监听端口
DEPLOY_RUN_PORT=5000
# 数据库配置(正式环境)
DB_HOST=192.168.10.250
DB_PORT=9030
DB_USER=root
DB_PASSWORD=DsideaL147258369
DB_NAME=yltcharge
# 日志级别DEBUG/INFO/WARNING/ERROR
LOG_LEVEL=INFO

View File

@@ -1,25 +1,29 @@
"""
数据库连接配置
"""
import os
import pymysql
from contextlib import contextmanager
from lib.logger import log_info, log_error, log_warning
# 数据库配置
DB_CONFIG = {
'host': 'haoslm2.xicp.net',
'port': 10216,
'user': 'root',
'password': 'DsideaL147258369',
'database': 'yltcharge',
def get_db_config():
"""从环境变量或默认值获取数据库配置"""
return {
'host': os.environ.get('DB_HOST', 'haoslm2.xicp.net'),
'port': int(os.environ.get('DB_PORT', 10216)),
'user': os.environ.get('DB_USER', 'root'),
'password': os.environ.get('DB_PASSWORD', 'DsideaL147258369'),
'database': os.environ.get('DB_NAME', 'yltcharge'),
'charset': 'utf8mb4',
'cursorclass': pymysql.cursors.DictCursor,
'autocommit': True,
'connect_timeout': 30, # 连接超时30秒
'read_timeout': 60, # 读取超时60秒
'write_timeout': 60 # 写入超时60秒
'connect_timeout': 30,
'read_timeout': 60,
'write_timeout': 60
}
DB_CONFIG = get_db_config()
@contextmanager
def get_connection():

View File

@@ -869,31 +869,46 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
charge_degree_col = col_idx
break
# 第一列显示标题
# 总列数
total_cols = len(selected_fields) + 2
if has_custom_service_fee:
total_cols += 1
# 标题文字
title_text = f'当月累计充电量(共{total_days}天,截止{report_date}'
if missing_dates and len(missing_dates) > 0:
# 最多显示5个缺失日期超过的用"...共N天"表示
if len(missing_dates) <= 5:
missing_str = ''.join([d[5:] for d in missing_dates]) # 只显示月-日
missing_str = ''.join([d[5:] for d in missing_dates])
else:
missing_str = ''.join([d[5:] for d in missing_dates[:5]]) + f'...共{len(missing_dates)}'
title_text += f'\n(缺:{missing_str}'
ws.cell(row=monthly_row, column=1).value = title_text
ws.cell(row=monthly_row, column=1).font = monthly_font
ws.cell(row=monthly_row, column=1).fill = monthly_fill
ws.cell(row=monthly_row, column=1).alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
ws.cell(row=monthly_row, column=1).border = thin_border
# 标题跨列从第1列到 charge_degree_col 的前一列
# 如果没有找到充电电量列,就跨到倒数第二列
title_end_col = charge_degree_col - 1 if charge_degree_col else total_cols - 1
if title_end_col < 1:
title_end_col = 1
# 其他列也填充背景色
total_cols = len(selected_fields) + 2
if has_custom_service_fee:
total_cols += 1
# 合并标题单元格
if title_end_col > 1:
ws.merge_cells(start_row=monthly_row, start_column=1,
end_row=monthly_row, end_column=title_end_col)
# 设置标题单元格
title_cell = ws.cell(row=monthly_row, column=1)
title_cell.value = title_text
title_cell.font = monthly_font
title_cell.fill = monthly_fill
title_cell.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
title_cell.border = thin_border
# 其他列填充背景色和边框
for col_idx in range(2, total_cols):
cell = ws.cell(row=monthly_row, column=col_idx)
cell.fill = monthly_fill
cell.border = thin_border
# 数值放在 charge_degree 列
if charge_degree_col:
cell = ws.cell(row=monthly_row, column=charge_degree_col)
cell.value = total_degree
@@ -901,11 +916,11 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.000'
# 如果有缺失日期,行高加大一点
# 行高
if missing_dates and len(missing_dates) > 0:
ws.row_dimensions[monthly_row].height = 40
ws.row_dimensions[monthly_row].height = 45
else:
ws.row_dimensions[monthly_row].height = 25
ws.row_dimensions[monthly_row].height = 28
except Exception as e:
log_error(f"[日报生成] 写入月度总计时出错: {e}", 'report')

View File

@@ -18,5 +18,8 @@ APScheduler==3.10.4
python-dateutil==2.8.2
pytz==2023.3
# 生产服务器Windows推荐
waitress==3.0.0
# 开发工具(可选)
python-dotenv==1.0.0

25
run_prod.py Normal file
View File

@@ -0,0 +1,25 @@
"""
生产环境启动脚本
使用 waitress 作为 WSGI 服务器
"""
import os
from waitress import serve
from app import app
if __name__ == '__main__':
port = int(os.environ.get('DEPLOY_RUN_PORT', 5000))
host = os.environ.get('DEPLOY_RUN_HOST', '0.0.0.0')
print(f'订单日报系统 - 生产模式')
print(f'监听地址: {host}:{port}')
print('按 Ctrl+C 停止服务')
print('-' * 50)
serve(
app,
host=host,
port=port,
threads=8,
connection_limit=200,
channel_timeout=300,
)

132
启动.bat Normal file
View File

@@ -0,0 +1,132 @@
@echo off
chcp 65001 >nul
title 订单日报系统 - 生产模式
cd /d "%~dp0"
echo ========================================
echo 订单日报系统 - 生产模式启动
echo ========================================
echo.
REM ============================================
REM 第一步:读取 .env 配置文件(如果存在)
REM ============================================
echo [1/5] 读取配置...
if exist ".env" (
echo [信息] 找到 .env 文件,正在加载配置...
for /f "usebackq tokens=1,2 delims==" %%a in (".env") do (
if not "%%a"=="" if not "%%~a"=="#" (
set "%%a=%%b"
)
)
echo [信息] 配置加载完成
) else if exist ".env.prod" (
echo [信息] 找到 .env.prod 文件,正在加载配置...
for /f "usebackq tokens=1,2 delims==" %%a in (".env.prod") do (
if not "%%a"=="" if not "%%~a"=="#" (
set "%%a=%%b"
)
)
echo [信息] 配置加载完成
) else (
echo [信息] 未找到 .env 文件,使用默认配置
)
REM ============================================
REM 第二步:检查 Python 是否安装
REM ============================================
echo.
echo [2/5] 检查 Python 环境...
where python >nul 2>&1
if errorlevel 1 (
echo [错误] 未检测到 Python
echo.
echo 请先安装 Python 3.10 或更高版本:
echo 下载地址: https://www.python.org/downloads/
echo 安装时请勾选 "Add Python to PATH"
echo.
pause
exit /b 1
)
for /f "delims=" %%v in ('python --version 2^>^&1') do set PY_VERSION=%%v
echo [信息] Python 已安装: %PY_VERSION%
REM ============================================
REM 第三步:创建虚拟环境(如果不存在)
REM ============================================
echo.
echo [3/5] 检查虚拟环境...
if not exist ".venv\Scripts\python.exe" (
echo [信息] 虚拟环境不存在,正在创建...
python -m venv .venv
if errorlevel 1 (
echo [错误] 虚拟环境创建失败!
pause
exit /b 1
)
echo [信息] 虚拟环境创建成功
) else (
echo [信息] 虚拟环境已存在
)
set PYTHON=.venv\Scripts\python.exe
set PIP=.venv\Scripts\pip.exe
REM ============================================
REM 第四步:安装依赖(只在缺少时安装)
REM ============================================
echo.
echo [4/5] 检查依赖...
REM 检查核心依赖是否已安装
%PYTHON% -c "import flask" 2>nul
if errorlevel 1 (
set NEED_INSTALL=1
) else (
set NEED_INSTALL=0
)
if "%NEED_INSTALL%"=="1" (
echo [信息] 正在安装依赖,请稍候...
%PIP% install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
if errorlevel 1 (
echo [警告] 清华源安装失败,尝试官方源...
%PIP% install -r requirements.txt
if errorlevel 1 (
echo [错误] 依赖安装失败!
pause
exit /b 1
)
)
echo [信息] 依赖安装完成
) else (
echo [信息] 依赖已就绪
)
REM ============================================
REM 第五步:启动服务
REM ============================================
echo.
echo [5/5] 启动服务...
echo.
echo [信息] 服务启动后,访问 http://localhost:5000
echo [信息] 按 Ctrl+C 停止服务
echo.
echo ========================================
echo.
%PYTHON% run_prod.py
if errorlevel 1 (
echo.
echo ========================================
echo [错误] 服务异常退出,错误代码: %errorlevel%
echo ========================================
echo.
pause
)

123
服务管理.bat Normal file
View File

@@ -0,0 +1,123 @@
@echo off
chcp 65001 >nul
title 订单日报系统 - Windows服务管理
cd /d "%~dp0"
REM ============================================
REM 使用 NSSM 将程序注册为 Windows 服务
REM 需要先下载 nssm.exe 放到当前目录
REM 下载地址: https://nssm.cc/download
REM ============================================
set SERVICE_NAME=DailyReportSystem
set SERVICE_DESC=订单日报系统服务
set NSSM_EXE=nssm.exe
if not exist "%NSSM_EXE%" (
echo [错误] 未找到 %NSSM_EXE%
echo.
echo 请先下载 NSSM:
echo 1. 访问 https://nssm.cc/download
echo 2. 下载 Win64 版本
echo 3. 解压后将 nssm.exe 放到当前目录
echo.
pause
exit /b 1
)
REM 检查虚拟环境
if exist ".venv\Scripts\python.exe" (
set PYTHON_PATH=%cd%\.venv\Scripts\python.exe
) else (
for /f "delims=" %%i in ('where python') do (
set PYTHON_PATH=%%i
goto :found_python
)
:found_python
)
echo ========================================
echo 订单日报系统 - Windows服务管理
echo ========================================
echo.
echo 服务名称: %SERVICE_NAME%
echo Python路径: %PYTHON_PATH%
echo 工作目录: %cd%
echo.
echo 请选择操作:
echo 1. 安装服务
echo 2. 启动服务
echo 3. 停止服务
echo 4. 重启服务
echo 5. 删除服务
echo 6. 查看服务状态
echo 0. 退出
echo.
set /p choice=请输入选项:
if "%choice%"=="1" goto install
if "%choice%"=="2" goto start
if "%choice%"=="3" goto stop
if "%choice%"=="4" goto restart
if "%choice%"=="5" goto remove
if "%choice%"=="6" goto status
if "%choice%"=="0" goto end
:install
echo.
echo [信息] 正在安装服务...
%NSSM_EXE% install %SERVICE_NAME% "%PYTHON_PATH%" "%cd%\run_prod.py"
%NSSM_EXE% set %SERVICE_NAME% AppDirectory "%cd%"
%NSSM_EXE% set %SERVICE_NAME% DisplayName "%SERVICE_DESC%"
%NSSM_EXE% set %SERVICE_NAME% Description "订单日报系统 - 自动生成充电订单日报报表"
%NSSM_EXE% set %SERVICE_NAME% Start SERVICE_AUTO_START
%NSSM_EXE% set %SERVICE_NAME% AppStdout "%cd%\logs\service_stdout.log"
%NSSM_EXE% set %SERVICE_NAME% AppStderr "%cd%\logs\service_stderr.log"
%NSSM_EXE% set %SERVICE_NAME% AppRotateFiles 1
%NSSM_EXE% set %SERVICE_NAME% AppRotateOnline 1
%NSSM_EXE% set %SERVICE_NAME% AppRotateBytes 10485760
echo [信息] 服务安装完成!
goto end
:start
echo.
echo [信息] 正在启动服务...
net start %SERVICE_NAME%
goto end
:stop
echo.
echo [信息] 正在停止服务...
net stop %SERVICE_NAME%
goto end
:restart
echo.
echo [信息] 正在重启服务...
net stop %SERVICE_NAME%
timeout /t 3 /nobreak >nul
net start %SERVICE_NAME%
goto end
:remove
echo.
echo [警告] 即将删除服务 %SERVICE_NAME%
set /p confirm=确认删除吗?(y/n):
if /i not "%confirm%"=="y" goto end
echo [信息] 正在停止服务...
net stop %SERVICE_NAME% 2>nul
echo [信息] 正在删除服务...
%NSSM_EXE% remove %SERVICE_NAME% confirm
echo [信息] 服务已删除!
goto end
:status
echo.
echo [信息] 服务状态:
sc query %SERVICE_NAME%
goto end
:end
echo.
pause