chore(tools): 根目录散落工具脚本归位 tools/ 目录

- find/listdir/r/sound/SendWX 及 WARN.mp3 移入 tools/(sound.py 相对路径同目录保持可用)
- Version 死代码(import 自增 VER)归档 tools/Version
- Main.py(生产入口候选)与 TODO 保留根目录待确认
This commit is contained in:
TermiNexus committed 2026-08-13 18:15:30 +08:00
1 parent 727fbba272
commit a208dbb02a
10 files changed
+2 -2

No files matched your search

+68
View File
@@ -0,0 +1,68 @@
import requests
import json
def SendWeChatWorkMessage(access_token, agent_id, title, description, _url, btntxt="更多",
to_user=None, to_party=None, to_tag=None):
"""
发送企业微信文本卡片消息
:param access_token: 调用接口凭证
:param agent_id: 企业应用的id
:param title: 卡片标题
:param description: 卡片描述内容(支持HTML)
:param url: 点击后跳转的链接
:param btntxt: 按钮文字,默认为"更多"
:param to_user: 接收消息的成员,多个用'|'分隔,None表示不指定
:param to_party: 接收消息的部门,多个用'|'分隔,None表示不指定
:param to_tag: 接收消息的标签,多个用'|'分隔,None表示不指定
:return: 接口返回结果
"""
url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}"
message = {
"msgtype": "textcard",
"agentid": agent_id,
"textcard": {
"title": title,
"description": description,
"url": _url,
"btntxt": btntxt
},
"enable_id_trans": 0,
"enable_duplicate_check": 0,
"duplicate_check_interval": 1800
}
if to_user:
message["touser"] = to_user
if to_party:
message["toparty"] = to_party
if to_tag:
message["totag"] = to_tag
headers = {'Content-Type': 'application/json; charset=utf-8'}
response = requests.post(url,
headers=headers,
data=json.dumps(message, ensure_ascii=False).encode('utf-8'))
return response.json()
if __name__ == "__main__":
ACCESS_TOKEN = "EzUNqv2s_S_MZ70bmJuBL5-hp2tB1eX7I3jbLxb5kdUSUZXd4TlCJY92scfQrSJgvd8jIMRpR1B2wsqrFxfU0oyuu-pvP5kvBNgkxyIJ-w2aX2cLGHi7cC4sCYbAqAAP92wI3DjK7SrXFkyLBd6BRQdUjyInpQObzjyUzOSiRK8IRTKB-Svs0UV9PRkfx54gBIgX5FNk_fdX9Uonp_kIjQ"
AGENT_ID = 1000003
TITLE = "领奖通知"
DESCRIPTION = """<div class=\"gray\">3000年13月32日</div>
<div class=\"normal\">请尽快前往工作室系统签到</div>
<div class=\"highlight\">否则经人力资源部确认后将发起离职</div>"""
URL = "https://manage.gvsds.com/"
BTNTXT = "查看详情"
TO_USER = "WangYuTong"
TO_PARTY = "@all"
TO_TAG = "@all"
result = SendWeChatWorkMessage(ACCESS_TOKEN, AGENT_ID, TITLE, DESCRIPTION, URL, BTNTXT,
TO_USER, TO_PARTY, TO_TAG)
print("发送结果:")
print(json.dumps(result, indent=2, ensure_ascii=False))
+2
View File
@@ -0,0 +1,2 @@
0.0000.0195.4129
1954129
+49
View File
@@ -0,0 +1,49 @@
def openw(file, write, mode="1", encoding="UTF-8"):
if mode == "1" or mode == 1:
with open(file, "w", encoding=encoding) as f:
f.write(write)
elif mode == "2" or mode == 2:
with open(file, "wb") as f:
f.write(write)
def read_ver():
try:
with open("./Version/CONFIG/VER", 'r') as f:
read=f.read()
if read == "":
ver_str = '0.0000.0000.0000'
ver_int = 0
else:
ver_str = read.split("\n")[-3]
ver_int = int(read.split("\n")[-2])
except FileNotFoundError:
ver_str = '0.0000.0000.0000'
ver_int = 0
return ver_str, ver_int
def write_ver(ver_str, ver_int):
openw("./Version/CONFIG/VER", ver_str + '\n' + str(ver_int) + '\n')
def increase_ver(ver_str, ver_int):
ver_int += 1
ver_str_list = ver_str.split('.')
for i in range(len(ver_str_list)-1, -1, -1):
num = int(ver_str_list[i])
if num < 9999:
ver_str_list[i] = str(num + 1).zfill(4)
break
else:
ver_str_list[i] = '0000'
ver_str = '.'.join(ver_str_list)
return ver_str, ver_int
ver_str, ver_int = read_ver()
ver_str, ver_int = increase_ver(ver_str, ver_int)
write_ver(ver_str, ver_int)
print(" * Version:", ver_str)
Ver=ver_str
VER=ver_str
+7
View File
@@ -0,0 +1,7 @@
[CONFIG]
ENTRY=Main.py
DECODE=Python
LIBRARY=
SET=CONFIG
VER=VER
LOG_DIR=./LOG/
BIN
View File
Binary file not shown.
+103
View File
@@ -0,0 +1,103 @@
import os
import re
import argparse
from typing import List
def search_in_file(file_path: str, pattern: str, is_regex: bool = False) -> List[str]:
"""
在单个文件中搜索指定内容(文本/正则)
Args:
file_path: 文件路径
pattern: 要搜索的文本或正则表达式
is_regex: 是否按正则表达式匹配(默认False,按普通文本匹配)
Returns:
匹配的行列表(格式:"行号: 行内容")
"""
matched_lines = []
try:
# 支持常见编码(utf-8/gbk),避免中文乱码
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
for line_num, line in enumerate(f, 1):
# 正则匹配 / 普通文本包含匹配
if is_regex:
if re.search(pattern, line):
matched_lines.append(f"第{line_num}行: {line.strip()}")
else:
if pattern in line:
matched_lines.append(f"第{line_num}行: {line.strip()}")
except (PermissionError, IsADirectoryError):
# 跳过无权限文件/误判为文件的文件夹
pass
return matched_lines
def search_in_directory(dir_path: str, pattern: str, is_regex: bool = False, extensions: List[str] = None) -> None:
"""
遍历文件夹下指定后缀的文件,搜索指定内容
Args:
dir_path: 文件夹路径
pattern: 要搜索的文本或正则表达式
is_regex: 是否按正则表达式匹配
extensions: 要筛选的文件后缀列表(如 ['.css', '.js']),None 表示匹配所有文件
"""
# 校验文件夹路径是否存在
if not os.path.isdir(dir_path):
print(f"错误:文件夹路径 '{dir_path}' 不存在或不是有效文件夹!")
return
# 处理后缀参数:统一转为小写,确保 .css 和 CSS 都能匹配
valid_extensions = None
if extensions:
valid_extensions = [ext.lower() if ext.startswith('.') else f'.{ext.lower()}' for ext in extensions]
print(f"筛选后缀:{', '.join(valid_extensions)}")
# 打印搜索信息
print(f"开始搜索:\n文件夹:{dir_path}\n搜索内容:{pattern}\n是否正则:{is_regex}")
if valid_extensions:
print(f"筛选后缀:{', '.join(valid_extensions)}")
print('='*60)
# 遍历文件夹(包括子文件夹)
file_count = 0 # 统计遍历的文件数
match_count = 0 # 统计匹配的文件数
for root, _, files in os.walk(dir_path):
for file_name in files:
# 过滤文件后缀
if valid_extensions:
file_ext = os.path.splitext(file_name)[1].lower()
if file_ext not in valid_extensions:
continue # 跳过不符合后缀的文件
file_path = os.path.join(root, file_name)
file_count += 1
matched_lines = search_in_file(file_path, pattern, is_regex)
if matched_lines:
match_count += 1
print(f"\n【匹配到文件】:{file_path}")
for line in matched_lines:
print(f" {line}")
# 打印搜索统计
print(f'\n{"="*60}')
print(f"搜索完成!")
print(f"共遍历文件数:{file_count}")
print(f"匹配到文件数:{match_count}")
def main():
# 命令行参数解析(新增 --ext 参数指定文件后缀)
parser = argparse.ArgumentParser(description='在指定文件夹中搜索文本或正则表达式(支持指定文件后缀)')
parser.add_argument('dir_path', help='要搜索的文件夹路径(绝对/相对路径均可)')
parser.add_argument('pattern', help='要搜索的文本或正则表达式')
parser.add_argument('-r', '--regex', action='store_true', help='是否按正则表达式匹配(默认否)')
parser.add_argument('-e', '--ext', nargs='+', help='指定要搜索的文件后缀(多个用空格分隔,如:-e css js html)')
args = parser.parse_args()
# 执行搜索
search_in_directory(args.dir_path, args.pattern, args.regex, args.ext)
if __name__ == '__main__':
main()
+210
View File
@@ -0,0 +1,210 @@
import os
import argparse
import re
from collections import defaultdict
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, Border, Side
# 配置默认参数
DEFAULT_EXTENSIONS = {'py', 'pyw', 'api', 'html', 'js', 'css'}
AUTO_EXCLUDE_DIRS = {'.env', 'layui', 'node_modules'} # 不区分大小写
AUTO_EXCLUDE_KEYWORDS = {
'font-awesome',
'bootstrap',
re.compile(r'.*\.lib\.js$', re.IGNORECASE),
re.compile(r'.*\.lib\.css$', re.IGNORECASE)
}
class CodeCounter:
def __init__(self, target_dir, exclude_paths=None, extensions=None):
self.target_dir = os.path.abspath(target_dir)
self.exclude_paths = [os.path.abspath(p) for p in exclude_paths] if exclude_paths else []
self.extensions = extensions or DEFAULT_EXTENSIONS
self.file_stats = [] # 存储每个文件的统计信息
self.total_lines = 0
self.total_chars = 0
self.total_files = 0
def _should_exclude_file(self, file_path):
"""判断文件是否需要排除"""
# 检查自动排除的目录(任何深度)
dir_parts = file_path.lower().split(os.sep)
if any(ed.lower() in dir_parts for ed in AUTO_EXCLUDE_DIRS):
return True
# 检查手动排除的路径
for ep in self.exclude_paths:
if file_path.startswith(ep):
return True
# 检查自动排除的关键字/正则
file_name = os.path.basename(file_path).lower()
for keyword in AUTO_EXCLUDE_KEYWORDS:
if isinstance(keyword, re.Pattern):
if keyword.match(file_name):
return True
else:
if keyword.lower() in file_path.lower():
return True
return False
def _get_file_ext(self, file_path):
"""获取文件扩展名(不含点)"""
ext = os.path.splitext(file_path)[1].lstrip('.').lower()
return ext
def _count_file(self, file_path):
"""统计单个文件的行数和字符数"""
try:
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
lines = len(content.splitlines())
chars = len(content)
return lines, chars
except Exception as e:
print(f"警告:无法读取文件 {file_path} - {e}")
return 0, 0
def scan(self):
"""扫描目录并统计代码量"""
print(f"开始扫描目录:{self.target_dir}")
print(f"包含扩展名:{', '.join(self.extensions)}")
print(f"排除路径:{', '.join(self.exclude_paths) if self.exclude_paths else '无'}")
print("-" * 80)
for root, dirs, files in os.walk(self.target_dir):
# 跳过自动排除的目录(优化遍历性能)
dirs[:] = [d for d in dirs if d.lower() not in AUTO_EXCLUDE_DIRS]
for file in files:
file_path = os.path.join(root, file)
ext = self._get_file_ext(file_path)
# 检查扩展名是否符合要求
if ext not in self.extensions:
continue
# 检查是否需要排除
if self._should_exclude_file(file_path):
continue
# 统计文件
lines, chars = self._count_file(file_path)
self.file_stats.append({
'path': file_path,
'lines': lines,
'chars': chars
})
self.total_lines += lines
self.total_chars += chars
self.total_files += 1
# 实时输出进度
print(f"已统计:{file_path} | 行数:{lines} | 字符数:{chars}")
print("-" * 80)
print(f"统计完成!")
print(f"总文件数:{self.total_files}")
print(f"总行数:{self.total_lines}")
print(f"总字符数:{self.total_chars}")
def export_xlsx(self, output_path):
"""导出统计结果到XLSX文件"""
wb = Workbook()
ws = wb.active
ws.title = "代码量统计"
# 设置表头
headers = ['文件路径', '行数', '字符数']
for col, header in enumerate(headers, 1):
cell = ws.cell(row=1, column=col, value=header)
cell.font = Font(bold=True, size=12)
cell.alignment = Alignment(horizontal='center')
cell.border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
# 填充数据
for row, stat in enumerate(self.file_stats, 2):
ws.cell(row=row, column=1, value=stat['path'])
ws.cell(row=row, column=2, value=stat['lines'])
ws.cell(row=row, column=3, value=stat['chars'])
# 设置单元格格式
for col in range(1, 4):
cell = ws.cell(row=row, column=col)
cell.border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
if col > 1:
cell.alignment = Alignment(horizontal='center')
# 添加总计行
total_row = len(self.file_stats) + 3
ws.cell(row=total_row, column=1, value='总计')
ws.cell(row=total_row, column=2, value=self.total_lines)
ws.cell(row=total_row, column=3, value=self.total_chars)
for col in range(1, 4):
cell = ws.cell(row=total_row, column=col)
cell.font = Font(bold=True)
cell.alignment = Alignment(horizontal='center')
cell.border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
# 调整列宽
ws.column_dimensions['A'].width = 80
ws.column_dimensions['B'].width = 15
ws.column_dimensions['C'].width = 15
# 保存文件
try:
wb.save(output_path)
print(f"\nXLSX文件已导出:{os.path.abspath(output_path)}")
except Exception as e:
print(f"\n导出XLSX失败:{e}")
def main():
# 解析命令行参数
parser = argparse.ArgumentParser(description='Python代码量统计工具')
parser.add_argument('dir', help='要统计的目标目录')
parser.add_argument('--exclude', nargs='+', default=[],
help='需要排除的路径(如:TempLate/cdn TempLate/AKS)')
parser.add_argument('--extensions', nargs='+', default=list(DEFAULT_EXTENSIONS),
help='要统计的文件扩展名(默认:py pyw api html js css)')
parser.add_argument('--export', help='导出XLSX文件路径(如:code_stats.xlsx)')
args = parser.parse_args()
# 处理排除路径(相对路径转绝对路径)
exclude_paths = []
for ep in args.exclude:
if os.path.isabs(ep):
exclude_paths.append(ep)
else:
exclude_paths.append(os.path.join(os.path.abspath(args.dir), ep))
# 创建统计器并执行统计
counter = CodeCounter(
target_dir=args.dir,
exclude_paths=exclude_paths,
extensions=set(args.extensions)
)
counter.scan()
# 导出XLSX(如果指定)
if args.export:
counter.export_xlsx(args.export)
if __name__ == '__main__':
main()
+76
View File
@@ -0,0 +1,76 @@
import os
# 目录定义
ROOT_DIR = r"./TempLateModule/"
EXTRA_FILES = []
def snake_to_upper_camel(s: str) -> str:
if not s:
return s
if s.startswith('_'):
first = '_'
rest = s[1:]
else:
first = ''
rest = s
parts = rest.split('_')
pascal = ''.join(part.capitalize() for part in parts)
return first + pascal
while True:
old_str = input("请输入原蛇形字符串:").strip()
new_input = input("替换内容(留空自动转大驼峰):").strip()
if not old_str:
print("错误:原字符串不能为空\n")
continue
total_mod = 0
# ====================== 1. 处理 lib 下所有 .py ======================
for root, _, files in os.walk(ROOT_DIR):
for file in files:
if file.endswith(".py"):
file_path = os.path.join(root, file)
try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
if new_input == "":
replace_target = snake_to_upper_camel(old_str)
new_content = content.replace(old_str, replace_target)
else:
new_content = content.replace(old_str, new_input)
if new_content != content:
with open(file_path, "w", encoding="utf-8") as f:
f.write(new_content)
print(f"已修改:{file_path}")
total_mod += 1
except Exception as err:
print(f"异常 {file_path}:{err}")
# ====================== 2. 处理根目录下 3 个指定文件 ======================
for file_path in EXTRA_FILES:
if os.path.exists(file_path):
try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
if new_input == "":
replace_target = snake_to_upper_camel(old_str)
new_content = content.replace(old_str, replace_target)
else:
new_content = content.replace(old_str, new_input)
if new_content != content:
with open(file_path, "w", encoding="utf-8") as f:
f.write(new_content)
print(f"已修改:{file_path}")
total_mod += 1
except Exception as err:
print(f"异常 {file_path}:{err}")
print(f"\n处理完成,共计修改 {total_mod} 个文件\n")
+66
View File
@@ -0,0 +1,66 @@
import time
import datetime
import requests
import pygame
import os
def PlayWarning():
try:
pygame.mixer.init()
pygame.mixer.music.load("./warn.mp3")
pygame.mixer.music.play(-1)
except Exception as e:
print(f"播放报警失败: {e}")
def StopWarning():
try:
if pygame.mixer.get_init():
pygame.mixer.music.stop()
pygame.mixer.quit()
except Exception as e:
print(f"停止报警失败: {e}")
def CheckBaidu():
try:
return requests.get("https://www.baidu.com", timeout=10).status_code == 200
except:
return False
def IsAlarmTime():
now = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8)))
return 7 <= now.hour <= 22
def Main():
print("进程启动,开始监控...")
consecutiveFailures = 0
warningPlaying = False
while True:
success = CheckBaidu()
if success:
print("访问成功")
consecutiveFailures = 0
if warningPlaying:
StopWarning()
warningPlaying = False
time.sleep(10)
else:
consecutiveFailures += 1
print(f"访问失败,连续次数: {consecutiveFailures}")
if consecutiveFailures >= 5 and IsAlarmTime() and not warningPlaying:
print("开始播放报警音频...")
PlayWarning()
warningPlaying = True
elif consecutiveFailures >= 5 and not IsAlarmTime() and warningPlaying:
StopWarning()
warningPlaying = False
time.sleep(1 if consecutiveFailures >= 5 else 5)
if __name__ == "__main__":
if not os.path.exists("./warn.mp3"):
print("错误: 未找到 ./warn.mp3")
exit(1)
Main()