mirror of
https://github.com/Cp0204/quark-auto-save.git
synced 2026-01-16 01:10:44 +08:00
新增显示最近更新日期、最近转存文件和当日更新标识功能,优化文件表格的图标显示
Merge pull request #32 from x1ao4/dev
This commit is contained in:
commit
34738f2ac0
@ -12,6 +12,7 @@
|
|||||||
- **查重逻辑**:支持优先通过历史转存记录查重,对于有转存记录的文件,即使删除网盘文件,也不会重复转存。
|
- **查重逻辑**:支持优先通过历史转存记录查重,对于有转存记录的文件,即使删除网盘文件,也不会重复转存。
|
||||||
- **Aria2**:支持成功添加 Aria2 下载任务后自动删除夸克网盘内对应的文件,清理网盘空间。
|
- **Aria2**:支持成功添加 Aria2 下载任务后自动删除夸克网盘内对应的文件,清理网盘空间。
|
||||||
- **文件整理**:支持浏览和管理多个夸克账号的网盘文件,支持单项/批量重命名(支持应用完整的命名、过滤规则和撤销重命名等操作)、移动文件、删除文件、新建文件夹等操作。
|
- **文件整理**:支持浏览和管理多个夸克账号的网盘文件,支持单项/批量重命名(支持应用完整的命名、过滤规则和撤销重命名等操作)、移动文件、删除文件、新建文件夹等操作。
|
||||||
|
- **更新状态**:支持在任务列表页面显示任务的最近更新日期、最近转存文件,支持在任务列表、转存记录、文件整理页面显示当日更新标识(对于当日更新的内容)。
|
||||||
|
|
||||||
本项目修改后的版本为个人需求定制版,目的是满足我自己的使用需求,某些(我不用的)功能可能会因为修改而出现 BUG,不一定会被修复。若你要使用本项目,请知晓本人不是程序员,我无法保证本项目的稳定性,如果你在使用过程中发现了 BUG,可以在 Issues 中提交,但不保证每个 BUG 都能被修复,请谨慎使用,风险自担。
|
本项目修改后的版本为个人需求定制版,目的是满足我自己的使用需求,某些(我不用的)功能可能会因为修改而出现 BUG,不一定会被修复。若你要使用本项目,请知晓本人不是程序员,我无法保证本项目的稳定性,如果你在使用过程中发现了 BUG,可以在 Issues 中提交,但不保证每个 BUG 都能被修复,请谨慎使用,风险自担。
|
||||||
|
|
||||||
|
|||||||
137
app/run.py
137
app/run.py
@ -40,6 +40,35 @@ from quark_auto_save import Config, format_bytes
|
|||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
from quark_auto_save import extract_episode_number, sort_file_by_name, chinese_to_arabic, is_date_format
|
from quark_auto_save import extract_episode_number, sort_file_by_name, chinese_to_arabic, is_date_format
|
||||||
|
|
||||||
|
|
||||||
|
def process_season_episode_info(filename):
|
||||||
|
"""
|
||||||
|
处理文件名中的季数和集数信息
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename: 文件名(不含扩展名)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
处理后的显示名称
|
||||||
|
"""
|
||||||
|
# 匹配 SxxExx 格式(不区分大小写)
|
||||||
|
# 支持 S1E1, S01E01, s13e10 等格式
|
||||||
|
season_episode_match = re.search(r'[Ss](\d{1,2})[Ee](\d{1,3})', filename)
|
||||||
|
if season_episode_match:
|
||||||
|
season = season_episode_match.group(1).zfill(2) # 确保两位数
|
||||||
|
episode = season_episode_match.group(2).zfill(2) # 确保两位数
|
||||||
|
return f"S{season}E{episode}"
|
||||||
|
|
||||||
|
# 匹配只有 Exx 或 EPxx 格式(不区分大小写)
|
||||||
|
# 支持 E1, E01, EP1, EP01, e10, ep10 等格式
|
||||||
|
episode_only_match = re.search(r'[Ee][Pp]?(\d{1,3})', filename)
|
||||||
|
if episode_only_match:
|
||||||
|
episode = episode_only_match.group(1).zfill(2) # 确保两位数
|
||||||
|
return f"E{episode}"
|
||||||
|
|
||||||
|
# 如果没有匹配到季数集数信息,返回原文件名
|
||||||
|
return filename
|
||||||
|
|
||||||
# 导入拼音排序工具
|
# 导入拼音排序工具
|
||||||
try:
|
try:
|
||||||
from utils.pinyin_sort import get_filename_pinyin_sort_key
|
from utils.pinyin_sort import get_filename_pinyin_sort_key
|
||||||
@ -1358,12 +1387,118 @@ def delete_history_records():
|
|||||||
deleted_count += db.delete_record(record_id)
|
deleted_count += db.delete_record(record_id)
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"success": True,
|
"success": True,
|
||||||
"message": f"成功删除 {deleted_count} 条记录",
|
"message": f"成功删除 {deleted_count} 条记录",
|
||||||
"deleted_count": deleted_count
|
"deleted_count": deleted_count
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
# 获取任务最新转存信息(包括日期和文件)
|
||||||
|
@app.route("/task_latest_info")
|
||||||
|
def get_task_latest_info():
|
||||||
|
if not is_login():
|
||||||
|
return jsonify({"success": False, "message": "未登录"})
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 初始化数据库
|
||||||
|
db = RecordDB()
|
||||||
|
cursor = db.conn.cursor()
|
||||||
|
|
||||||
|
# 获取所有任务的最新转存时间
|
||||||
|
query = """
|
||||||
|
SELECT task_name, MAX(transfer_time) as latest_transfer_time
|
||||||
|
FROM transfer_records
|
||||||
|
WHERE task_name != 'rename'
|
||||||
|
GROUP BY task_name
|
||||||
|
"""
|
||||||
|
cursor.execute(query)
|
||||||
|
latest_times = cursor.fetchall()
|
||||||
|
|
||||||
|
task_latest_records = {} # 存储最新转存日期
|
||||||
|
task_latest_files = {} # 存储最新转存文件
|
||||||
|
|
||||||
|
for task_name, latest_time in latest_times:
|
||||||
|
if latest_time:
|
||||||
|
# 1. 处理最新转存日期
|
||||||
|
try:
|
||||||
|
# 确保时间戳在合理范围内
|
||||||
|
timestamp = int(latest_time)
|
||||||
|
if timestamp > 9999999999: # 检测是否为毫秒级时间戳(13位)
|
||||||
|
timestamp = timestamp / 1000 # 转换为秒级时间戳
|
||||||
|
|
||||||
|
if 0 < timestamp < 4102444800: # 从1970年到2100年的合理时间戳范围
|
||||||
|
# 格式化为月-日格式(用于显示)和完整日期(用于今日判断)
|
||||||
|
date_obj = datetime.fromtimestamp(timestamp)
|
||||||
|
formatted_date = date_obj.strftime("%m-%d")
|
||||||
|
full_date = date_obj.strftime("%Y-%m-%d")
|
||||||
|
task_latest_records[task_name] = {
|
||||||
|
"display": formatted_date, # 显示用的 MM-DD 格式
|
||||||
|
"full": full_date # 比较用的 YYYY-MM-DD 格式
|
||||||
|
}
|
||||||
|
except (ValueError, TypeError, OverflowError):
|
||||||
|
pass # 忽略无效的时间戳
|
||||||
|
|
||||||
|
# 2. 处理最新转存文件
|
||||||
|
# 获取该任务在最新转存时间附近(同一分钟内)的所有文件
|
||||||
|
# 这样可以处理同时转存多个文件但时间戳略有差异的情况
|
||||||
|
time_window = 60000 # 60秒的时间窗口(毫秒)
|
||||||
|
query = """
|
||||||
|
SELECT renamed_to, original_name, transfer_time, modify_date
|
||||||
|
FROM transfer_records
|
||||||
|
WHERE task_name = ? AND transfer_time >= ? AND transfer_time <= ?
|
||||||
|
ORDER BY id DESC
|
||||||
|
"""
|
||||||
|
cursor.execute(query, (task_name, latest_time - time_window, latest_time + time_window))
|
||||||
|
files = cursor.fetchall()
|
||||||
|
|
||||||
|
if files:
|
||||||
|
if len(files) == 1:
|
||||||
|
# 如果只有一个文件,直接使用
|
||||||
|
best_file = files[0][0] # renamed_to
|
||||||
|
else:
|
||||||
|
# 如果有多个文件,使用全局排序函数进行排序
|
||||||
|
file_list = []
|
||||||
|
for renamed_to, original_name, transfer_time, modify_date in files:
|
||||||
|
# 构造文件信息字典,模拟全局排序函数需要的格式
|
||||||
|
file_info = {
|
||||||
|
'file_name': renamed_to,
|
||||||
|
'original_name': original_name,
|
||||||
|
'updated_at': transfer_time # 使用转存时间而不是文件修改时间
|
||||||
|
}
|
||||||
|
file_list.append(file_info)
|
||||||
|
|
||||||
|
# 使用全局排序函数进行正向排序,最后一个就是最新的
|
||||||
|
try:
|
||||||
|
sorted_files = sorted(file_list, key=sort_file_by_name)
|
||||||
|
best_file = sorted_files[-1]['file_name'] # 取排序后的最后一个文件
|
||||||
|
except Exception as e:
|
||||||
|
# 如果排序失败,使用第一个文件作为备选
|
||||||
|
best_file = files[0][0]
|
||||||
|
|
||||||
|
# 去除扩展名并处理季数集数信息
|
||||||
|
if best_file:
|
||||||
|
file_name_without_ext = os.path.splitext(best_file)[0]
|
||||||
|
processed_name = process_season_episode_info(file_name_without_ext)
|
||||||
|
task_latest_files[task_name] = processed_name
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"data": {
|
||||||
|
"latest_records": task_latest_records,
|
||||||
|
"latest_files": task_latest_files
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({
|
||||||
|
"success": False,
|
||||||
|
"message": f"获取任务最新信息失败: {str(e)}"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 删除单条转存记录
|
# 删除单条转存记录
|
||||||
@app.route("/delete_history_record", methods=["POST"])
|
@app.route("/delete_history_record", methods=["POST"])
|
||||||
def delete_history_record():
|
def delete_history_record():
|
||||||
|
|||||||
@ -1678,7 +1678,7 @@ button.close:focus,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#fileSelectModal .table .text-warning {
|
#fileSelectModal .table .text-warning {
|
||||||
color: #ffc107 !important;
|
color: #098eff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 弹窗内表格行悬停效果 */
|
/* 弹窗内表格行悬停效果 */
|
||||||
@ -1687,7 +1687,20 @@ button.close:focus,
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#fileSelectModal .bi-file-earmark {
|
#fileSelectModal .bi-file-earmark,
|
||||||
|
#fileSelectModal .bi-file-earmark-play,
|
||||||
|
#fileSelectModal .bi-file-earmark-music,
|
||||||
|
#fileSelectModal .bi-file-earmark-image,
|
||||||
|
#fileSelectModal .bi-file-earmark-text,
|
||||||
|
#fileSelectModal .bi-file-earmark-richtext,
|
||||||
|
#fileSelectModal .bi-file-earmark-zip,
|
||||||
|
#fileSelectModal .bi-file-earmark-font,
|
||||||
|
#fileSelectModal .bi-file-earmark-code,
|
||||||
|
#fileSelectModal .bi-file-earmark-pdf,
|
||||||
|
#fileSelectModal .bi-file-earmark-word,
|
||||||
|
#fileSelectModal .bi-file-earmark-excel,
|
||||||
|
#fileSelectModal .bi-file-earmark-ppt,
|
||||||
|
#fileSelectModal .bi-file-earmark-medical {
|
||||||
color: var(--dark-text-color);
|
color: var(--dark-text-color);
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
@ -3915,7 +3928,7 @@ table.selectable-records .expand-button:hover {
|
|||||||
|
|
||||||
/* 模态框通用文件夹图标样式 */
|
/* 模态框通用文件夹图标样式 */
|
||||||
#fileSelectModal .bi-folder-fill {
|
#fileSelectModal .bi-folder-fill {
|
||||||
color: #ffc107;
|
color: #098eff;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
margin-right: 4px !important;
|
margin-right: 4px !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -3924,7 +3937,20 @@ table.selectable-records .expand-button:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 模态框通用文件图标样式 */
|
/* 模态框通用文件图标样式 */
|
||||||
#fileSelectModal .bi-file-earmark {
|
#fileSelectModal .bi-file-earmark,
|
||||||
|
#fileSelectModal .bi-file-earmark-play,
|
||||||
|
#fileSelectModal .bi-file-earmark-music,
|
||||||
|
#fileSelectModal .bi-file-earmark-image,
|
||||||
|
#fileSelectModal .bi-file-earmark-text,
|
||||||
|
#fileSelectModal .bi-file-earmark-richtext,
|
||||||
|
#fileSelectModal .bi-file-earmark-zip,
|
||||||
|
#fileSelectModal .bi-file-earmark-font,
|
||||||
|
#fileSelectModal .bi-file-earmark-code,
|
||||||
|
#fileSelectModal .bi-file-earmark-pdf,
|
||||||
|
#fileSelectModal .bi-file-earmark-word,
|
||||||
|
#fileSelectModal .bi-file-earmark-excel,
|
||||||
|
#fileSelectModal .bi-file-earmark-ppt,
|
||||||
|
#fileSelectModal .bi-file-earmark-medical {
|
||||||
color: var(--dark-text-color);
|
color: var(--dark-text-color);
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
margin-right: 4px !important;
|
margin-right: 4px !important;
|
||||||
@ -3994,7 +4020,6 @@ table.selectable-records .expand-button:hover {
|
|||||||
/* 任务按钮悬停显示样式 */
|
/* 任务按钮悬停显示样式 */
|
||||||
.task-buttons .hover-only {
|
.task-buttons .hover-only {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.2s ease-in-out;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
@ -4029,24 +4054,92 @@ table.selectable-records .expand-button:hover {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 任务最近更新日期样式 */
|
||||||
|
.task-latest-date {
|
||||||
|
color: var(--dark-text-color);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 任务最近转存文件样式 */
|
||||||
|
.task-latest-file {
|
||||||
|
color: var(--dark-text-color);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 悬停显示模式 - 使用display来避免占用空间,同时保持平滑的悬停效果 */
|
||||||
|
.task-latest-date.hover-only,
|
||||||
|
.task-latest-file.hover-only {
|
||||||
|
display: none;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task .btn:hover .task-latest-date.hover-only,
|
||||||
|
.task .btn:hover .task-latest-file.hover-only {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 显示设置行样式 */
|
||||||
|
.display-setting-row > [class*='col-'] {
|
||||||
|
padding-left: 4px !important;
|
||||||
|
padding-right: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当天更新指示器样式 */
|
||||||
|
.task-today-indicator {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 0.92rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-today-indicator i {
|
||||||
|
background: linear-gradient(45deg, #03d5ff 25%, var(--focus-border-color) 60%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
color: var(--focus-border-color); /* 备用颜色,以防渐变不支持 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当日更新图标悬停显示样式 */
|
||||||
|
.task-today-indicator.hover-only {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 任务列表页面悬停显示 */
|
||||||
|
.task:hover .task-today-indicator.hover-only {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 转存记录页面悬停显示 */
|
||||||
|
.table-hover tbody tr:hover .task-today-indicator.hover-only {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 文件整理页面悬停显示 */
|
||||||
|
.selectable-files tbody tr:hover .task-today-indicator.hover-only {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-setting-row {
|
||||||
|
margin-left: -4px !important;
|
||||||
|
margin-right: -4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 992px) {
|
@media (min-width: 992px) {
|
||||||
.display-setting-row > .col-lg-3 {
|
.display-setting-row > .col-lg-3 {
|
||||||
padding-left: 4px !important;
|
padding-left: 4px !important;
|
||||||
padding-right: 4px !important;
|
padding-right: 4px !important;
|
||||||
}
|
}
|
||||||
.display-setting-row {
|
|
||||||
margin-left: -4px !important;
|
|
||||||
margin-right: -4px !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.display-setting-row > [class*='col-'] {
|
/* 调整显示设置第二行的上边距,使其与第一行保持8px间距 */
|
||||||
padding-left: 4px !important;
|
.display-setting-row + .display-setting-row {
|
||||||
padding-right: 4px !important;
|
margin-top: -8px !important;
|
||||||
}
|
|
||||||
.display-setting-row {
|
|
||||||
margin-left: -4px !important;
|
|
||||||
margin-right: -4px !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 文件整理性能设置样式 */
|
/* 文件整理性能设置样式 */
|
||||||
@ -4075,22 +4168,6 @@ table.selectable-records .expand-button:hover {
|
|||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 任务按钮悬停显示样式 */
|
|
||||||
.task-buttons .hover-only {
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.2s ease-in-out;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 修改悬停触发范围到整个任务单元 */
|
|
||||||
.task:hover .task-buttons .hover-only {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 确保按钮容器在悬停时保持宽度 */
|
/* 确保按钮容器在悬停时保持宽度 */
|
||||||
.task-buttons {
|
.task-buttons {
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -5228,7 +5305,20 @@ body .selectable-files tr.selected-file:has([style*="white-space: normal"]) .fil
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 文件整理页面的文件图标样式 */
|
/* 文件整理页面的文件图标样式 */
|
||||||
.selectable-files .bi-file-earmark {
|
.selectable-files .bi-file-earmark,
|
||||||
|
.selectable-files .bi-file-earmark-play,
|
||||||
|
.selectable-files .bi-file-earmark-music,
|
||||||
|
.selectable-files .bi-file-earmark-image,
|
||||||
|
.selectable-files .bi-file-earmark-text,
|
||||||
|
.selectable-files .bi-file-earmark-richtext,
|
||||||
|
.selectable-files .bi-file-earmark-zip,
|
||||||
|
.selectable-files .bi-file-earmark-font,
|
||||||
|
.selectable-files .bi-file-earmark-code,
|
||||||
|
.selectable-files .bi-file-earmark-pdf,
|
||||||
|
.selectable-files .bi-file-earmark-word,
|
||||||
|
.selectable-files .bi-file-earmark-excel,
|
||||||
|
.selectable-files .bi-file-earmark-ppt,
|
||||||
|
.selectable-files .bi-file-earmark-medical {
|
||||||
font-size: 1.06rem; /* 比模态框的0.95rem大一些 */
|
font-size: 1.06rem; /* 比模态框的0.95rem大一些 */
|
||||||
margin-right: 7px !important; /* 图标距离文本的距离 */
|
margin-right: 7px !important; /* 图标距离文本的距离 */
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -5243,7 +5333,7 @@ body .selectable-files tr.selected-file:has([style*="white-space: normal"]) .fil
|
|||||||
position: relative;
|
position: relative;
|
||||||
top: 1px; /* 可微调垂直对齐 */
|
top: 1px; /* 可微调垂直对齐 */
|
||||||
left: -1px; /* 可微调水平对齐 */
|
left: -1px; /* 可微调水平对齐 */
|
||||||
color: #ffc107; /* 保持黄色 */
|
color: #098eff; /* 55%接近深蓝色 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 文件整理页面无法识别剧集编号样式 */
|
/* 文件整理页面无法识别剧集编号样式 */
|
||||||
|
|||||||
@ -69,18 +69,109 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 根据文件扩展名获取对应的Bootstrap图标类名
|
||||||
|
function getFileIconClass(fileName, isDir = false) {
|
||||||
|
// 如果是文件夹,返回文件夹图标
|
||||||
|
if (isDir) {
|
||||||
|
return 'bi-folder-fill';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件扩展名(转为小写)
|
||||||
|
const ext = fileName.toLowerCase().split('.').pop();
|
||||||
|
|
||||||
|
// 视频文件
|
||||||
|
const videoExts = ['mp4', 'mkv', 'avi', 'mov', 'rmvb', 'flv', 'wmv', 'm4v', 'ts', 'webm', '3gp', 'f4v'];
|
||||||
|
if (videoExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-play';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 音频文件
|
||||||
|
const audioExts = ['mp3', 'wav', 'flac', 'aac', 'ogg', 'm4a', 'wma', 'ape', 'ac3', 'dts'];
|
||||||
|
if (audioExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-music';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片文件
|
||||||
|
const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff', 'svg', 'ico', 'raw'];
|
||||||
|
if (imageExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-image';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文本文件(包括歌词文件和字幕文件)
|
||||||
|
const textExts = ['txt', 'md', 'rtf', 'log', 'ini', 'cfg', 'conf', 'lrc', 'srt', 'ass', 'ssa', 'vtt', 'sup'];
|
||||||
|
if (textExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-text';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 富文本文件
|
||||||
|
const richtextExts = ['rtf', 'odt'];
|
||||||
|
if (richtextExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-richtext';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 压缩文件
|
||||||
|
const archiveExts = ['zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'lzma', 'cab', 'iso'];
|
||||||
|
if (archiveExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-zip';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字体文件
|
||||||
|
const fontExts = ['ttf', 'otf', 'woff', 'woff2', 'eot'];
|
||||||
|
if (fontExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-font';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 代码文件
|
||||||
|
const codeExts = ['js', 'html', 'css', 'py', 'java', 'c', 'cpp', 'php', 'go', 'json', 'xml', 'yml', 'yaml', 'sql', 'sh', 'bat', 'ps1', 'rb', 'swift', 'kt', 'ts', 'jsx', 'tsx', 'vue', 'scss', 'sass', 'less'];
|
||||||
|
if (codeExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-code';
|
||||||
|
}
|
||||||
|
|
||||||
|
// PDF文件
|
||||||
|
if (ext === 'pdf') {
|
||||||
|
return 'bi-file-earmark-pdf';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word文档
|
||||||
|
const wordExts = ['doc', 'docx'];
|
||||||
|
if (wordExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-word';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Excel文档
|
||||||
|
const excelExts = ['xls', 'xlsx', 'csv'];
|
||||||
|
if (excelExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-excel';
|
||||||
|
}
|
||||||
|
|
||||||
|
// PowerPoint文档
|
||||||
|
const pptExts = ['ppt', 'pptx'];
|
||||||
|
if (pptExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-ppt';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 医疗/健康相关文件
|
||||||
|
const medicalExts = ['dcm', 'dicom', 'hl7'];
|
||||||
|
if (medicalExts.includes(ext)) {
|
||||||
|
return 'bi-file-earmark-medical';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认文件图标
|
||||||
|
return 'bi-file-earmark';
|
||||||
|
}
|
||||||
|
|
||||||
// 添加检测文件整理页面文件名溢出的自定义指令
|
// 添加检测文件整理页面文件名溢出的自定义指令
|
||||||
Vue.directive('check-file-overflow', {
|
Vue.directive('check-file-overflow', {
|
||||||
inserted: function(el, binding, vnode) {
|
inserted: function(el, binding, vnode) {
|
||||||
// 检查元素是否溢出
|
// 检查元素是否溢出
|
||||||
const isOverflowing = el.scrollWidth > el.clientWidth;
|
const isOverflowing = el.scrollWidth > el.clientWidth;
|
||||||
|
|
||||||
// 如果绑定了值,则绑定到该值对应的文件属性上
|
// 如果绑定了值,则绑定到该值对应的文件属性上
|
||||||
if (binding.value) {
|
if (binding.value) {
|
||||||
const indexAndField = binding.value.split('|');
|
const indexAndField = binding.value.split('|');
|
||||||
const index = parseInt(indexAndField[0]);
|
const index = parseInt(indexAndField[0]);
|
||||||
const field = indexAndField[1];
|
const field = indexAndField[1];
|
||||||
|
|
||||||
// 设置文件的_isOverflowing属性
|
// 设置文件的_isOverflowing属性
|
||||||
const files = vnode.context.fileManager.fileList;
|
const files = vnode.context.fileManager.fileList;
|
||||||
if (files && files[index]) {
|
if (files && files[index]) {
|
||||||
@ -97,13 +188,13 @@
|
|||||||
update: function(el, binding, vnode) {
|
update: function(el, binding, vnode) {
|
||||||
// 检查元素是否溢出
|
// 检查元素是否溢出
|
||||||
const isOverflowing = el.scrollWidth > el.clientWidth;
|
const isOverflowing = el.scrollWidth > el.clientWidth;
|
||||||
|
|
||||||
// 如果绑定了值,则绑定到该值对应的文件属性上
|
// 如果绑定了值,则绑定到该值对应的文件属性上
|
||||||
if (binding.value) {
|
if (binding.value) {
|
||||||
const indexAndField = binding.value.split('|');
|
const indexAndField = binding.value.split('|');
|
||||||
const index = parseInt(indexAndField[0]);
|
const index = parseInt(indexAndField[0]);
|
||||||
const field = indexAndField[1];
|
const field = indexAndField[1];
|
||||||
|
|
||||||
// 设置文件的_isOverflowing属性
|
// 设置文件的_isOverflowing属性
|
||||||
const files = vnode.context.fileManager.fileList;
|
const files = vnode.context.fileManager.fileList;
|
||||||
if (files && files[index]) {
|
if (files && files[index]) {
|
||||||
@ -614,6 +705,44 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-2 display-setting-row">
|
||||||
|
<div class="col-lg-3 col-md-6 mb-2">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">最近更新日期</span>
|
||||||
|
</div>
|
||||||
|
<select class="form-control" v-model="formData.button_display.latest_update_date">
|
||||||
|
<option value="always">始终显示</option>
|
||||||
|
<option value="hover">悬停显示</option>
|
||||||
|
<option value="disabled">禁用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-3 col-md-6 mb-2">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">最近转存文件</span>
|
||||||
|
</div>
|
||||||
|
<select class="form-control" v-model="formData.button_display.latest_transfer_file">
|
||||||
|
<option value="always">始终显示</option>
|
||||||
|
<option value="hover">悬停显示</option>
|
||||||
|
<option value="disabled">禁用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-3 col-md-6 mb-2">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">当日更新标识</span>
|
||||||
|
</div>
|
||||||
|
<select class="form-control" v-model="formData.button_display.today_update_indicator">
|
||||||
|
<option value="always">始终显示</option>
|
||||||
|
<option value="hover">悬停显示</option>
|
||||||
|
<option value="disabled">禁用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 性能设置 -->
|
<!-- 性能设置 -->
|
||||||
<div class="row title" title="调整文件整理页面的请求参数和缓存时长,可提升大文件夹的加载速度和数据刷新效率。合理配置可减少API请求次数,同时保证数据及时更新">
|
<div class="row title" title="调整文件整理页面的请求参数和缓存时长,可提升大文件夹的加载速度和数据刷新效率。合理配置可减少API请求次数,同时保证数据及时更新">
|
||||||
@ -690,6 +819,21 @@
|
|||||||
<div class="col pl-0" data-toggle="collapse" :data-target="'#collapse_'+index" aria-expanded="true" :aria-controls="'collapse_'+index">
|
<div class="col pl-0" data-toggle="collapse" :data-target="'#collapse_'+index" aria-expanded="true" :aria-controls="'collapse_'+index">
|
||||||
<div class="btn btn-block text-left">
|
<div class="btn btn-block text-left">
|
||||||
<i class="bi bi-caret-right-fill"></i> #<span v-html="`${String(index+1).padStart(2, '0')} ${task.taskname}`"></span>
|
<i class="bi bi-caret-right-fill"></i> #<span v-html="`${String(index+1).padStart(2, '0')} ${task.taskname}`"></span>
|
||||||
|
<span v-if="formData.button_display.latest_update_date !== 'disabled' && taskLatestRecords[task.taskname]"
|
||||||
|
class="task-latest-date"
|
||||||
|
:class="{'hover-only': formData.button_display.latest_update_date === 'hover'}">
|
||||||
|
· {{ getTaskLatestRecordDisplay(task.taskname) }}
|
||||||
|
</span>
|
||||||
|
<span v-if="formData.button_display.latest_transfer_file !== 'disabled' && taskLatestFiles[task.taskname]"
|
||||||
|
class="task-latest-file"
|
||||||
|
:class="{'hover-only': formData.button_display.latest_transfer_file === 'hover'}">
|
||||||
|
· {{ taskLatestFiles[task.taskname] }}
|
||||||
|
</span>
|
||||||
|
<span v-if="isTaskUpdatedToday(task.taskname) && shouldShowTodayIndicator()"
|
||||||
|
class="task-today-indicator"
|
||||||
|
:class="getTodayIndicatorClass()">
|
||||||
|
<i class="bi bi-stars"></i>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto task-buttons">
|
<div class="col-auto task-buttons">
|
||||||
@ -946,17 +1090,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="position-relative">
|
<td class="position-relative">
|
||||||
<div v-if="!record._expandedFields || !record._expandedFields.includes('renamed_to')"
|
<div v-if="!record._expandedFields || !record._expandedFields.includes('renamed_to')"
|
||||||
class="text-truncate"
|
class="text-truncate"
|
||||||
:title="record.renamed_to"
|
:title="record.renamed_to"
|
||||||
v-check-overflow="index + '|renamed_to'">
|
v-check-overflow="index + '|renamed_to'">
|
||||||
{{ record.renamed_to }}
|
{{ record.renamed_to }}
|
||||||
|
<span v-if="isRecordUpdatedToday(record) && shouldShowTodayIndicator()"
|
||||||
|
class="task-today-indicator"
|
||||||
|
:class="getTodayIndicatorClass()">
|
||||||
|
<i class="bi bi-stars"></i>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="expand-button" v-if="isTextTruncated(record.renamed_to, index, 'renamed_to')" @click.stop="toggleExpand(index, 'renamed_to', $event)">
|
<div class="expand-button" v-if="isTextTruncated(record.renamed_to, index, 'renamed_to')" @click.stop="toggleExpand(index, 'renamed_to', $event)">
|
||||||
<i :class="record._expandedFields && record._expandedFields.length > 0 ? 'bi bi-chevron-up' : 'bi bi-chevron-down'"></i>
|
<i :class="record._expandedFields && record._expandedFields.length > 0 ? 'bi bi-chevron-up' : 'bi bi-chevron-down'"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="expanded-text" v-if="record._expandedFields && record._expandedFields.includes('renamed_to')">
|
<div class="expanded-text" v-if="record._expandedFields && record._expandedFields.includes('renamed_to')">
|
||||||
{{ record.renamed_to }}
|
{{ record.renamed_to }}
|
||||||
|
<span v-if="isRecordUpdatedToday(record) && shouldShowTodayIndicator()"
|
||||||
|
class="task-today-indicator"
|
||||||
|
:class="getTodayIndicatorClass()">
|
||||||
|
<i class="bi bi-stars"></i>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="file-size-cell">
|
<td class="file-size-cell">
|
||||||
@ -1181,7 +1335,7 @@
|
|||||||
<td class="position-relative">
|
<td class="position-relative">
|
||||||
<!-- 编辑状态 -->
|
<!-- 编辑状态 -->
|
||||||
<div v-if="file._editing" class="d-flex align-items-center" @click.stop>
|
<div v-if="file._editing" class="d-flex align-items-center" @click.stop>
|
||||||
<i class="bi mr-2" :class="file.dir ? 'bi-folder-fill text-warning' : 'bi-file-earmark'"></i>
|
<i class="bi mr-2" :class="getFileIconClass(file.file_name, file.dir)"></i>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="form-control form-control-sm rename-input"
|
class="form-control form-control-sm rename-input"
|
||||||
@ -1194,15 +1348,25 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 正常显示状态 -->
|
<!-- 正常显示状态 -->
|
||||||
<div v-else-if="!file._expanded" class="d-flex align-items-center">
|
<div v-else-if="!file._expanded" class="d-flex align-items-center">
|
||||||
<i class="bi mr-2" :class="file.dir ? 'bi-folder-fill text-warning' : 'bi-file-earmark'"></i>
|
<i class="bi mr-2" :class="getFileIconClass(file.file_name, file.dir)"></i>
|
||||||
<div class="text-truncate"
|
<div class="text-truncate"
|
||||||
:title="file.file_name"
|
:title="file.file_name"
|
||||||
v-check-file-overflow="index + '|file_name'">
|
v-check-file-overflow="index + '|file_name'">
|
||||||
{{ file.file_name }}
|
{{ file.file_name }}
|
||||||
|
<span v-if="isFileUpdatedToday(file) && shouldShowTodayIndicator()"
|
||||||
|
class="task-today-indicator"
|
||||||
|
:class="getTodayIndicatorClass()">
|
||||||
|
<i class="bi bi-stars"></i>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else style="white-space: normal; word-break: break-word; padding-right: 25px;">
|
<div v-else style="white-space: normal; word-break: break-word; padding-right: 25px;">
|
||||||
<i class="bi mr-2" :class="file.dir ? 'bi-folder-fill text-warning' : 'bi-file-earmark'"></i>{{ file.file_name }}
|
<i class="bi mr-2" :class="getFileIconClass(file.file_name, file.dir)"></i>{{ file.file_name }}
|
||||||
|
<span v-if="isFileUpdatedToday(file) && shouldShowTodayIndicator()"
|
||||||
|
class="task-today-indicator"
|
||||||
|
:class="getTodayIndicatorClass()">
|
||||||
|
<i class="bi bi-stars"></i>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="expand-button" v-if="!file._editing && isFilenameTruncated(file.file_name, index, 'file_name')" @click.stop="toggleExpandFilename(file)">
|
<div class="expand-button" v-if="!file._editing && isFilenameTruncated(file.file_name, index, 'file_name')" @click.stop="toggleExpandFilename(file)">
|
||||||
<i :class="file._expanded ? 'bi bi-chevron-up' : 'bi bi-chevron-down'"></i>
|
<i :class="file._expanded ? 'bi bi-chevron-up' : 'bi bi-chevron-down'"></i>
|
||||||
@ -1413,13 +1577,13 @@
|
|||||||
style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-right: 25px;"
|
style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-right: 25px;"
|
||||||
:title="file.file_name"
|
:title="file.file_name"
|
||||||
v-check-modal-overflow="key + '|file_name'">
|
v-check-modal-overflow="key + '|file_name'">
|
||||||
<i class="bi" :class="file.dir ? 'bi-folder-fill text-warning' : 'bi-file-earmark'"></i> {{file.file_name}}
|
<i class="bi" :class="getFileIconClass(file.file_name, file.dir)"></i> {{file.file_name}}
|
||||||
</div>
|
</div>
|
||||||
<div class="expand-button" v-if="isModalTextTruncated(file.file_name, key, 'file_name')" @click.stop="toggleModalExpand(key, 'file_name')">
|
<div class="expand-button" v-if="isModalTextTruncated(file.file_name, key, 'file_name')" @click.stop="toggleModalExpand(key, 'file_name')">
|
||||||
<i :class="file._expandedFields && file._expandedFields.includes('file_name') ? 'bi bi-chevron-up' : 'bi bi-chevron-down'"></i>
|
<i :class="file._expandedFields && file._expandedFields.includes('file_name') ? 'bi bi-chevron-up' : 'bi bi-chevron-down'"></i>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="file._expandedFields && file._expandedFields.includes('file_name')" style="white-space: normal; word-break: break-word; padding-right: 25px; display: block; width: 100%; position: relative;">
|
<div v-if="file._expandedFields && file._expandedFields.includes('file_name')" style="white-space: normal; word-break: break-word; padding-right: 25px; display: block; width: 100%; position: relative;">
|
||||||
<i class="bi" :class="file.dir ? 'bi-folder-fill text-warning' : 'bi-file-earmark'"></i> {{file.file_name}}
|
<i class="bi" :class="getFileIconClass(file.file_name, file.dir)"></i> {{file.file_name}}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="col-rename position-relative" v-if="fileSelect.selectShare || fileSelect.previewRegex" :class="{'text-success': file.file_name_re && !file.file_name_re.startsWith('×'), 'text-danger': !file.file_name_re || file.file_name_re === '×' || file.file_name_re.startsWith('× ')}" style="padding-left: 5px; vertical-align: top;">
|
<td class="col-rename position-relative" v-if="fileSelect.selectShare || fileSelect.previewRegex" :class="{'text-success': file.file_name_re && !file.file_name_re.startsWith('×'), 'text-danger': !file.file_name_re || file.file_name_re === '×' || file.file_name_re.startsWith('× ')}" style="padding-left: 5px; vertical-align: top;">
|
||||||
@ -1522,7 +1686,10 @@
|
|||||||
run_task: "always",
|
run_task: "always",
|
||||||
delete_task: "always",
|
delete_task: "always",
|
||||||
refresh_plex: "always",
|
refresh_plex: "always",
|
||||||
refresh_alist: "always"
|
refresh_alist: "always",
|
||||||
|
latest_update_date: "always",
|
||||||
|
latest_transfer_file: "always",
|
||||||
|
today_update_indicator: "always"
|
||||||
},
|
},
|
||||||
file_performance: {
|
file_performance: {
|
||||||
api_page_size: 200,
|
api_page_size: 200,
|
||||||
@ -1551,6 +1718,8 @@
|
|||||||
taskDirs: [""],
|
taskDirs: [""],
|
||||||
taskDirSelected: "",
|
taskDirSelected: "",
|
||||||
taskNameFilter: "",
|
taskNameFilter: "",
|
||||||
|
taskLatestRecords: {}, // 存储每个任务的最新转存记录日期
|
||||||
|
taskLatestFiles: {}, // 存储每个任务的最近转存文件
|
||||||
modalLoading: false,
|
modalLoading: false,
|
||||||
smart_param: {
|
smart_param: {
|
||||||
index: null,
|
index: null,
|
||||||
@ -1975,6 +2144,10 @@
|
|||||||
document.removeEventListener('click', this.handleOutsideClick);
|
document.removeEventListener('click', this.handleOutsideClick);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 获取文件图标类名
|
||||||
|
getFileIconClass(fileName, isDir = false) {
|
||||||
|
return getFileIconClass(fileName, isDir);
|
||||||
|
},
|
||||||
// 拼音排序辅助函数
|
// 拼音排序辅助函数
|
||||||
sortTaskNamesByPinyin(taskNames) {
|
sortTaskNamesByPinyin(taskNames) {
|
||||||
return taskNames.sort((a, b) => {
|
return taskNames.sort((a, b) => {
|
||||||
@ -2443,9 +2616,24 @@
|
|||||||
run_task: "always",
|
run_task: "always",
|
||||||
delete_task: "always",
|
delete_task: "always",
|
||||||
refresh_plex: "always",
|
refresh_plex: "always",
|
||||||
refresh_alist: "always"
|
refresh_alist: "always",
|
||||||
|
latest_update_date: "always",
|
||||||
|
latest_transfer_file: "always",
|
||||||
|
today_update_indicator: "always"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// 确保最近更新日期配置存在(向后兼容)
|
||||||
|
if (!config_data.button_display.latest_update_date) {
|
||||||
|
config_data.button_display.latest_update_date = "always";
|
||||||
|
}
|
||||||
|
// 确保最近转存文件配置存在(向后兼容)
|
||||||
|
if (!config_data.button_display.latest_transfer_file) {
|
||||||
|
config_data.button_display.latest_transfer_file = "always";
|
||||||
|
}
|
||||||
|
// 确保当日更新图标配置存在(向后兼容)
|
||||||
|
if (!config_data.button_display.today_update_indicator) {
|
||||||
|
config_data.button_display.today_update_indicator = "always";
|
||||||
|
}
|
||||||
// 确保文件整理性能配置存在
|
// 确保文件整理性能配置存在
|
||||||
if (!config_data.file_performance) {
|
if (!config_data.file_performance) {
|
||||||
config_data.file_performance = {
|
config_data.file_performance = {
|
||||||
@ -2468,7 +2656,10 @@
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.configModified = false;
|
this.configModified = false;
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
|
// 加载任务最新信息(包括记录和文件)
|
||||||
|
this.loadTaskLatestInfo();
|
||||||
|
|
||||||
// 数据加载完成后检查分享链接状态
|
// 数据加载完成后检查分享链接状态
|
||||||
if (this.activeTab === 'tasklist') {
|
if (this.activeTab === 'tasklist') {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -4043,6 +4234,94 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
loadTaskLatestInfo() {
|
||||||
|
// 获取所有任务的最新转存信息(包括日期和文件)
|
||||||
|
axios.get('/task_latest_info')
|
||||||
|
.then(response => {
|
||||||
|
if (response.data.success) {
|
||||||
|
this.taskLatestRecords = response.data.data.latest_records;
|
||||||
|
this.taskLatestFiles = response.data.data.latest_files;
|
||||||
|
} else {
|
||||||
|
console.error('获取任务最新信息失败:', response.data.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('获取任务最新信息失败:', error);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getTaskLatestRecordDisplay(taskName) {
|
||||||
|
// 获取任务最新记录的显示文本
|
||||||
|
const latestRecord = this.taskLatestRecords[taskName];
|
||||||
|
return latestRecord ? latestRecord.display : '';
|
||||||
|
},
|
||||||
|
isTaskUpdatedToday(taskName) {
|
||||||
|
// 检查任务是否在今天更新
|
||||||
|
const latestRecord = this.taskLatestRecords[taskName];
|
||||||
|
if (!latestRecord || !latestRecord.full) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取今天的完整日期,格式为 YYYY-MM-DD
|
||||||
|
const today = new Date();
|
||||||
|
const todayFormatted = today.getFullYear() + '-' +
|
||||||
|
String(today.getMonth() + 1).padStart(2, '0') + '-' +
|
||||||
|
String(today.getDate()).padStart(2, '0');
|
||||||
|
|
||||||
|
return latestRecord.full === todayFormatted;
|
||||||
|
},
|
||||||
|
isRecordUpdatedToday(record) {
|
||||||
|
// 检查转存记录是否在今天更新
|
||||||
|
if (!record || !record.transfer_time_readable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取今天的日期,格式为 YYYY-MM-DD
|
||||||
|
const today = new Date();
|
||||||
|
const todayFormatted = today.getFullYear() + '-' +
|
||||||
|
String(today.getMonth() + 1).padStart(2, '0') + '-' +
|
||||||
|
String(today.getDate()).padStart(2, '0');
|
||||||
|
|
||||||
|
// 从 transfer_time_readable 中提取日期部分(格式通常为 "YYYY-MM-DD HH:MM:SS")
|
||||||
|
const recordDate = record.transfer_time_readable.split(' ')[0];
|
||||||
|
|
||||||
|
return recordDate === todayFormatted;
|
||||||
|
},
|
||||||
|
isFileUpdatedToday(file) {
|
||||||
|
// 检查文件是否在今天更新(基于修改日期)
|
||||||
|
if (!file || !file.updated_at) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取今天的日期,格式为 YYYY-MM-DD
|
||||||
|
const today = new Date();
|
||||||
|
const todayFormatted = today.getFullYear() + '-' +
|
||||||
|
String(today.getMonth() + 1).padStart(2, '0') + '-' +
|
||||||
|
String(today.getDate()).padStart(2, '0');
|
||||||
|
|
||||||
|
// 使用与 formatDate 方法相同的逻辑处理时间戳
|
||||||
|
try {
|
||||||
|
const fileDate = new Date(file.updated_at);
|
||||||
|
const fileDateFormatted = fileDate.getFullYear() + '-' +
|
||||||
|
String(fileDate.getMonth() + 1).padStart(2, '0') + '-' +
|
||||||
|
String(fileDate.getDate()).padStart(2, '0');
|
||||||
|
|
||||||
|
return fileDateFormatted === todayFormatted;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('处理文件时间戳时出错:', error, file.updated_at);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shouldShowTodayIndicator() {
|
||||||
|
// 检查是否应该显示当日更新图标
|
||||||
|
return this.formData.button_display.today_update_indicator !== 'disabled';
|
||||||
|
},
|
||||||
|
getTodayIndicatorClass() {
|
||||||
|
// 获取当日更新图标的CSS类
|
||||||
|
if (this.formData.button_display.today_update_indicator === 'hover') {
|
||||||
|
return 'hover-only';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
openDatePicker(index) {
|
openDatePicker(index) {
|
||||||
// 使用$refs访问对应的日期选择器并打开它
|
// 使用$refs访问对应的日期选择器并打开它
|
||||||
const dateRef = this.$refs[`enddate_${index}`];
|
const dateRef = this.$refs[`enddate_${index}`];
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user