mirror of
https://github.com/Cp0204/quark-auto-save.git
synced 2026-01-12 15:20:44 +08:00
为数据库增加保存路径数据的存储功能,为选择保存到的文件夹页面增加删除文件和记录功能
This commit is contained in:
parent
831a5cfa24
commit
5a5fa4cdeb
49
app/run.py
49
app/run.py
@ -650,6 +650,55 @@ def delete_file():
|
||||
account = Quark(config_data["cookie"][0], 0)
|
||||
if fid := request.json.get("fid"):
|
||||
response = account.delete([fid])
|
||||
|
||||
# 处理delete_records参数
|
||||
if request.json.get("delete_records") and response.get("code") == 0:
|
||||
try:
|
||||
# 初始化数据库
|
||||
db = RecordDB()
|
||||
|
||||
# 获取save_path参数
|
||||
save_path = request.json.get("save_path", "")
|
||||
|
||||
# 如果没有提供save_path,则不删除任何记录
|
||||
if not save_path:
|
||||
response["deleted_records"] = 0
|
||||
# logging.info(f">>> 删除文件 {fid} 但未提供save_path,不删除任何记录")
|
||||
return jsonify(response)
|
||||
|
||||
# 查询与该文件ID和save_path相关的所有记录
|
||||
cursor = db.conn.cursor()
|
||||
|
||||
# 使用file_id和save_path进行精确匹配
|
||||
cursor.execute("SELECT id FROM transfer_records WHERE file_id = ? AND save_path = ?", (fid, save_path))
|
||||
record_ids = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
# 如果没有找到匹配的file_id记录,尝试通过文件名查找
|
||||
if not record_ids:
|
||||
# 获取文件名(如果有的话)
|
||||
file_name = request.json.get("file_name", "")
|
||||
if file_name:
|
||||
# 使用文件名和save_path进行精确匹配
|
||||
cursor.execute("""
|
||||
SELECT id FROM transfer_records
|
||||
WHERE (original_name = ? OR renamed_to = ?)
|
||||
AND save_path = ?
|
||||
""", (file_name, file_name, save_path))
|
||||
|
||||
record_ids = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
# 删除找到的所有记录
|
||||
deleted_count = 0
|
||||
for record_id in record_ids:
|
||||
deleted_count += db.delete_record(record_id)
|
||||
|
||||
# 添加删除记录的信息到响应中
|
||||
response["deleted_records"] = deleted_count
|
||||
# logging.info(f">>> 删除文件 {fid} 同时删除了 {deleted_count} 条相关记录")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f">>> 删除记录时出错: {str(e)}")
|
||||
# 不影响主流程,即使删除记录失败也返回文件删除成功
|
||||
else:
|
||||
response = {"success": False, "message": "缺失必要字段: fid"}
|
||||
return jsonify(response)
|
||||
|
||||
@ -31,9 +31,17 @@ class RecordDB:
|
||||
resolution TEXT,
|
||||
modify_date INTEGER NOT NULL,
|
||||
file_id TEXT,
|
||||
file_type TEXT
|
||||
file_type TEXT,
|
||||
save_path TEXT
|
||||
)
|
||||
''')
|
||||
|
||||
# 检查save_path字段是否存在,如果不存在则添加
|
||||
cursor.execute("PRAGMA table_info(transfer_records)")
|
||||
columns = [column[1] for column in cursor.fetchall()]
|
||||
if 'save_path' not in columns:
|
||||
cursor.execute('ALTER TABLE transfer_records ADD COLUMN save_path TEXT')
|
||||
|
||||
self.conn.commit()
|
||||
|
||||
def close(self):
|
||||
@ -41,19 +49,19 @@ class RecordDB:
|
||||
self.conn.close()
|
||||
|
||||
def add_record(self, task_name, original_name, renamed_to, file_size, modify_date,
|
||||
duration="", resolution="", file_id="", file_type=""):
|
||||
duration="", resolution="", file_id="", file_type="", save_path=""):
|
||||
"""添加一条转存记录"""
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute(
|
||||
"INSERT INTO transfer_records (transfer_time, task_name, original_name, renamed_to, file_size, "
|
||||
"duration, resolution, modify_date, file_id, file_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
"duration, resolution, modify_date, file_id, file_type, save_path) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(int(time.time()), task_name, original_name, renamed_to, file_size,
|
||||
duration, resolution, modify_date, file_id, file_type)
|
||||
duration, resolution, modify_date, file_id, file_type, save_path)
|
||||
)
|
||||
self.conn.commit()
|
||||
return cursor.lastrowid
|
||||
|
||||
def update_renamed_to(self, file_id, original_name, renamed_to, task_name=""):
|
||||
def update_renamed_to(self, file_id, original_name, renamed_to, task_name="", save_path=""):
|
||||
"""更新最近一条记录的renamed_to字段
|
||||
|
||||
Args:
|
||||
@ -61,6 +69,7 @@ class RecordDB:
|
||||
original_name: 原文件名
|
||||
renamed_to: 重命名后的文件名
|
||||
task_name: 任务名称,可选项,如提供则作为附加筛选条件
|
||||
save_path: 保存路径,可选项,如提供则同时更新保存路径
|
||||
|
||||
Returns:
|
||||
更新的记录数量
|
||||
@ -97,11 +106,17 @@ class RecordDB:
|
||||
|
||||
if result:
|
||||
record_id = result[0]
|
||||
# 更新记录
|
||||
cursor.execute(
|
||||
"UPDATE transfer_records SET renamed_to = ? WHERE id = ?",
|
||||
(renamed_to, record_id)
|
||||
)
|
||||
# 根据是否提供save_path决定更新哪些字段
|
||||
if save_path:
|
||||
cursor.execute(
|
||||
"UPDATE transfer_records SET renamed_to = ?, save_path = ? WHERE id = ?",
|
||||
(renamed_to, save_path, record_id)
|
||||
)
|
||||
else:
|
||||
cursor.execute(
|
||||
"UPDATE transfer_records SET renamed_to = ? WHERE id = ?",
|
||||
(renamed_to, record_id)
|
||||
)
|
||||
self.conn.commit()
|
||||
return cursor.rowcount
|
||||
|
||||
@ -124,7 +139,7 @@ class RecordDB:
|
||||
|
||||
# 构建SQL查询
|
||||
valid_columns = ["transfer_time", "task_name", "original_name", "renamed_to",
|
||||
"file_size", "duration", "resolution", "modify_date"]
|
||||
"file_size", "duration", "resolution", "modify_date", "save_path"]
|
||||
|
||||
if sort_by not in valid_columns:
|
||||
sort_by = "transfer_time"
|
||||
@ -140,7 +155,8 @@ class RecordDB:
|
||||
params.append(task_name_filter)
|
||||
|
||||
if keyword_filter:
|
||||
where_clauses.append("task_name LIKE ?")
|
||||
where_clauses.append("(task_name LIKE ? OR original_name LIKE ?)")
|
||||
params.append(f"%{keyword_filter}%")
|
||||
params.append(f"%{keyword_filter}%")
|
||||
|
||||
where_clause = " AND ".join(where_clauses)
|
||||
@ -192,4 +208,33 @@ class RecordDB:
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("DELETE FROM transfer_records WHERE id = ?", (record_id,))
|
||||
self.conn.commit()
|
||||
return cursor.rowcount
|
||||
return cursor.rowcount
|
||||
|
||||
def get_records_by_save_path(self, save_path, include_subpaths=False):
|
||||
"""根据保存路径查询记录
|
||||
|
||||
Args:
|
||||
save_path: 要查询的保存路径
|
||||
include_subpaths: 是否包含子路径下的文件
|
||||
|
||||
Returns:
|
||||
匹配的记录列表
|
||||
"""
|
||||
cursor = self.conn.cursor()
|
||||
|
||||
if include_subpaths:
|
||||
# 如果包含子路径,使用LIKE查询
|
||||
query = "SELECT * FROM transfer_records WHERE save_path LIKE ? ORDER BY transfer_time DESC"
|
||||
cursor.execute(query, [f"{save_path}%"])
|
||||
else:
|
||||
# 精确匹配路径
|
||||
query = "SELECT * FROM transfer_records WHERE save_path = ? ORDER BY transfer_time DESC"
|
||||
cursor.execute(query, [save_path])
|
||||
|
||||
records = cursor.fetchall()
|
||||
|
||||
# 将结果转换为字典列表
|
||||
if records:
|
||||
columns = [col[0] for col in cursor.description]
|
||||
return [dict(zip(columns, row)) for row in records]
|
||||
return []
|
||||
@ -1633,10 +1633,11 @@ button.close:focus,
|
||||
|
||||
/* 操作列 - 固定宽度 */
|
||||
#fileSelectModal .table .col-action {
|
||||
width: 53px;
|
||||
min-width: 53px;
|
||||
max-width: 53px;
|
||||
text-align: center;
|
||||
width: 188px;
|
||||
min-width: 188px;
|
||||
max-width: 188px;
|
||||
text-align: left;
|
||||
padding-left: 12px !important;
|
||||
}
|
||||
|
||||
/* 确保单元格内容溢出时正确显示 */
|
||||
@ -3576,11 +3577,11 @@ input::-moz-list-button {
|
||||
|
||||
/* 针对选择保存到的文件夹模式 - 带操作列的表格 */
|
||||
#fileSelectModal[data-modal-type="target"] .breadcrumb {
|
||||
min-width: 513px; /* 4列表格总宽度: 230px + 90px + 140px + 53px */
|
||||
min-width: 648px; /* 4列表格总宽度: 230px + 90px + 140px + 188px */
|
||||
}
|
||||
|
||||
#fileSelectModal[data-modal-type="target"] .table {
|
||||
width: 513px;
|
||||
width: 648px;
|
||||
}
|
||||
|
||||
/* 针对命名预览模式 - 2列表格 */
|
||||
|
||||
@ -953,7 +953,8 @@
|
||||
<td class="col-size" v-else style="vertical-align: top;">{{file.size | size}}</td>
|
||||
<td class="col-date" style="vertical-align: top;">{{file.updated_at | ts2date}}</td>
|
||||
<td class="col-action" v-if="!fileSelect.selectShare" style="vertical-align: top;">
|
||||
<a @click.stop.prevent="deleteSelectedFiles(file.fid, file.file_name, file.dir)" style="cursor: pointer;">删除</a>
|
||||
<a @click.stop.prevent="deleteSelectedFiles(file.fid, file.file_name, file.dir)" style="cursor: pointer;">删除文件</a>
|
||||
<a @click.stop.prevent="deleteSelectedFiles(file.fid, file.file_name, file.dir, true)" style="cursor: pointer; margin-left: 10px;">删除文件和记录</a>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
@ -2290,12 +2291,23 @@
|
||||
this.$delete(this.formData.magic_regex, key);
|
||||
}
|
||||
},
|
||||
deleteFile(fid, fname, isDir) {
|
||||
if (!confirm(`确定要删除此项目吗?`)) {
|
||||
deleteFile(fid, fname, isDir, deleteRecords = false) {
|
||||
// 根据是否删除记录显示不同的确认提示
|
||||
let confirmMessage = deleteRecords
|
||||
? `确定要删除此项目及其关联记录吗?`
|
||||
: `确定要删除此项目吗?`;
|
||||
|
||||
if (!confirm(confirmMessage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
axios.post('/delete_file', { fid: fid })
|
||||
// 获取当前路径作为save_path参数
|
||||
let save_path = "";
|
||||
if (this.fileSelect && this.fileSelect.paths) {
|
||||
save_path = this.fileSelect.paths.map(item => item.name).join("/");
|
||||
}
|
||||
|
||||
axios.post('/delete_file', { fid: fid, file_name: fname, delete_records: deleteRecords, save_path: save_path })
|
||||
.then(response => {
|
||||
if (response.data.code === 0) {
|
||||
// 从列表中移除文件
|
||||
@ -2311,7 +2323,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
this.showToast('成功删除 1 个项目');
|
||||
// 显示成功消息,根据是否删除记录显示不同的消息
|
||||
if (deleteRecords) {
|
||||
const deletedRecords = response.data.deleted_records || 0;
|
||||
this.showToast(`成功删除 1 个项目${deletedRecords > 0 ? `及其关联的 ${deletedRecords} 条记录` : ''}`);
|
||||
} else {
|
||||
this.showToast('成功删除 1 个项目');
|
||||
}
|
||||
|
||||
// 如果同时删除了记录,无论当前在哪个页面,都刷新历史记录
|
||||
if (deleteRecords) {
|
||||
this.loadHistoryRecords();
|
||||
}
|
||||
} else {
|
||||
alert('删除失败: ' + response.data.message);
|
||||
}
|
||||
@ -3403,36 +3426,53 @@
|
||||
// 阻止事件冒泡
|
||||
event.stopPropagation();
|
||||
},
|
||||
deleteSelectedFiles(clickedFid, clickedFname, isDir) {
|
||||
deleteSelectedFiles(clickedFid, clickedFname, isDir, deleteRecords = false) {
|
||||
// 如果是文件夹或者没有选中的文件,则按原来的方式删除单个文件
|
||||
if (isDir || this.fileSelect.selectedFiles.length === 0) {
|
||||
this.deleteFile(clickedFid, clickedFname, isDir);
|
||||
this.deleteFile(clickedFid, clickedFname, isDir, deleteRecords);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果点击的文件不在选中列表中,也按原来的方式删除单个文件
|
||||
if (!this.fileSelect.selectedFiles.includes(clickedFid)) {
|
||||
this.deleteFile(clickedFid, clickedFname, isDir);
|
||||
this.deleteFile(clickedFid, clickedFname, isDir, deleteRecords);
|
||||
return;
|
||||
}
|
||||
|
||||
// 多选删除
|
||||
const selectedCount = this.fileSelect.selectedFiles.length;
|
||||
|
||||
// 根据选中数量使用不同的确认提示
|
||||
let confirmMessage = selectedCount === 1
|
||||
? `确定要删除此项目吗?`
|
||||
: `确定要删除选中的 ${selectedCount} 个项目吗?`;
|
||||
// 根据选中数量和是否删除记录使用不同的确认提示
|
||||
let confirmMessage = '';
|
||||
if (deleteRecords) {
|
||||
confirmMessage = selectedCount === 1
|
||||
? `确定要删除此项目及其关联记录吗?`
|
||||
: `确定要删除选中的 ${selectedCount} 个项目及其关联记录吗?`;
|
||||
} else {
|
||||
confirmMessage = selectedCount === 1
|
||||
? `确定要删除此项目吗?`
|
||||
: `确定要删除选中的 ${selectedCount} 个项目吗?`;
|
||||
}
|
||||
|
||||
if (confirm(confirmMessage)) {
|
||||
// 获取当前路径作为save_path参数
|
||||
let save_path = "";
|
||||
if (this.fileSelect && this.fileSelect.paths) {
|
||||
save_path = this.fileSelect.paths.map(item => item.name).join("/");
|
||||
}
|
||||
|
||||
// 创建一个Promise数组来处理所有删除请求
|
||||
const deletePromises = this.fileSelect.selectedFiles.map(fid => {
|
||||
return axios.post('/delete_file', { fid: fid })
|
||||
// 查找对应的文件对象,获取文件名
|
||||
const fileObj = this.fileSelect.fileList.find(file => file.fid === fid);
|
||||
const fileName = fileObj ? fileObj.file_name : '';
|
||||
|
||||
return axios.post('/delete_file', { fid: fid, file_name: fileName, delete_records: deleteRecords, save_path: save_path })
|
||||
.then(response => {
|
||||
return { fid: fid, success: response.data.code === 0 };
|
||||
return { fid: fid, success: response.data.code === 0, deleted_records: response.data.deleted_records || 0 };
|
||||
})
|
||||
.catch(error => {
|
||||
return { fid: fid, success: false };
|
||||
return { fid: fid, success: false, deleted_records: 0 };
|
||||
});
|
||||
});
|
||||
|
||||
@ -3442,6 +3482,8 @@
|
||||
// 统计成功和失败的数量
|
||||
const successCount = results.filter(r => r.success).length;
|
||||
const failCount = results.length - successCount;
|
||||
// 统计删除的记录数
|
||||
const totalDeletedRecords = results.reduce((sum, r) => sum + (r.deleted_records || 0), 0);
|
||||
|
||||
// 从文件列表中移除成功删除的文件
|
||||
const successfullyDeletedFids = results.filter(r => r.success).map(r => r.fid);
|
||||
@ -3455,7 +3497,17 @@
|
||||
if (failCount > 0) {
|
||||
alert(`成功删除 ${successCount} 个项目,${failCount} 个项目删除失败`);
|
||||
} else {
|
||||
this.showToast(`成功删除 ${successCount} 个项目`);
|
||||
// 根据是否删除记录显示不同的消息
|
||||
if (deleteRecords) {
|
||||
this.showToast(`成功删除 ${successCount} 个项目${totalDeletedRecords > 0 ? `及其关联的 ${totalDeletedRecords} 条记录` : ''}`);
|
||||
} else {
|
||||
this.showToast(`成功删除 ${successCount} 个项目`);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果同时删除了记录,无论当前在哪个页面都刷新历史记录
|
||||
if (deleteRecords) {
|
||||
this.loadHistoryRecords();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1146,6 +1146,19 @@ class Quark:
|
||||
# 目前只是添加占位符,未来可以扩展功能
|
||||
pass
|
||||
|
||||
# 获取保存路径
|
||||
save_path = task.get("savepath", "")
|
||||
# 如果file_info中有子目录路径信息,则拼接完整路径
|
||||
subdir_path = file_info.get("subdir_path", "")
|
||||
if subdir_path:
|
||||
# 确保路径格式正确,避免双斜杠
|
||||
if save_path.endswith('/') and subdir_path.startswith('/'):
|
||||
save_path = save_path + subdir_path[1:]
|
||||
elif not save_path.endswith('/') and not subdir_path.startswith('/'):
|
||||
save_path = save_path + '/' + subdir_path
|
||||
else:
|
||||
save_path = save_path + subdir_path
|
||||
|
||||
# 添加记录到数据库
|
||||
db.add_record(
|
||||
task_name=task.get("taskname", ""),
|
||||
@ -1156,7 +1169,8 @@ class Quark:
|
||||
duration=duration,
|
||||
resolution=resolution,
|
||||
file_id=file_id,
|
||||
file_type=file_type
|
||||
file_type=file_type,
|
||||
save_path=save_path
|
||||
)
|
||||
|
||||
# 关闭数据库连接
|
||||
@ -1195,12 +1209,26 @@ class Quark:
|
||||
file_id = file_info.get("fid", "")
|
||||
task_name = task.get("taskname", "")
|
||||
|
||||
# 获取保存路径
|
||||
save_path = task.get("savepath", "")
|
||||
# 如果file_info中有子目录路径信息,则拼接完整路径
|
||||
subdir_path = file_info.get("subdir_path", "")
|
||||
if subdir_path:
|
||||
# 确保路径格式正确,避免双斜杠
|
||||
if save_path.endswith('/') and subdir_path.startswith('/'):
|
||||
save_path = save_path + subdir_path[1:]
|
||||
elif not save_path.endswith('/') and not subdir_path.startswith('/'):
|
||||
save_path = save_path + '/' + subdir_path
|
||||
else:
|
||||
save_path = save_path + subdir_path
|
||||
|
||||
# 更新记录
|
||||
updated = db.update_renamed_to(
|
||||
file_id=file_id,
|
||||
original_name=original_name,
|
||||
renamed_to=renamed_to,
|
||||
task_name=task_name
|
||||
task_name=task_name,
|
||||
save_path=save_path
|
||||
)
|
||||
|
||||
# 关闭数据库连接
|
||||
@ -1255,12 +1283,17 @@ class Quark:
|
||||
# 使用原文件名和任务名查找记录
|
||||
task_name = task.get("taskname", "")
|
||||
|
||||
# 获取保存路径
|
||||
save_path = task.get("savepath", "")
|
||||
# 注意:从日志中无法获取子目录信息,只能使用任务的主保存路径
|
||||
|
||||
# 更新记录
|
||||
updated = db.update_renamed_to(
|
||||
file_id="", # 不使用file_id查询,因为在日志中无法获取
|
||||
original_name=old_name,
|
||||
renamed_to=new_name,
|
||||
task_name=task_name
|
||||
task_name=task_name,
|
||||
save_path=save_path
|
||||
)
|
||||
|
||||
# 关闭数据库连接
|
||||
|
||||
Loading…
Reference in New Issue
Block a user